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

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

(2023年12月20日)人口データを2022年版に更新
(2023年5月4日)人口データを2021年版に更新,jpGraphをバージョンアップ.

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

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

サンプル・プログラム

圧縮ファイルの内容
poppyramid.phpサンプル・プログラム本体。
population2011.csv統計データ 2011年版
population2017.csv統計データ 2017年版
population2018.csv統計データ 2018年版
population2019.csv統計データ 2019年版
population2020.csv統計データ 2020年版
population2021.csv統計データ 2021年版
population2022.csv統計データ 2022年版
poppyramid.php 更新履歴
バージョン 更新日 内容
2.1.3 2023/12/20 データを2022年版に更新
2.1.2 2023/05/04 データを2021年版に更新
2.11 2022/11/01 データを2020年版に更新
2.1 2022/02/19 PHP8対応,リファラ・チェック追加
2.0 2018/06/02 データを2017年版に更新,jpgraph 4.2.1対応

準備:JpGraphの導入

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

JpGraph は、国内ではアシアル株式会社がサポートしており、同社のサイトからコミュニティ版をダウンロードできる。QPL (Qt Free License) 1.0ライセンスの下で、非営利目的で使用する場合は無料で利用できる。
解凍したら、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  を利用する。
凡例やラベルに日本語を使う場合は、日本語フォント(TrueTypeファイル)を用意しておく。これについても、アシアル社のサイトに詳しい説明がある
具体的には、下記のようにフォント・ファイルを格納したフォルダを "jpg-config.inc.php" の定数 TTF_DIR および MBTTF_DIR に設定してやる。

  41: define('TTF_DIR','/virtual/pahoo/public_html/common/font/');
  42: define('MBTTF_DIR','/virtual/pahoo/public_html/common/font/');

実際に使うフォントは "jpgraph_ttf.inc.php" の下記の場所に定義されている。
ここで定義しているのはIPAの無償ファイルフォントで、文字情報技術促進協議会のIPAフォントから入手できる。

 133: // Japanese TrueType font used with FF_MINCHO, FF_PMINCHO, FF_GOTHIC, FF_PGOTHIC
 134: // Standard fonts from Infomation-technology Promotion Agency (IPA)
 135: // See http://mix-mplus-ipa.sourceforge.jp/
 136: define('MINCHO_TTF_FONT','ipam.ttf');
 137: define('PMINCHO_TTF_FONT','ipamp.ttf');
 138: define('GOTHIC_TTF_FONT','ipag.ttf');
 139: define('PGOTHIC_TTF_FONT','ipagp.ttf');

バージョン4.4.1(2022年5月12日)は、PHP5.1から5.6、PHP7.0から7.4、PHP8.0、8.1に対応している。残念ながら、PHP8.2では正常に動作しない箇所がある。

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

  24: //元となるCSVデータファイル名
  25: //人口:2022年 https://www.stat.go.jp/data/nenkan/73nenkan/02.html
  26: define('FILE_DATA', './population2022.csv');

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

解説:JpGraph の準備

  41: //JpGraph:include_pathが通ったディレクトリに配置すること.
  42: require_once('jpgraph/jpgraph.php');
  43: require_once('jpgraph/jpgraph_bar.php');
  44: require_once('jpgraph/jpgraph_line.php');
  45: 
  46: //グラフの幅・高さ
  47: define('WIDTH',  600);
  48: define('HEIGHT', 600);

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

