PHPとJpGraphで人口ピラミッドを表示する

(1/1)
JpGraph は PHP のライブラリの一種で、Excel のように簡単にグラフを作成できる。QPL 1.0 (Qt Free Licensee)ライセンスにしたがい、コミュニティや教育などの非営利目的での使用に限り無料で利用できる。
ぱふぅ家ホームページでは、JpGraph を使ってアクセス回数の推移などを表示している。
今回は、JpGraph を用い、日本の人口ピラミッドを表示させるプログラムを作ってみることにする。

サンプル・プログラムの実行例

PHPとJpGraphで人口ピラミッドを表示する

サンプル・プログラム

準備:JpGraph の導入

まず、JpGraph を使うための準備をする。

JpGraph は、国内ではアシアル株式会社がサポートしており、同社のサイトから無償版をダウンロードできる。解凍したら、PHP から利用できるディレクトリにコピーしておく。
JpGraph の使用に際しては、GD ライブラリがインストールされていることが前提となる。

JpGraph は複数の PHP プログラムから成り立っているが、さまざまな場所にあるプログラムから呼ばれることになるだろうから、相対パスで指定することが面倒である。
PHP には、外部ファイルを読み込むためのオプション設定 include_path が用意されている。この機能を利用するといいだろう。
設定ファイル php.ini に記述してやる。Linux環境であれば、以下のようにセミコロン ; を介して複数のパスを設定する。

include_path=".:/php/includes;/php/jpgraph"


Windows環境であれば、以下のように記述する。

include_path=".;c:\php\includes;c:\php\jpgraph"



include_path は、 require_once  のほか、 require 、 include 、  fopen 、 file 、  readfile 、 file_get_contents  に影響を及ぼす。
実行時にオプション値を設定したい場合は、組み込み関数  set_include_path  を利用する。

0133: // Japanese TrueType font used with FF_MINCHO, FF_PMINCHO, FF_GOTHIC, FF_PGOTHIC
0134: // Standard fonts from Infomation-technology Promotion Agency (IPA)
0135: // See http://mix-mplus-ipa.sourceforge.jp/
0136: define('MINCHO_TTF_FONT','ipam.ttf');
0137: define('PMINCHO_TTF_FONT','ipamp.ttf');
0138: define('GOTHIC_TTF_FONT','ipag.ttf');
0139: define('PGOTHIC_TTF_FONT','ipagp.ttf');

凡例やラベルに日本語を使う場合は、事前に日本語フォント(TrueType ファイル)を用意しておく必要がある。これについても、アシアル社のサイトに詳しい説明がある
具体的には、フォント・ファイルを格納したフォルダを "jpg-config.inc.php" の定数 TTF_DIR および MBTTF_DIR に設定してやる。
実際に使うフォントは "jpgraph_ttf.inc.php" の上の場所に定義されている。いま定義されているのは、IPA の無償ファイルフォントで、IPA フォント ダウンロードページから入手できる。

1399:         $y2 = round($y2);
1400: 
1401: //        imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color);
1402:         $this->DrawLine($this->img, $x1$y1$x2$y2$this->line_weight, $this->current_color);
1403:         $this->lastx=$x2;

なお、バージョン 4.2.1 では、折れ線グラフの太さを設定する Weight プロパティが正常に機能しなかった。そこでソース・プログラムを解析したところ、"gd_image.inc.php" の上の部分、imageline関数をコメントアウトし、DrawLine メソッドのコメントを外せば正常に動くようになった。

準備:人口データファイル

0015: //元となるCSVデータファイル名
0016: //人口・死亡率:2017年 http://www.stat.go.jp/data/nenkan/66nenkan/02.html
0017: //出生率:2020年の中位値 http://www.ipss.go.jp/pp-zenkoku/j/zenkoku2017/pp29_Report2.pdf
0018: define('FILE_DATA', './population2017.csv');

