Version 0 of A little function plotter

Updated 2001-06-05 02:22:43

See Fun with functions for a quite improved version (still little ;-)


Richard Suchenwirth -- Of course there is BLT, but Tcl is just such a great wheel reinvention tool ;-) Somebody asked on comp.lang.tcl whether there's software for plotting functions, and I just needed a little challenge. So here it is: fun2points tabulates x/y values for a given function, plotpoints draws, scales, and moves such a tabulated function (or whatever other x/y coordinates - stock quotes over time?) on a given canvas, and some wrapping lines as usage example. Sheer fun...

 #!/bin/sh
 # next lines restarts \
 exec wish "$0" ${1+"$@"}

 proc fun2points {fun args} {
        array set opt {
                -from -4.0 -to 4.0 -step .1
        }
        array set opt $args
        set res [list]
        for {set x $opt(-from)} {$x <= $opt(-to)} {set x [expr {$x+$opt(-step)}]} {
           if {![catch {expr $fun} y]} {lappend res $x $y}
        }
        set res
 }
 proc plotpoints {w points args} {
    eval $w create line $points $args
    set maxx [set minx [lindex $points 0]]
    set maxy [set miny [lindex $points 1]]
    foreach {x y} $points {
        if {$x<$minx} {set minx $x}
        if {$x>$maxx} {set maxx $x}
        if {$y<$miny} {set miny $y}
        if {$y>$maxy} {set maxy $y}
    }
    $w create line $minx 0 $maxx 0
    $w create line 0 $miny 0 $maxy
    set xfac [expr 0.95*[$w cget -width]/($maxx-$minx)]
    set yfac [expr 0.95*[$w cget -height]/($maxy-$miny)]
    $w scale all 0 0 $xfac -$yfac
    foreach {minxc minyc} [$w bbox all] break
    $w move all [expr -$minxc+5] [expr -$minyc+5]
 }

 set fun [lindex $argv 0]
 pack [canvas .c]
 plotpoints .c [fun2points $fun] -fill red
 wm title . $fun

 # usage example: funplot.tcl 'sin($x)'

Here are actually some problems. This script probably runs on UNIX, but not on Windows 2000. I had to change it to the following form to be able to run it from the wish.

 #!/bin/sh
 # next lines restarts \
 # the following line doesn't do anything under windows, does it?
 # exec wish "$0" ${1+"$@"}

 proc fun2points {fun args} {
        array set opt {
                -from -4.0 -to 4.0 -step .1
        }
        array set opt $args
        set res [list]
        for {set x $opt(-from)} {$x <= $opt(-to)} {set x [expr {$x+$opt(-step)}]} {
                # i had to exchange the following line:
                # if {![catch {expr $fun} y]} {lappend res $x $y}
                set func $fun
                append func ($x)
                lappend res $x [expr $func]
        }
        set res
 }

 proc plotpoints {w points args} {
        eval $w create line $points $args
        set maxx [set minx [lindex $points 0]]
        set maxy [set miny [lindex $points 1]]
        foreach {x y} $points {
                if {$x<$minx} {set minx $x}
                if {$x>$maxx} {set maxx $x}
                if {$y<$miny} {set miny $y}
                if {$y>$maxy} {set maxy $y}
        }
        $w create line $minx 0 $maxx 0
        $w create line 0 $miny 0 $maxy
        set xfac [expr 0.95*[$w cget -width]/($maxx-$minx)]
        set yfac [expr 0.95*[$w cget -height]/($maxy-$miny)]
        $w scale all 0 0 $xfac -$yfac
        foreach {minxc minyc} [$w bbox all] break
        $w move all [expr -$minxc+5] [expr -$minyc+5]
 }

 proc funplot {argv} {
        set fun [lindex $argv 0]
        if {[winfo exists .c]} {destroy .c}
        pack [canvas .c]
        plotpoints .c [fun2points $fun] -fill red
        wm title . $fun
 }

 # i also had to exchange the usage
 # usage example: funplot sin

There is something very weird also: x should run up to 4.0 in this example, but it runs only to 3.9 :-(

Does anyone understand this, please? Yes - comparing doubles is a real problem. Since I just wanted to cover the range from -Pi to +Pi, I didn't look that hard, but you're right, and can isolate the problem to

 expr {3.9+.01>1.0}

which returns 1. so a cleaner test condition would have been

 for ... {($x-$opt(-to))<0.00001} ...

or another delta that bridges the gap between real and evident - RS


BLT is at http://www.tcltk.com/blt/ . See also emu-graph, padgraph at http://www.shlrc.mq.edu.au/~steve/tcl