目次

GDを使ったグラフ描画

2008年01月31日 03時14分45秒

これは何?

perlで書いたグラフの描画コード。

perlでグラフを書く

GD.pm

有名どころにGDなるものがある。このモジュールを利用すると、昔のBASICに実装されていたグラフィックステートメントの様な雰囲気のメソッド群が利用できるようになる。 ただし、直接画面を描画するわけではなく、仮想画面を準備しそこへ描画。最終的に仮想画面の画像データを必要とする画像形式で取出しする。このあたりはさすがに昨今の描画システムを踏襲しているようだ。

グラフを書くには絵を描く道具はあるものの、これを有用なものにくみ上げるのは大変手間がかかる。 グラフ描画コンポーネントが数多く作られ、利用されているのは、こういった手間を省いて、本来の要件に注力出来るようにするためである。

これでどうする?

たとえば、円グラフであれば、表示するデータのスケールによって描画精度を変更し、美しく見えるようにする必要があるし、棒グラフであれば、各データの比率を出して美しく見える大きさ(比率)を算出しなくてはいけない。 こういった事を考えつつ作業を行うのは非常に困難が伴うはずだ。

しかし、自分の目的に沿ったコンポーネントが無い場合はやはり、原始的な部分から組み上げていかなければならない。 とりあえず生成品質はおいて。

ソース

以下は、とりあえずの円グラフを書き出すperlスクリプトである。CGIとして利用する。 値としてP1,P2を入力。その比率を円グラフであらわす。円グラフはPNG形式の画像として出力される。

circle.pl
 #!/usr/bin/perl
 
 use GD;
 use CGI;
 
 my $PI   = 3.141592653;
 my $R    = 50;
 my $X    = 150;
 my $Y    = 150;
 
 my $form = new CGI;
 my $image = new GD::Image(300,300);
 
   $p1 = $form->url_param("P1");
   $p2 = $form->url_param("P2");
 
   $white = $image->colorAllocate(255,255,255);
   $black = $image->colorAllocate(  0,  0,  0);
   $blue  = $image->colorAllocate(128,128,255);
   $red   = $image->colorAllocate(255,  0,  0);
 
   $image->transparent($white);
 
   $image->filledRectangle( 20,50, 50,55, $blue);
   $image->string(gdMediumBoldFont, 55,45, "P1 " . ($p1)."/".($p1+$p2) , $black);
 
   $image->filledRectangle( 20,60, 50,65, $red);
   $image->string(gdMediumBoldFont, 55,55, "P2 " . ($p2)."/".($p1+$p2) , $black);
 
   if ($p1+$p2 > 0) {
     $p1_percent    = ( $p1 / ( $p1 + $p2 ) );
     $p2_percent    = ( $p2 / ( $p1 + $p2 ) );
     $p1_percentDo  = ( $p1 / ( $p1 + $p2 ) ) * 360;
     $p2_percentDo  = ( $p2 / ( $p1 + $p2 ) ) * 360;
     $p1_percentR   = ( $p1 / ( $p1 + $p2 ) ) * 2 * $PI;
     $p2_percentR   = ( $p2 / ( $p1 + $p2 ) ) * 2 * $PI;
 
     ## p1
     $image->arc( $X,$Y, 2*$R,2*$R, 0                            ,$p1_percentDo, $black);
     $image->line( $X,$Y, $X+int(cos(0) * $R)                    ,$Y+int(sin(0) * $R),  $black);
     $image->line( $X,$Y, $X+int(cos($p1_percentR) * $R)         ,$Y+int(sin($p1_percentR) * $R), $black);
     $image->fill( $X+int(cos($p1_percentR/2) * ($R/2))          ,$Y+int(sin($p1_percentR/2) * ($R/2)), $blue);
 
     ## p2
     $image->arc( $X,$Y, 2*$R,2*$R, $p1_percentDo                          ,$p1_percentDo+$p2_percentDo, $black);
     $image->line( $X,$Y, $X+int(cos($p1_percentR) * $R)                   ,$Y+int(sin($p1_percentR) * $R), $black);
     $image->line( $X,$Y, $X+int(cos($p1_percentR+$p2_percentR) * $R)      ,$Y+int(sin($p1_percentR+$p2_percentR) * $R), $black);
     $image->fill( $X+int(cos($p1_percentR+($p2_percentR/2)) * ($R/2))     ,$Y+int(sin($p1_percentR+($p2_percentR/2)) * ($R/2)), $red);
   }
   else {
     $image->arc( $X,$Y, 2*$R,2*$R, 0,360, $black);
   }
 
 print("Content-type: image/png\n\n");
 print $image->png;

これを “circle.pl” とでも名前をつけて保存し、

 http://hogehoge.co.jp/circle.pl?P1=10&P2=35

のように呼び出す。

http://hgotoh.jp/circle.pl?P1=10&P2=35

実行してみればわかるが、ジャギーは目立つし、極端な比率の場合の表示もプア。 描画開始位置もおかしい。 こういった細かい部分にどれだけ手が入っているかで、グラフ描画コンポーネントの価値が決まる。