[Arjen Markus] 2010-02-01: In a discussion about my work on a LAPACK wrapper, Kevin Kenny mentioned [http://www.usenix.org/events/tcl98/tcl98/full_papers/howlett/howlett.pdf%|%Data Objects], by George Howlett, 1998, which are, roughly speaking, collections of data that have a set of operations connected to them. The concept differs from ''object-oriented objects'', because data objects do not have inheritance and so on. The program below illustrates how you can have operations on data performed automatically, whenever the data change. It simply connects two variables to a Plotchart plot and whenever the values of these variables change, the plot gets redrawn. Redrawing occurs when the event loop is run (so when the program is waiting for input from the user). The idea is not at all limited to plotting the data, you can also store the data in a database, run a statistical analysis or whatever. ====== # binddata.tcl -- # Simple example of using the concept of "data objects" as described # in the article by George Howlett. # # Idea: # Variables are updated and this automatically provokes an action, such updating # the plot that is associated with them # package require Plotchart # bindplotdata -- # Bind variables to a Plotchart plot # # Arguments: # plot The Plotchart plot they belong to # series The series name # xvar Global (!) variable for x values # yvar Global (!) variable for y values # # Returns: # None # # Side effects: # The procedure creates a trace for these two variables # proc bindplotdata {plot series xvar yvar} { trace add variable ::$xvar write [list UpdatePlot $plot $series $xvar $yvar] trace add variable ::$yvar write [list UpdatePlot $plot $series $xvar $yvar] } # UpdatePlot -- # Queue an after event for updating the plot if the data change # # Arguments: # plot The Plotchart plot the data belong to # series The series name # xvar Global (!) variable for x values # yvar Global (!) variable for y values # name1 Name of the changed variable (not used) # name2 Name of the element - if any (not used) # op Operation (not used) # # Returns: # None # # Side effects: # An event is queued - it will fire when the program's event loop is run # proc UpdatePlot {plot series xvar yvar name1 name2 op} { global eventID if { [info exists eventID] } { after cancel $eventID } set eventID [after 0 RedrawData $plot $series $xvar $yvar] } # RedrawData -- # Redraw the data # # Arguments: # plot The Plotchart plot the data belong to # series The series name # xvar Global (!) variable for x values # yvar Global (!) variable for y values # # Returns: # None # # Side effects: # All data in the plot is deleted first, so this works for one series only # proc RedrawData {plot series xvar yvar} { global notfirst upvar #0 $xvar xdata upvar #0 $yvar ydata set canvas [string range $plot 7 end] $canvas delete data if { [info exist notfirst] } { $plot plot $series {} {} } else { set notfirst 1 ;# Workaround for small glitch in Plotchart } foreach x $xdata y $ydata { $plot plot $series $x $y } } # main -- # Test the procedure # pack [canvas .c -bg white -width 400 -height 400] set p [::Plotchart::createXYPlot .c {-2 2 0.5} {-2 2 0.5}] bindplotdata $p circle x y set x {} set y {} set pi 3.1415926 for {set i 0} {$i <= 100} {incr i} { lappend x [expr {cos($pi*$i/50.0)}] lappend y [expr {sin($pi*$i/50.0)}] } ====== <> Category Example | Category Plotting