解説:データ読み込み

  78: /**
  79:  * データファイル(CSV形式)を指定し,人口データを配列に読み込む.
  80:  * @param   string $filename データ・ファイル名
  81:  * @param   array  $age    年齢を格納する配列
  82:  * @param   array  $male   男性人口を格納する配列
  83:  * @param   array  $female 女性人口を格納する配列
  84:  * @return  array 読み込んだデータ/FALSE:データファイルがないなど
  85: */
  86: function readDate($filename, &$age, &$male, &$female) {
  87:     $items = array();
  88: 
  89:     //元となるデータファイルを読み込む
  90:     $infp = fopen(FILE_DATA, 'r');
  91:     if ($infp == FALSE)     return FALSE;
  92:     fgetcsv($infp, 9999, ',');      //ラベル行をスキップ
  93:     $cnt = 0;
  94:     while (!feof($infp)) {
  95:         $arr = fgetcsv($infp, 9999, ',');
  96:         if (! is_numeric($arr[0]))  continue;
  97:         $age[$cnt]    = $arr[0] / 1;        //年齢
  98:         $male[$cnt]   = $arr[4] / 1;        //男性人口(単位:千人)
  99:         $female[$cnt] = $arr[5] / 1;        //女性人口(単位:千人)
 100:         $cnt++;
 101:         if ($cnt > 100)     break;          //100歳で打ち切り
 102:     }
 103:     fclose($infp);
 104: 
 105:     return $items;
 106: }

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

 123: //人口ピラミッドは年齢の高い方が上なので配列を逆転させる.
 124: $age = array_reverse($age);
 125: $male = array_reverse($male);
 126: $female = array_reverse($female);
 127: 
 128: //女性は負数扱い.
 129: foreach ($female as $key=>$val$female[$key] = (0 - $female[$key]);

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

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

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

 131: //JpGraphでグラフを生成する
 132: $graph = new Graph(WIDTH, HEIGHT, 'auto');
 133: $graph->SetScale('textlin');
 134: 
 135: //タイトル、凡例などを設定する.
 136: $graph->img->SetImgFormat('png');
 137: $graph->img->SetMargin(60, 80, 20, 40);
 138: $graph->title->SetFont(FF_PGOTHIC, FS_NORMAL, 16);
 139: $graph->title->Set('人口ピラミッド');
 140: $graph->legend->SetFont(FF_PGOTHIC);
 141: //フッタを設定する.
 142: $graph->footer->right->SetFont(FF_PGOTHIC, FS_NORMAL, 10);
 143: $graph->footer->right->Set('produced by JpGraph');
 144: 
 145: $graph->xaxis->SetPos('min');
 146: $graph->xaxis->title->SetFont(FF_PGOTHIC);
 147: $graph->xaxis->title->Set('年齢');
 148: $graph->xaxis->SetTextLabelInterval(10);        //10歳おき
 149: $graph->xaxis->SetTitleMargin(0);
 150: 
 151: $graph->xaxis->SetPos('min');
 152: $graph->yaxis->title->SetFont(FF_PGOTHIC);
 153: $graph->yaxis->SetLabelFormatCallback('myNumberFormat');
 154: 
 155: $graph->xaxis->SetFont(FF_PGOTHIC);
 156: $graph->xaxis->SetTickLabels($age);
 157: 
 158: //グラフを90度横に倒す.
 159: $top    = 50;
 160: $bottom = 50;
 161: $left   = 50;
 162: $right  = 50;
 163: $graph->Set90AndMargin($left, $right, $top, $bottom);
 164: 
 165: //男性の棒グラフを準備する.
 166: $PlotMale = new BarPlot($male);
 167: $PlotMale->SetWidth(1.0);
 168: $PlotMale->SetLegend('男性');
 169: 
 170: //女性の棒グラフを準備する.
 171: $PlotFemale = new BarPlot($female);
 172: $PlotFemale->SetWidth(1.0);
 173: $PlotFemale->SetLegend('女性');
 174: 
 175: //2つの棒グラフを結合する.
 176: $graph->Add($PlotFemale);
 177: $graph->Add($PlotMale);
 178: 
 179: //最後に色指定を行う.
 180: $PlotFemale->SetColor('red');
 181: $PlotFemale->SetFillColor('red@0.6');
 182: $PlotMale->SetColor('blue');
 183: $PlotMale->SetFillColor('blue@0.6');
 184: 
 185: //グラフを画面に表示する.
 186: $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