Perlでグラフを作ろう (GD::Graph)
Perl でいろいろとプログラムを作っていると、あるデータをグラフ化したくなってきます。そこで、グラフを作成するモジュールを探して使ってみることにします。
モジュールの入手
Perl で、グラフを作成するのに便利なモジュールとして GD::Graph があります。まず、これを利用するのに必要なパッケージを入手しなくてはなりません。
GD Graphics Library | Thomas Boutell氏の作成した、線や多角形、円を描画するためのライブラリ | http://www.boutell.com/gd/ |
PNG graphics library | PNG グラフィックスフォーマット用のライブラリ | http://www.libpng.org/pub/png |
zlib compression library | zlib 汎用圧縮ライブラリ | http://www.gzip.org/zlib/ |
FreeType | TrueTypeフォントをレンダリングするライブラリ | http://www.freetype.org/ |
JPEG library | JPEG グラフィックスフォーマット用のライブラリ | ftp://ftp.uu.net/graphics/jpeg/ |
GD Perl Module | GD ライブラリを Perl で利用可能にするモジュール | CPAN |
GD::Text ( GDTextUtil) | GD を利用してテキストを扱えるようにするモジュール | CPAN |
GD::Graph (GDGraph) | GD を利用してグラフを扱えるようにするモジュール | CPAN |
Jcode | 日本語文字コードを変換するモジュール | http://openlab.ring.gr.jp/Jcode/ |
これらすべてが必要なわけではありません。OS によっては、すでにインストールされているものもあります。
インストール
必要なモジュールを入手したら、それらをインストールする必要があります。OSによって、入手しなければならないモジュールが異なります。ここでは、RedHat Linux 9 を利用して説明します。RedHat Linux 9 ではほとんどのライブラリがインストールされています。以下では、必要なモジュールのインストールのみ記述しています。また、Perl のバージョンが 5.6.0 以上でなければなりません。
インストールはスーパーユーザーで作業GD Perl モジュールのインストール # gzip -dc GD-1.41.tar.gz | tar xf - # cd GD-1.41 # perl Makefile.PL ... Build JPEG support? [y] <Enter> Build FreeType support? [y] <Enter> Build XPM support? [y] <Enter> Build GIF support (for patched versions of gd)? [n] <Enter> ... # make # make test (このときに X Window に対して描画できる状態で無ければいくつかテストが失敗します。) # make html # make install GD::Text Perl モジュールのインストール # gzip -dc GDTextUtil-0.86.tar.gz | tar xf - # cd GDTextUtil-0.86 # perl Makefile.PL # make # make test # make demo # make install GD::Graph Perl モジュールのインストール # gzip -dc GDGraph-1.43.tar.gz | tar xf - # cd GDGraph-1.43 # perl Makefile.PL # make # make install # make sample Jcode Perl モジュールのインストール # gzip -dc Jcode-0.83.tar.gz | tar xf - # cd Jcode-0.83 # perl Makefile.PL # make # make test # make install
利用
GD::Graph の一般的な利用には、次の3つのステップを行う必要があります。
取得したデータを Perlデータタイプに変換
グラフの描画方法を指定し、パラメータセットを追加して GD::Graphオブジェクトを作成
作成されたオブジェクトはメモリに格納されているのでファイルに保存(または、アプリケーションに渡す)
GD::Graph によって作成できるグラフには以下のようなものがあります。(一部)
グラフは、データセットを含む多次元配列を作成するところから始まります。Perlの多次元配列は、複数の配列のリファレンスを含む配列として格納します。GD::Graphデータでは、最初にX軸のラベルの配列のリファレンス格納されます。つづいて、実際のデータセットの配列のリファレンスが格納さます。ます、単純にデータセットをひとつだけ持つグラフを作ってみましょう。
my @labels = qw( under 10s 20s 30s 40s 50s 60s 70s over ); my @dataset = qw( 20 40 60 80 65 15 10 20 5 ); my @data = ( \@labels, \@dataset);
配列は、すべて同じサイズでなければなりません。そこで、もし未知の値がある場合、その値をundef
と設定することでその値については描画されなくなります。
上記のように記述しましたが、各配列に名前をつける必要が無いので無名配列を使ってデータを作成してしまうことも出来ます。
my @data = (["under","10s","20s","30s","40s","50s","60s","70s", "over"], [ 20, 40, 60, 80, 65, 15, 10, 20, 5]);
データの準備ができたら、各グラフに対応するコンストラクタを呼び出してグラフ・オブジェクトを作成します。すべてのグラフ・コンストラクタには、作成したいグラフイメージの幅と高さの2つのパラメータがあります。よって、600ピクセル X 450ピクセルの棒グラフ・オブジェクトを作成する場合は以下のように記述します。
my $graph = GD::Graph::bars->new( 400, 300 );
これで、イメージを格納する領域が確保されました。実際に表現できるグラフは以下の通りです。
GD::Graph::lines |
折線グラフ |
GD::Graph::bars |
棒グラフ |
GD::Graph::points |
点グラフ |
GD::Graph::linespoints |
点付折れ線グラフ |
GD::Graph::area |
面グラフ |
GD::Graph::mixed |
上記のグラフを組み合わせたグラフ |
GD::Graph::pie |
円グラフ |
次に、必要な外観をグラフ・オブジェクトに設定します。ここでは、グラフ・オブジェクトのset()
メソッドを使用してタイトルとグラフのY軸のラベルを設定しましょう。日本語の文字列は UTF-8 にします。
$graph->set( title => jcode("にこにこ村の人口")->utf8, y_label => jcode("人数")->utf8 );
次に、日本語を表示するために使用する TrueType フォントを選ばなければなりません。
GD::Text->font_path( "./" ); $graph->set_title_font( "GOTHIC_FONT", 14 ); $graph->set_legend_font( "GOTHIC_FONT", 8 ); $graph->set_x_axis_font( "GOTHIC_FONT", 8 ); $graph->set_x_label_font( "GOTHIC_FONT", 10 ); $graph->set_y_axis_font( "GOTHIC_FONT", 8 ); $graph->set_y_label_font( "GOTHIC_FONT", 8 );
これは、カレントディレクトリにある GOTHIC_FONT.ttf
という TrueType フォントをそれぞれのラベルでそれぞれのフォントサイズで利用することを意味します。
これで、グラフを実際に描画できるようになりました。オブジェクトの作成は、plot()
メソッドを使用します。
my $image = $graph->plot( \@data );
データの配列のリファレンスを渡しています。何らかの原因でグラフの描画が失敗した場合、未定義の値が返されます。
最後に、作成したオブジェクトを利用可能な形式に変換します。JPEG形式のファイルを作ってみましょう。
open( OUT, "> graph.jpg") or die( "Cannot open file: graph.jpg" ); binmode OUT; print OUT $image->jpeg(); close OUT;
これで、graph.jpg という名前で JPEG イメージが出来上がりました。出力先や出力できる画像フォーマットはいくつかありますが、実際に Web などで利用することを考えると以下の通りです。
open( OUT, "> filename") |
ファイル "filename" へ出力 |
open( OUT, "| display -") |
ImageMagickによる X Window への表示 |
print "Content-type: image/jpeg;\n\n"; |
ブラウザに返す |
jpeg() |
JPEG フォーマット |
png() |
PNG フォーマット |
今までの内容を、実際に実行できるようにコードをまとめてみましょう。
#!/usr/bin/perl -w use strict; use Jcode; use GD::Graph::bars; my @labels = qw( under 10s 20s 30s 40s 50s 60s 70s over ); my @dataset = qw( 20 40 60 80 65 15 10 20 5 ); my @data = ( \@labels, \@dataset); my $graph = GD::Graph::bars->new( 400, 300 ); $graph->set( title => jcode("にこにこ村の人口")->utf8, y_label => jcode("人数")->utf8 ); GD::Text->font_path( "./" ); $graph->set_title_font( "GOTHIC_FONT", 14 ); $graph->set_legend_font( "GOTHIC_FONT", 8 ); $graph->set_x_axis_font( "GOTHIC_FONT", 8 ); $graph->set_x_label_font( "GOTHIC_FONT", 10 ); $graph->set_y_axis_font( "GOTHIC_FONT", 8 ); $graph->set_y_label_font( "GOTHIC_FONT", 8 ); my $image = $graph->plot( \@data ); open( OUT, "> graph.jpg") or die( "Cannot open file: graph.jpg" ); binmode OUT; print OUT $image->jpeg(); close OUT;
出来上がった JPEG ファイル(graph.jpg )は、以下のようになります。
ここまでで、GD::Graph の機能が簡単に理解できたと思います。非常に簡単にグラフが作れるので大変便利なモジュールです。つづいて、もう少し複雑なグラフを作ってみましょう。
GD::Graphモジュールは、グラフ・スタイルの選択とオプションの設定によりグラフの出力を調整することができます。グラフのスタイルは、上記の表の一覧を確認してください。オプションは、すべてのグラフに共通のものと固有のものがあります。ここですべては紹介できないので、よく使いそうなものをピックアップして紹介します。
まず、フォントの設定ですが、これも既に上記で説明しているので省略します。日本語の TrueType フォントを指定し、漢字コードを UTF-8 にすればほぼ問題なく表示されます。
続いて、色の指定ですが、通常 16 進数を用いた色の指定方法(#FF0000)で行えるが、色の名前を用いて色指定を行えると便利なのではないかと考えます。それを実現する機能が GD::Graph::colour
モジュールを使う方法です。ううむ、スペルがイギリス英語だなあ〜
use GD::Graph::colour qw( :files ); GD::Graph::colour::read_rgb( "/usr/lib/X11/rgb.txt" );
これで、X Windows System のカーラーテーブルのカラー名を使用できるようになります。実際の色は、xcolors
コマンドで確認できます。
boxclr => "WhiteSmoke" dclrs => [ "SlateGray" ] shadowclr => "chocolate" shadow_depth => 3
これらは、グラフ・オブジェクトのset()
メソッドで設定します。では、「にこにこ村の人口」のグラフの色を変更してみましょう。画像フォーマットも PNG に変更してみます。
オプション設定の多くは、グラフ・オブジェクトのset()
メソッドを使って設定します。よく使いそうな設定をリストしておきます。
title |
グラフのタイトル |
t_margin |
Top マージン |
b_margin |
Bottom マージン |
l_margin |
Left マージン |
r_margin |
Right マージン |
x_label |
X軸ラベル |
y_label |
Y軸ラベル |
y_max_value |
Y軸の最大値 |
y_tick_number |
Y軸を刻む数 |
y_label_skip |
Y軸ラベルのスキップ |
types |
mixed タイプのグラフの場合、各データをどの種類のグラフにするか無名配列でリストする |
cumulate |
データセットが積算される(棒グラフ、面グラフ) |
line_types |
線グラフの線の種類を無名配列でリストする( 1:実線 2:ダッシ 3:点線 4:点線 ) |
line_width |
線グラフの太さ |
markers |
点、点付折れ線グラフで使われる点の種類を無名配列でリストする ( 1:塗り四角 2:四角 3:十字 4:クロス十字 5:塗り菱形 6:菱形 7:塗り丸 8:丸 ) |
marker_size |
点、点付折れ線グラフで使われる点のサイズ(デフォルト 4) |
bar_width |
棒グラフの幅 |
bar_spacing |
棒グラフ間の幅 |
bgclr |
グラフの背景色 |
fgclr |
グラフの前景色 |
boxclr |
グラフ内の背景色 |
dclrs |
グラフの色を無名配列でリストする |
accentclr |
グラフの外枠の色 |
shadowclr |
グラフの影の色 |
shadow_depth |
グラフの影の幅 |
また、よく使いそうなメソッドもリストしておきます。
set_legend() |
凡例となる文字列をリストする |
set_text_clr() |
文字の色 |
最後に、ちょっと複雑なグラフと円グラフを作ってみましょう。まず、棒グラフと折れ線グラフの混在したグラフ。
#!/usr/bin/perl -w use strict; use GD::Graph::mixed; use GD::Graph::colour qw( :files ); use GD::Text; use Jcode; GD::Graph::colour::read_rgb( "/usr/lib/X11/rgb.txt" ) or die( "Can't read colours" ); my @labels = qw( under 10s 20s 30s 40s 50s 60s 70s over ); my @male = qw( 8 20 25 33 29 8 7 8 0 ); my @female = qw( 12 20 35 47 36 7 3 12 5 ); my @differ = qw( 1 3 9 10 2 1 5 2 0 ); my @data = ( \@labels, \@male, \@female, \@differ); my $graph = GD::Graph::mixed->new( 400, 300 ); $graph->set( title => jcode("にこにこ村の人口")->utf8, t_margin => 10, b_margin => 10, l_margin => 10, r_margin => 10, x_label => jcode("年齢")->utf8, x_label_position => 0.5, y_label => jcode("人数")->utf8, types => [ qw(bars bars linespoints) ], dclrs => [ qw(AliceBlue LavenderBlush DarkSalmon) ], boxclr => "snow", y_tick_number => 10, y_label_skip => 2, line_width => 1, markers => [ 7 ], marker_size => 2, bar_width => 10, bar_spacing => 3, cumulate => 1 ); $graph->set_legend( jcode("男性")->utf8, jcode("女性")->utf8, jcode("前年差")->utf8); GD::Text->font_path( "./" ); $graph->set_title_font( "GOTHIC_FONT", 12 ); $graph->set_legend_font( "GOTHIC_FONT", 7 ); $graph->set_x_axis_font( "GOTHIC_FONT", 7 ); $graph->set_x_label_font( "GOTHIC_FONT", 9 ); $graph->set_y_axis_font( "GOTHIC_FONT", 7 ); $graph->set_y_label_font( "GOTHIC_FONT", 7 ); my $image = $graph->plot( \@data ) or die( "Cannot create image" ); open( OUT, "> graph2.png") or die( "Cannot open file: graph2.png" ); binmode OUT; print OUT $image->png(); close OUT;
円グラフ
#!/usr/bin/perl -w use strict; use GD::Graph::pie; use GD::Graph::colour qw( :files ); use GD::Text; use Jcode; GD::Graph::colour::read_rgb( "/usr/lib/X11/rgb.txt" ) or die( "Can't read colours" ); my @data = ( [ jcode("好き")->utf8, jcode("嫌い")->utf8, jcode("どちらともいえない")->utf8, jcode("無回答")->utf8 ], [ 43, 15, 32, 10 ] ); my $graph = GD::Graph::pie->new( 400, 300 ); $graph->set( title => jcode("にこにこ村について")->utf8, t_margin => 10, b_margin => 10, l_margin => 10, r_margin => 10, axislabelclr => 'black', dclrs => [ qw(MediumSlateBlue MediumSeaGreen DarkSalmon FloralWhite) ], pie_height => 36, start_angle => 230, transparent => 0, ); GD::Text->font_path( "./" ); $graph->set_title_font( "GOTHIC_FONT", 12 ); $graph->set_value_font( "GOTHIC_FONT", 8 ); my $image = $graph->plot( \@data ) or die( "Cannot create image" ); open( OUT, "> graph3.png") or die( "Cannot open file: graph3.png" ); binmode OUT; print OUT $image->png(); close OUT;
Solaris でperl モジュールコンパイル時のエラーに対処
Solarisのパッケージに含まれている perl と gcc を利用して perl モジュールを作成しようした際にエラーが出てコンパイルできない場合があります。そのような場合 perlgcc (
/usr/perl5/bin/perlgcc)
を利用します。
# perl Makefile.PL # make /usr/ucb/cc: language optional software package not installed ... # perl Makefile.PL CC=gcc # make gcc: unrecognized option `-KPIC' gcc: language ildoff not recognized ... # perlgcc Makefile.PL # make
perlgcc
が存在しない場合、perl Makefile.PL
によって生成された Makefile
を以下のように修正するとよい...
修正前 | 修正後 |
CCCDLFLAGS = -KPIC | CCCDLFLAGS = |
OPTIMIZE = -xO3 -xspace -xildoff | OPTIMIZE = |
# perl Makefile.PL CC=gcc # edit Makefile # make # make install
これを毎回行うのは面倒で gcc しか利用しないなら Config.pm
を編集してしまうという荒業があります。たとえば、 Intel 版 Solaris の Perl 5.8.4 の場合。
/usr/perl5/5.8.4/lib/i86pc-solaris-64int/Config.pm
の編集修正前 | 修正後 |
cc='cc' | cc='gcc' |
ccname='cc' | ccname='gcc' |
cccdlflags='-KPIC' | cccdlflags='' |
ld='cc' | ld='gcc' |
optimize='-xO3 -xspace -xildoff' | optimize='' |
'cc' => 'cc' | 'cc' => 'gcc' |
これで、デフォルトで gcc を利用するようになります。 この作業は、perlgcc が存在しない場合の応急措置です。Solarisのパッケージに含まれる Perl ではなく、gcc を利用してソースから Perl をビルドしたほうがよいかもしれません。