Histogram Plotter

GWM Oct 2004 A simple canvas object to display a bar histogram from given data.


 global ready
 set ready 0
 proc histogram {slist wid ht} { ;# render a histogram
        global ready
        array set scores $slist
        set nms [lsort -integer [array names scores]]
        catch {destroy .h} {}
        catch {destroy .b} {}
        canvas .h -width $wid -height $ht -bg beige
          pack .h
        set nbars [array size scores] ;#how many histogram bars
        set nax [expr $nbars/10] ;# axis spacing
        set hwid [expr $wid/ $nbars]
        set i 0
        set hmax -9999999 ;# largest y value 
        set hmin  9999999 ;# smallest y value
        while {$i<$nbars} {
                set f $scores([lindex $nms $i])
                set hmax [ expr {$f>$hmax} ? $f : $hmax]
                set hmin [ expr {$f<$hmin} ? $f : $hmin]
                incr i
        }

        if {$hmax>$hmin} {
        set i 0
        set nay 100
        while {$nay<$hmax} {
                set yp [expr $ht-0.75*$nay-20]
                .h create line  0 $yp $wid $yp -fill red
                incr nay 100
        }
        set nax 10
        while {$i<$nbars} {
                set x [expr $hwid*$i]
                set rhs [expr $x+$hwid/2]
                set f [expr $ht-20-.75*$ht*$scores([lindex $nms $i])/$hmax]
                .h create rectangle  $x [expr $ht-20] $rhs $f -fill gray
                if {[expr $i>=$nax]} {
                .h create line  $x [expr $ht-20] $x 0 -fill red
                        incr nax 10
                }
                incr i
                incr x $hwid
        }
        update

 #        button .b  -text "Next" -command "incr ready" ;# when ready is changed, proceeds with commands
 #        pack .b
        }
 }

Call using

 histogram {1 2 2 3 3 5 4 7 5 6} 500 400

The list is actually an array :: category 1 occurred twice; category 2 three times, category 3 5 times, category 4 7 times & 5 occurred 6 times. The category names must be integers. For a way of looking at the rand function:

 for {set i 0} {$i<50} {incr i} {lappend scores $i [expr rand()]}
 histogram $scores 500 200

will show a histogram of the value returned by rand for 50 trials (nb not the frequency).

For rand frequency of the first digit returned by rand() use:

 for {set i 0} {$i<10} {incr i} {set rnd($i) 0}
 for {set i 0} {$i<50} {incr i} { incr rnd([expr int(9.9999*rand())])}
 histogram [array get rnd] 300 200

Repeatedly paste this code into wish console to see the variation in frequency of each integer value.

Other graphics routines

See also