Tcl(/Tk) でグラフ [Tcl]
Lightweight Language のサイトの「キミならどう書く 2.0 - ROUND 3 -」というトラックバック企画 [1] で今回のお題が「いくつかのデータを与えたときにグラフを出力するプログラム」(細かい仕様無し)ということだった。
今までこの企画で Tcl や Tcl/Tk で参加している人は意外にもいないっぽいので書いてみることにしました(それにこのお題はいかにも Tcl/Tk 向き)。
まずちょっと仕様を制限したもの。キャンバスの幅をはみ出すようなデータは考慮しない。
# graph.tcl
pack [canvas .canvas -width 200 -height [expr 20*[llength $argv]] -bg white]
set ypos 10
foreach num $argv {
.canvas create line 0 $ypos [expr $num*10] $ypos -width 18 -fill blue
.canvas create text 2 $ypos -text $num -anchor w -fill white
incr ypos 20
}
実行するには
wish graph.tcl 2 5 9 18 15
などとする。実行結果はこうなる。
次はちゃんとキャンバスの大きさに合わせて伸縮するようにしたもの。
# graph2.tcl
set height 150; set width 200; # キャンバスの大きさ
set max [lindex [lsort -integer $argv] end]; # 要素の最大値
set lwidth [expr $height/[llength $argv]]; # 線の取れる太さ
pack [canvas .canvas -width $width -height $height -bg white]
set ypos [expr $lwidth/2]
foreach num $argv {
set xpos [expr $width*$num/$max]
.canvas create line 0 $ypos $xpos $ypos -width [expr $lwidth-2] -fill blue
.canvas create text $xpos $ypos -text $num -anchor e -fill white
incr ypos $lwidth
}
実行結果は以下のとおり。
wish graph2.tcl 2 5 9 30 18 15
しかしここまでだと何のひねりもなくて、単なる Tcl/Tk 入門みたいな話になってしまう。そして「***/Tk ならもっとスマートに書ける。なんだその expr は」とか言われそうだ。
こういう企画は「そんなものを使ってグラフを表現するなんて!」とか「おっと、そんな書き方があったか」とか「ここはワンライナーで」みたいな部分が面白みだと思うので Tk なしの Tcl 版で1行で収まるように書いてみたものを最後に紹介します(とはいえ tclsh には awk や perl のようにコマンド引数から直接プログラムを与える書き方はない)。
eval [regsub -all {(\d+)} $argv {puts [format "%2d : " \1][string repeat * \1];}]
実行結果はこんな風。
F:\>tclsh graph3.tcl 2 5 9 2 : ** 5 : ***** 9 : *********
ループ構文が出てこないところがちょっといい感じ(かな?)。
[1] http://ll.jus.or.jp/2006/blog/doukaku3
コメント 0