1# plotstat.tcl -- 2# 3# Set of very simple drawing routines, belonging to the statistics 4# package 5# 6# version 0.1: initial implementation, january 2003 7 8namespace eval ::math::statistics {} 9 10# plot-scale 11# Set the scale for a plot in the given canvas 12# 13# Arguments: 14# canvas Canvas widget to use 15# xmin Minimum x value 16# xmax Maximum x value 17# ymin Minimum y value 18# ymax Maximum y value 19# 20# Result: 21# None 22# 23# Side effect: 24# Array elements set 25# 26proc ::math::statistics::plot-scale { canvas xmin xmax ymin ymax } { 27 variable plot 28 29 if { $xmin == $xmax } { set xmax [expr {1.1*$xmin+1.0}] } 30 if { $ymin == $ymax } { set ymax [expr {1.1*$ymin+1.0}] } 31 32 set plot($canvas,xmin) $xmin 33 set plot($canvas,xmax) $xmax 34 set plot($canvas,ymin) $ymin 35 set plot($canvas,ymax) $ymax 36 37 set cwidth [$canvas cget -width] 38 set cheight [$canvas cget -height] 39 set cx 20 40 set cy 20 41 set cx2 [expr {$cwidth-$cx}] 42 set cy2 [expr {$cheight-$cy}] 43 44 set plot($canvas,cx) $cx 45 set plot($canvas,cy) $cy 46 47 set plot($canvas,dx) [expr {($cwidth-2*$cx)/double($xmax-$xmin)}] 48 set plot($canvas,dy) [expr {($cheight-2*$cy)/double($ymax-$ymin)}] 49 set plot($canvas,cx2) $cx2 50 set plot($canvas,cy2) $cy2 51 52 $canvas create line $cx $cy $cx $cy2 $cx2 $cy2 -tag axes 53} 54 55# plot-xydata 56# Create a simple XY plot in the given canvas (collection of dots) 57# 58# Arguments: 59# canvas Canvas widget to use 60# xdata Series of independent data 61# ydata Series of dependent data 62# tag Tag to give to the plotted data (defaults to xyplot) 63# 64# Result: 65# None 66# 67# Side effect: 68# Simple xy graph in the canvas 69# 70# Note: 71# The tag can be used to manipulate the xy graph 72# 73proc ::math::statistics::plot-xydata { canvas xdata ydata {tag xyplot} } { 74 PlotXY $canvas points $tag $xdata $ydata 75} 76 77# plot-xyline 78# Create a simple XY plot in the given canvas (continuous line) 79# 80# Arguments: 81# canvas Canvas widget to use 82# xdata Series of independent data 83# ydata Series of dependent data 84# tag Tag to give to the plotted data (defaults to xyplot) 85# 86# Result: 87# None 88# 89# Side effect: 90# Simple xy graph in the canvas 91# 92# Note: 93# The tag can be used to manipulate the xy graph 94# 95proc ::math::statistics::plot-xyline { canvas xdata ydata {tag xyplot} } { 96 PlotXY $canvas line $tag $xdata $ydata 97} 98 99# plot-tdata 100# Create a simple XY plot in the given canvas (the index in the list 101# is the horizontal coordinate; points) 102# 103# Arguments: 104# canvas Canvas widget to use 105# tdata Series of dependent data 106# tag Tag to give to the plotted data (defaults to xyplot) 107# 108# Result: 109# None 110# 111# Side effect: 112# Simple xy graph in the canvas 113# 114# Note: 115# The tag can be used to manipulate the xy graph 116# 117proc ::math::statistics::plot-tdata { canvas tdata {tag xyplot} } { 118 PlotXY $canvas points $tag {} $tdata 119} 120 121# plot-tline 122# Create a simple XY plot in the given canvas (the index in the list 123# is the horizontal coordinate; line) 124# 125# Arguments: 126# canvas Canvas widget to use 127# tdata Series of dependent data 128# tag Tag to give to the plotted data (defaults to xyplot) 129# 130# Result: 131# None 132# 133# Side effect: 134# Simple xy graph in the canvas 135# 136# Note: 137# The tag can be used to manipulate the xy graph 138# 139proc ::math::statistics::plot-tline { canvas tdata {tag xyplot} } { 140 PlotXY $canvas line $tag {} $tdata 141} 142 143# PlotXY 144# Create a simple XY plot (points or lines) in the given canvas 145# 146# Arguments: 147# canvas Canvas widget to use 148# type Type: points or line 149# tag Tag to give to the plotted data 150# xdata Series of independent data (if empty: index used instead) 151# ydata Series of dependent data 152# 153# Result: 154# None 155# 156# Side effect: 157# Simple xy graph in the canvas 158# 159# Note: 160# This is the actual routine 161# 162proc ::math::statistics::PlotXY { canvas type tag xdata ydata } { 163 variable plot 164 165 if { ![info exists plot($canvas,xmin)] } { 166 return -code error -errorcode "No scaling given for canvas $canvas" 167 } 168 169 set xmin $plot($canvas,xmin) 170 set xmax $plot($canvas,xmax) 171 set ymin $plot($canvas,ymin) 172 set ymax $plot($canvas,ymax) 173 set dx $plot($canvas,dx) 174 set dy $plot($canvas,dy) 175 set cx $plot($canvas,cx) 176 set cy $plot($canvas,cy) 177 set cx2 $plot($canvas,cx2) 178 set cy2 $plot($canvas,cy2) 179 180 set plotpoints [expr {$type == "points"}] 181 set xpresent [expr {[llength $xdata] > 0}] 182 set idx 0 183 set coords {} 184 185 foreach y $ydata { 186 if { $xpresent } { 187 set x [lindex $xdata $idx] 188 } else { 189 set x $idx 190 } 191 incr idx 192 193 if { $x == {} } continue 194 if { $y == {} } continue 195 if { $x > $xmax } continue 196 if { $x < $xmin } continue 197 if { $y > $ymax } continue 198 if { $y < $ymin } continue 199 200 if { $plotpoints } { 201 set xc [expr {$cx+$dx*($x-$xmin)-2}] 202 set yc [expr {$cy2-$dy*($y-$ymin)-2}] 203 set xc2 [expr {$xc+4}] 204 set yc2 [expr {$yc+4}] 205 $canvas create oval $xc $yc $xc2 $yc2 -tag $tag -fill black 206 } else { 207 set xc [expr {$cx+$dx*($x-$xmin)}] 208 set yc [expr {$cy2-$dy*($y-$ymin)}] 209 lappend coords $xc $yc 210 } 211 } 212 213 if { ! $plotpoints } { 214 $canvas create line $coords -tag $tag 215 } 216} 217 218# plot-histogram 219# Create a simple histogram in the given canvas 220# 221# Arguments: 222# canvas Canvas widget to use 223# counts Series of bucket counts 224# limits Series of upper limits for the buckets 225# tag Tag to give to the plotted data (defaults to xyplot) 226# 227# Result: 228# None 229# 230# Side effect: 231# Simple histogram in the canvas 232# 233# Note: 234# The number of limits determines how many bars are drawn, 235# the number of counts that is expected is one larger. The 236# lower and upper limits of the first and last bucket are 237# taken to be equal to the scale's extremes 238# 239proc ::math::statistics::plot-histogram { canvas counts limits {tag xyplot} } { 240 variable plot 241 242 if { ![info exists plot($canvas,xmin)] } { 243 return -code error -errorcode DATA "No scaling given for canvas $canvas" 244 } 245 246 if { ([llength $counts]-[llength $limits]) != 1 } { 247 return -code error -errorcode ARG \ 248 "Number of counts does not correspond to number of limits" 249 } 250 251 set xmin $plot($canvas,xmin) 252 set xmax $plot($canvas,xmax) 253 set ymin $plot($canvas,ymin) 254 set ymax $plot($canvas,ymax) 255 set dx $plot($canvas,dx) 256 set dy $plot($canvas,dy) 257 set cx $plot($canvas,cx) 258 set cy $plot($canvas,cy) 259 set cx2 $plot($canvas,cx2) 260 set cy2 $plot($canvas,cy2) 261 262 # 263 # Construct a sufficiently long list of x-coordinates 264 # 265 set xdata [concat $xmin $limits $xmax] 266 267 set idx 0 268 foreach x $xdata y $counts { 269 incr idx 270 271 if { $y == {} } continue 272 273 set x1 $x 274 if { $x < $xmin } { set x1 $xmin } 275 if { $x > $xmax } { set x1 $xmax } 276 277 if { $y > $ymax } { set y $ymax } 278 if { $y < $ymin } { set y $ymin } 279 280 set x2 [lindex $xdata $idx] 281 if { $x2 < $xmin } { set x2 $xmin } 282 if { $x2 > $xmax } { set x2 $xmax } 283 284 set xc [expr {$cx+$dx*($x1-$xmin)}] 285 set xc2 [expr {$cx+$dx*($x2-$xmin)}] 286 set yc [expr {$cy2-$dy*($y-$ymin)}] 287 set yc2 $cy2 288 289 $canvas create rectangle $xc $yc $xc2 $yc2 -tag $tag -fill blue 290 } 291} 292 293# 294# Simple test code 295# 296if { [info exists ::argv0] && ([file tail [info script]] == [file tail $::argv0]) } { 297 298 set xdata {1 2 3 4 5 10 20 6 7 8 1 3 4 5 6 7} 299 set ydata {2 3 4 5 6 10 20 7 8 1 3 4 5 6 7 1} 300 301 canvas .c 302 canvas .c2 303 pack .c .c2 -side top -fill both 304 ::math::statistics::plot-scale .c 0 10 0 10 305 ::math::statistics::plot-scale .c2 0 20 0 10 306 307 ::math::statistics::plot-xydata .c $xdata $ydata 308 ::math::statistics::plot-xyline .c $xdata $ydata 309 ::math::statistics::plot-histogram .c2 {1 3 2 0.1 4 2} {-1 3 10 11 23} 310 ::math::statistics::plot-tdata .c2 $xdata 311 ::math::statistics::plot-tline .c2 $xdata 312} 313