男女の人口は外部ファイル("population2017.csv")で用意する。このファイルは、「PHP で人口を推計する」で利用するものと同じである。
各列の構造は以下の通り。いずれも 2017 年(平成 29 年)時点の値である。
  1. 年齢
  2. その年齢における男性の死亡率(千人あたり)
  3. その年齢における女性の死亡率(千人あたり)
  4. その年齢における出生率(女性一人あたり)
  5. その年齢における男性人口(千人)
  6. その年齢における女性人口(千人)
人口と死亡率については日本統計年鑑(総務省統計局)を参考にした。100 歳超の死亡率は分からないので、適当に設定した。出生率については、日本の将来推計人口(国立社会保障・人口問題研究所)の仮定値表の中位推計値を採用した。

解説:JpGraph の準備

0020: //JpGraph(各自の環境に合わせて)
0021: require_once('jpgraph/jpgraph.php');
0022: require_once('jpgraph/jpgraph_bar.php');
0023: require_once('jpgraph/jpgraph_line.php');
0024: 
0025: //グラフの幅・高さ
0026: define('WIDTH',  600);
0027: define('HEIGHT', 600);

"jpgraph.php" は共通ライブラリ。もう 1 つはグラフの種類によって読み込むライブラリが異なる。今回は棒グラフを用いるので "jpgraph_bar.php" を読み込む。
詳細は、アシアル社のサイトからダウンロードした圧縮ファイルに含まれる日本語ドキュメント(HTML 形式)を参照のこと。

解説:データ読み込み

0029: /**
0030:  * データ読み込み
0031:  * @param string $filename データ・ファイル名
0032:  * @param array  $age    年齢を格納する配列
0033:  * @param array  $male   男性人口を格納する配列
0034:  * @param array  $female 女性人口を格納する配列
0035:  * @return array 読み込んだデータ/FALSE:データファイルがないなど
0036: */
0037: function readDate($filename, &$age, &$male, &$female) {
0038:     $items = array();
0039: 
0040:     //元となるデータファイルを読み込む
0041:     $infp = fopen(FILE_DATA, 'r');
0042:     if ($infp == FALSE)     return FALSE;
0043:     fgetcsv($infp, 9999, ',');      //ラベル行をスキップ
0044:     $cnt = 0;
0045:     while (!feof($infp)) {
0046:         $arr = fgetcsv($infp, 9999, ',');
0047:         if (! is_numeric($arr[0]))   continue;
0048:         $age[$cnt]    = $arr[0] / 1;     //年齢
0049:         $male[$cnt]   = $arr[4] / 1;     //男性人口(単位:千人)
0050:         $female[$cnt] = $arr[5] / 1;     //女性人口(単位:千人)
0051:         $cnt++;
0052:         if ($cnt > 100) break;           //100歳で打ち切り
0053:     }
0054:     fclose($infp);
0055: 
0056:     return $items;
0057: }

データファイルの値は、年齢を配列 $age に、男性人口を配列 $male に、女性人口を配列 $female に代入するようにしてある。

