ulis, 2003-03-12:
A little script to plot a graph on a canvas. Non-stop scrolling capable. Can be used for real-time plotting.
#! /bin/env tclsh package require Tk proc sleep {time} { after $time set end 1 vwait end } # -------------------------- # params # -------------------------- # title # canvas width & height # delay between plots # x = f(t) # plot expression # initial & final times # accuracy array set params { title {sin(x)} width 400 height 240 delay 50 x {$t / 50.} plot {sin($x)} t0 0 # {t1 < t0: non-stop scrolling} t1 -1 accuracy 1.e-2 } # -------------------------- # plotting # -------------------------- # computed heights set h $params(height) set h1 [expr {int($h * 0.5)}] ;# canvas mid-height set h2 [expr {$h1 + 1}] set h3 [expr {int($h * 0.4)}] ;# graph mid-height # canvas & bindings canvas .c -width $params(width) -height $h -xscrollincrement 1 -bg beige bind . <Destroy> { exit } # plotting wm title . $params(title) pack .c .c xview scroll $params(t0) unit set t $params(t0) while TRUE { if {$t != $params(t1)} { set x [expr $params(x)] set vv [expr $params(plot)] set v [expr {int($vv * $h3) + $h1}] if {abs($vv) < $params(accuracy)} \ { #puts "$vv [expr {$params(accuracy)}]" ;#because I wanted to understand the points .c create text $t 0 -anchor n -text [expr { $t / 50. }] -fill gray .c create line $t 0 $t $h -fill gray } .c create line $t $h1 $t $h2 -fill gray .c create rectangle $t $v $t $v incr t if {$t > $params(width)} { .c xview scroll 1 unit } } sleep $params(delay) }
array set params \ { title {x^3 - x} width 400 height 240 delay 50 x {$t / 100.0} plot {pow($x,3) - $x} t0 -200 t1 200 accuracy 1.e-6 }
marcDouglas, 2018-11-2:
Loved this, wanted to having something scrolling. Found it a bit confusing, think I cleaned it up. The problem was the UI freezes if you use
after 50
to get the pause in the loop. The sleep command accomplishes this and cleans the code up. However you did teach me how you could use the after command (have it execute a script after delay and is non-blocking), I just don't think this is the place for it.
Also edited the text to accurately reflect value of (x).
arjen (2018-11-3) (Moved the addition to the end of the page) The proper way to achieve this is by:
after 50 { ... some script ... set ::waiting 1 ;# Should be a global/namespace variable } vwait waiting
See the page on the every script for more information and a convenient way of using the technique.