Richard Suchenwirth 2007-05-12 - Here's another little weekend project, an educational toy to experiment with linear regression.
On the
canvas, you can put data points with left mouse button. (Cursor position is displayed in the title bar). The "C" button clears all. The "Reg" button computes the linear regression for the points, and display it as a green line. That's all, but it may be fun for some...
package require Tk
proc main argv {
pack [frame .f] -fill x
button .f.c -text " C " -command {.c delete all}
button .f.r -text Reg -command {drawReg .c}
eval pack [winfo children .f] -side left
pack [canvas .c -bg white] -fill both -expand 1
bind .c <Motion> {wm title . [%W canvasx %x]|[%W canvasy %y]}
bind .c <1> {drawPoint %W %x %y}
bind .c <2> {%W delete current}
}
proc drawPoint {w x y} {
set x [$w canvasx $x]
set y [$w canvasy $y]
$w create rect $x $y [expr $x+2] [expr $y+2] -fill red -tag point
}
proc drawReg w {
set xys {}
foreach point [$w find withtag point] {
lappend xys [center [$w bbox $point]]
}
foreach {a b} [linear'regression $xys] break
set x1 [winfo width $w]
set y1 [expr {$a + $b*$x1}]
$w delete line
$w create line 0 $a $x1 $y1 -fill green -tag line
}
proc center bbox {
foreach {x0 y0 x1 y1} $bbox break
list [expr {($x0+$x1)/2.}] [expr {($y0+$y1)/2.}]
}
proc linear'regression xys {
set xsum 0.0; set ysum 0.0
foreach xy $xys {
foreach {x y} $xy break
set xsum [expr {$xsum + $x}]
set ysum [expr {$ysum + $y}]
}
set xm [expr {$xsum/[llength $xys]}]
set ym [expr {$ysum/[llength $xys]}]
set xsum 0.0; set ysum 0.0
foreach xy $xys {
foreach {x y} $xy break
set dx [expr {$x - $xm}]
set dy [expr {$y - $ym}]
set xsum [expr {$xsum + $dx * $dy}]
set ysum [expr {$ysum + $dx * $dx}]
}
set b [expr {$xsum / $ysum}]
set a [expr {$ym - $b * $xm}]
list $a $b
}
main $argv
#-- Useful little helper: quick restart
bind . <Escape> {exec wish $argv0 &; exit}