0074: //人口ピラミッドは年齢の高い方が上なので配列を逆転させる
0075: $age = array_reverse($age);
0076: $male = array_reverse($male);
0077: $female = array_reverse($female);
0078: 
0079: //女性は負数扱い
0080: foreach ($female as $key=>$val$female[$key] = (0 - $female[$key]);

人口ピラミッドは、年齢階層が高い方が上になる。当初の配列の順序では逆になってしまうので、関数  array_reverse  を使って配列の順序を逆転させておく。

人口ピラミッドを描くには、水平棒グラフを使う。
グラフの中央をゼロとして、右側が男性人口、左側が女性人口である。男性人口は正数、女性人口は負数として水平グラフを描けば、人口ピラミッドとなるはずである。
そこで、あらかじめ女性人口を負数にしておく。

解説:グラフの作成・描画

0082: //JpGraphでグラフを生成する
0083: $graph = new Graph(WIDTH, HEIGHT, 'auto');
0084: $graph->SetScale('textlin');
0085: 
0086: // タイトル、凡例などの設定
0087: $graph->img->SetImgFormat('png');
0088: $graph->img->SetMargin(60, 80, 20, 40);
0089: $graph->title->SetFont(FF_PGOTHIC, FS_NORMAL, 16);
0090: $graph->title->Set('人口ピラミッド');
0091: $graph->legend->SetFont(FF_PGOTHIC);
0092: 
0093: $graph->xaxis->SetPos('min');
0094: $graph->xaxis->title->SetFont(FF_PGOTHIC);
0095: $graph->xaxis->title->Set('年齢');
0096: $graph->xaxis->SetTextLabelInterval(10);       //10歳おき
0097: $graph->xaxis->SetTitleMargin(0);
0098: 
0099: $graph->xaxis->SetPos('min');
0100: $graph->yaxis->title->SetFont(FF_PGOTHIC);
0101: $graph->yaxis->SetLabelFormatCallback('myNumberFormat');
0102: 
0103: $graph->xaxis->SetFont(FF_PGOTHIC);
0104: $graph->xaxis->SetTickLabels($age);
0105: 
0106: //グラフを90度横に倒す
0107: $top    = 50;
0108: $bottom = 50;
0109: $left   = 50;
0110: $right  = 50;
0111: $graph->Set90AndMargin($left$right$top$bottom);
0112: 
0113: //男性の棒グラフを準備する
0114: $PlotMale = new BarPlot($male);
0115: $PlotMale->SetWidth(1.0);
0116: $PlotMale->SetLegend('男性');
0117: 
0118: //女性の棒グラフを準備する
0119: $PlotFemale = new BarPlot($female);
0120: $PlotFemale->SetWidth(1.0);
0121: $PlotFemale->SetLegend('女性');
0122: 
0123: //2つの棒グラフを結合する
0124: $graph->Add($PlotFemale);
0125: $graph->Add($PlotMale);
0126: 
0127: //色指定は最後に
0128: $PlotFemale->SetColor('red');
0129: $PlotFemale->SetFillColor('red@0.6');
0130: $PlotMale->SetColor('blue');
0131: $PlotMale->SetFillColor('blue@0.6');
0132: 
0133: //グラフを表示する
0134: $graph->Stroke();

JpGraph は、グラフを Graph オブジェクトとして扱う。
まず、新しいグラフオブジェクト $graph を生成する。

JpGraph では水平棒グラフは扱えない。そこで、通常の棒グラフを描いたグラフ領域全体をメソッド Set90AndMargin により 90 度横に倒すことで実現する。
この際、描画領域境界からのマージン($top, $bottom, $left, $right)を設定しておく必要がある。

メソッド SetLegend はグラフの凡例を定義する。
ここでは日本語を使っているが、TrueType フォントを使うので UTF-8 でエンコードしてやる必要があるが、本プログラムは内部コードが UTF-8 なので、とくに変換を意識する必要はない。

メソッド SetLabelFormatCallback を使って軸目盛りの書式を指定できる。ここではユーザー関数 myNumberFormat を指定している。この関数は、女性人口が負数となっていることを見せないようにするため、値の絶対値をとり、カンマ区切りを入れた正の整数として表示するものである。

日本語フォントファイルを導入し、FF_PGOTHIC に対して日本語フォントを対応づけていれば、日本語表示が可能であるはずである。ただし、日本語の指定は UTF-8 コードで行うこと。これは、「PHP で TrueType フォントを利用する」で述べたのと同じ理由による。

男性と女性は、別々のグラフとして描く。まず男性のグラフである。
BarPlot メソッドで棒グラフ・オブジェクトを生成する。棒グラフの間隔はゼロにする。

メソッド Add を使い、グラフオブジェクト $graph に男性のグラフと女性のグラフを結合する。グラフのタイトルや軸名称も設定する。

グラフの色指定は、メソッド Add のあとに行う。これは JpGraph 4.2 の仕様である。
棒グラフの塗りつぶし色を指定するメソッド SetFillColor では、透明度を指定できる。アットマークの後に透明度を指定する。

最後に、Storoke メソッドを使って画面にグラフを表示する。

参考サイト

(この項おわり)
header