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