Version 0 of How to plot a graph

Updated 2001-01-03 10:42:50

David H. Bigelow wrote in the comp.lang.tcl newsgroup:

The thing to remember with the Tcl Canvas widget is that it starts it's 0 0 at the upper left corner of your display and works down. Knowing that you are looking to do a graph. I have compensated for this so that the graph information is translated to the lower left corner and builds to the right.

Here is the point data I used in a file called: data.txt

 0,0
 10,10
 15,7.5
 20,25
 25,60
 30,30
 35,40
 40,45
 50,60

I have included a couple of variations for computing this. Both are computing the graph such that the origin is the lower left corner of the canvas -- so it looks like a graph:

 #**** PROGRAM 1 -- SIMPLE -- individual lines
 # DECLARE THE SIZE OF THE CANVAS
 set width 100
 set height 100
 canvas .c -width $width -height $height -background yellow
 pack .c

 # READ THE DATA FILE
 set infile [open data.txt]
 set indata [read $infile]
 close $infile

 set count 0
 foreach point $indata {
    if {$count == 0} {
       set oldx [lindex [split $point ,] 0]
       set oldy [expr $height-[lindex [split $point ,] 1]]
       incr count
    }
    if {$count > 0} {
       set newx [lindex [split $point ,] 0]
       set newy [expr $height-[lindex [split $point ,] 1]]
       .c create line $oldx $oldy $newx $newy
       set oldx $newx
       set oldy $newy
    }
 }

PROGRAM 1 is a very simple program to follow, and it gets the job done, although not as efficient as other methods (see below). However, if you are a beginner - this will plot data and quickly. Believe me -- there are more efficient methods.


 #**** PROGRAM 2-- MEDIUM/COMPLEX -- Single line for same data
 # DECLARE THE SIZE OF THE CANVAS
 set width 100
 set height 100
 canvas .c -width $width -height $height -background yellow
 pack .c

 # READ THE DATA FILE
 set infile [open data.txt]
 set indata [read $infile]
 close $infile

 set linecoords {}
 foreach point $indata {
    set x [lindex [split $point ,] 0]
    set y [expr $height-[lindex [split $point ,] 1]]
    lappend linecoords $x $y
 }
 set test ".c create line [join $linecoords]"
 eval $test

PROGRAM 2 is more complicated because it uses more advanved functions of Tcl than the first program. The advantage is that your data set is described in one element. Which may be very helpful if you have multiple data sets to deal with.


RS: Here are some things I'd do differently, just for discussion:

  • linecoords is a list, so it's slightly more efficient to initialize it as such
  • splitting the $point is done twice, once is enough
  • accessing with lindex is OK, but for constant positions, I prefer foreach...break
  • join is not needed, a list referenced in a string will come joined with spaces
 set linecoords [list]
 foreach point $indata {
    foreach {x y} [split $point ,] break
    lappend linecoords $x [expr {$height-$y}]
 }
 eval .c create line $linecoords

Arts and crafts of Tcl-Tk programming - See also A little function plotter