| 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 | |
|---|
| 8 | namespace 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 | # |
|---|
| 26 | proc ::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 | # |
|---|
| 73 | proc ::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 | # |
|---|
| 95 | proc ::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 | # |
|---|
| 117 | proc ::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 | # |
|---|
| 139 | proc ::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 | # |
|---|
| 162 | proc ::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 | # |
|---|
| 239 | proc ::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 | # |
|---|
| 296 | if { [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 | } |
|---|