CodeIgniterの学習 48 - PHPLOTのラッパーライブラリを作ってグラフ生成を簡単にする その1 (PHPでグラフを生成して表示したい 2 (実装))
(08/12/04:
Thanks for introduce this source to the CodeIgniter Wiki. I feel a little happy!
http://codeigniter.com/wiki/Phplot/
CodeIgniter本家のWikiにこの拙いソースを翻訳して投稿してくれた方がいた。
ついでに本家wiki側ソースの、自動翻訳絡みでの誤変換の微修正を行った。
(一部ディレクトリ構成等に差違有り))
今日は CodeIgniter上でのグラフ生成を、 PHPLOT(http://phplot.sourceforge.net/) を使って簡単に出来るようにしてみる。
かなり昔のエントリー(CodeIgniterの学習 5 - PHPでグラフを生成して表示したい 1 (調査) http://d.hatena.ne.jp/dix3/20080922/1222042738 ) の続き。
以前のエントリーで調査したまま放置プレイしていて気になっていたので、
呼びだしと生成を簡単に出来るように、適当にラッパーライブラリを作ってみた。
まだまだα版だけど、モチベーションをあげるために貼っておく。
画面
先に画面を貼っておく。こんなかんじ。
呼びだし時のパラメータを極力少なくしているが、
実際は、きめ細かにパラメータ設定出来るので、調整すればもっと良くなるはず。
インラインで表示させるために、一度画像ファイルを物理的に生成している。
古い画像ファイル(img/plot/plot_xxx.png)は、次回呼びだし時に自動的に消去するようにしているが、
unlinkを呼んでいるので、意図しないファイルを消してしまわないように注意。(var $old_file_del_flg = false;で試した方がいいかも)
なお、画像ファイルの作成パスは、
デフォルトでは ドキュメントルート/img/plot/plot_ランダムな文字列12桁_タイムスタンプ.png
としている。
ファイルが消えるまでは、直リンクで見えてしまうので注意。後で何とかしたい。
作成ソース
作成したソースは下記のとおり。いつもながら無保証。まだα版につきいろいろ気に入らないところがある。たぶん不具合もある。
作る方で疲れたので、今日は説明は省略する。
ソース内のコメントを参照のこと。詳しくは次回に書くかも。
ライブラリ:application/libraries/graph.php
<?php if ( !defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' ); // phplotのラッパーライブラリ 作成中 // 目的、phplotの呼びだしが煩雑なのでラッパーを噛まして簡略化する // @version 0.01-alpha // @link http://d.hatena.ne.jp/dix3/20081125/1227568495 // TODO:デフォルトパラメータの調整 // TODO:不要ファイル削除周りをもっと洗練する // TODO:直リンク拒否対策 // TODO:コメントの整備 class Graph { var $CI; var $obj; var $base_path = 'img/plot/'; var $random_file_prefix = 'plot'; //ランダムなファイル名の生成ファイルのprefix var $random_file_name_length = 12; //ランダムなファイル名の時のprefix,suffixを除いた部分の長さ var $old_file_del_flg = true; //生成後base_path配下の古いファイルを削除するか var $old_file_del_span = 10; //古いファイルの保存秒数 var $font_path; //グラフ用フォントパス var $width; //幅 var $height; //高さ var $file_path; //生成ファイルのフルパス var $url; //生成ファイルのURL var $input_file_path; // var $data; var $status; function Graph( $params = array() ) { $this -> CI = get_instance(); $this -> CI -> load -> helper( 'string' ); $this -> CI -> load -> helper( 'url' ); $this -> CI -> load -> helper( 'file' ); $this -> CI -> load -> helper( 'html' ); // 初期化 $this -> init($params); } // 初期化 function init( $params = array() ) { require_once( 'phplot.php' ); // フォント $default_font_path = BASEPATH . 'fonts/sazanami-gothic.ttf'; if ( isset( $params['font_path'] ) && realpath( $params['font_path'] ) && is_file( realpath( $params['font_path'] ) ) ) { $this -> font_path = $params['font_path']; }else { if ( isset( $default_font_path ) && realpath( $default_font_path ) && is_file( realpath( $default_font_path ) ) ) { $this -> font_path = $default_font_path ; } } // 生成ファイルを保存するディレクトリ $this -> base_path = isset( $params['base_path'] ) ? $params['base_path'] : $this -> base_path ; // ランダムなファイル名の生成ファイルのprefix $this -> random_file_prefix = isset( $params['random_file_prefix'] ) ? $params['random_file_prefix'] : $this -> random_file_prefix ; // ランダムなファイル名の時のprefix,suffixを除いた部分の長さ $this -> random_file_name_length = isset( $params['random_file_name_length'] ) ? ( int ) $params['random_file_name_length'] : $this -> random_file_name_length ; // 生成後古いファイルを削除するか $this -> old_file_del_flg = isset( $params['old_file_del_flg'] ) ? $params['old_file_del_flg'] : $this -> old_file_del_flg ; // 幅 $this -> width = isset( $params['width'] ) ? ( int ) $params['width'] : 450 ; // 高さ $this -> height = isset( $params['height'] ) ? ( int ) $params['height'] : 350 ; // グラフファイルの保存パス $fpath = isset( $params['path'] ) ? $params['path'] : '' ; // グラフファイル名、指定無しの時はランダムなファイル名.pngにする $fname = isset( $params['name'] ) ? $params['name'] : $this -> random_file_prefix . '_' . random_string( 'alnum', $this -> random_file_name_length ) . '_' . time() . '.png'; // ベースパスの設定 if ( $fpath && realpath( $fpath ) ) { $this -> file_path = rtrim( realpath( $fpath ), '/' ) . '/' . $fname ; }else { // ベースパスが指定されていないときは、ドキュメントルート/img/plot/以下に作成 if ( !realpath( $this -> base_path ) || !is_dir( realpath( $this -> base_path ) ) ) { mkdir( $this -> base_path, 0755 ); } $this -> file_path = realpath( $this -> base_path ) . '/' . $fname ; } // 生成ファイルのURL $this -> url = rtrim( base_url(), '/' ) . '/' . rtrim( $this -> base_path, '/' ) . '/' . $fname; // if ( isset( $params['input'] ) && realpath( $params['input'] ) && is_file( realpath( $params['input'] ) ) ) { $this -> input_file_path = $params['input']; }else { $this -> input_file_path = NULL ; } $this -> obj = new PHPlot( $this -> width, $this -> height, $this -> file_path, $this -> input_file_path ); } // データとパラメータのセット function setdata( $data = array(), $params = array() ) { if ( !$data || !is_array( $data ) ) { return false; }else { $this -> data = $data; } // デフォルトパラメータのセット $this -> _setdefaultparams(); // 追加パラメータのセット if ( $params ) { $this -> _setparams( $params ); } $this -> obj -> SetDataValues( $this -> data ); return true; } // デフォルトパラメータのセット、todo:あとで良い感じに調整する。 // (追加パラメータをなるべく渡さないで良いように調整する) function _setdefaultparams() { // フォントの指定 if($this -> font_path){ $this -> obj -> SetDefaultTTFont( $this -> font_path ); } // ファイルとして生成する $this -> obj -> SetIsInline( true ); // Select the data array representation and store the data: $this -> obj -> SetDataType( 'text-data' ); // 背景の色 $this -> obj -> SetBackgroundColor( '#dddddd' ); $this -> obj -> SetPlotBgColor( '#f9f9f9' ); $this -> obj -> SetDrawPlotAreaBackground( true ); // フォントサイズ if($this -> font_path){ $this -> obj -> SetFont( 'generic', $this -> font_path, 9 ); $this -> obj -> SetFont( 'title', $this -> font_path, 11 ); $this -> obj -> SetFont( 'x_label', $this -> font_path, 9 ); $this -> obj -> SetFont( 'y_label', $this -> font_path, 9 ); } // 内側の枠線 $this -> obj -> SetPlotBorderType( 'full' ); // 凡例の位置 // $this -> obj -> SetLegendWorld( 0.1, 30 ); // Define the data range. PHPlot can do this automatically, but not as well. // $this -> obj -> SetPlotAreaWorld( 0, 0, 7, 100 ); // ラベルの有無と、刻みの有無と位置 $this -> obj -> SetXTickPos( 'none' ); $this -> obj -> SetXTickLabelPos( 'none' ); // $this -> obj -> SetXDataLabelPos( 'plotdown' ); // $this -> obj -> SetYTickPos( 'plotright' ); // $this -> obj -> SetYTickLabelPos( 'plotright' ); return true; } // 追加パラメータのセット function _setparams( $params = array() ) { $class_methods = get_class_methods( get_class( $this -> obj ) ); // 各種メソッドを呼びだしてパラメータをセットする foreach( $params as $k => $v ) { if ( in_array( $k, $class_methods ) ) { if(is_array($v)){ $this -> obj -> $k( $v ); }elseif(is_string($v)){ //TODO:後で、もっと綺麗に書けるんだっけ? $p = explode(',',$v); $cnt = count($p); switch($cnt){ case 1: $this -> obj -> $k( $p[0] ); break; case 2: $this -> obj -> $k( $p[0],$p[1] ); break; case 3: $this -> obj -> $k( $p[0],$p[1],$p[2] ); break; case 4: $this -> obj -> $k( $p[0],$p[1],$p[2],$p[3] ); break; case 5: $this -> obj -> $k( $p[0],$p[1],$p[2],$p[3],$p[4]); break; default: break; } }else{ } } } return true; } // グラフファイルの生成 function draw() { if ( $this -> data ) { if ( $this -> old_file_del_flg ) { $this -> gcfiles(); } $this -> status = $this -> obj -> DrawGraph(); return $this -> status; }else { return false; } } // 生成したグラフファイルのURLを取得 function geturl() { return ( $this -> status ) ? $this -> url : ''; } // 生成したグラフファイルのimageタグを取得 function getimg( $index_page = FALSE ) { return ( $this -> status ) ? img( $this -> url, $index_page ) : ''; } // 古い画像ファイル(ランダムなファイル名の画像ファイル)の削除 function gcfiles() { $file_arr = get_dir_file_info( $this -> base_path ); $now = time(); if ( is_array( $file_arr ) ) { $regexp = '#^' . $this -> random_file_prefix . "_.{{$this->random_file_name_length}}_\d+\..+$#u"; foreach( $file_arr as $k => $v ) { if ( preg_match( $regexp, basename( $v['name'] ) ) ) { // 古いファイルの削除 if ( ( ( int )$now - ( $v['date'] + ( int )$this -> old_file_del_span ) ) > 0 ) { @unlink( $v['server_path'] ); } } } } } } //endofclass /** * End of file graph.php */ /** * Location: ./application/libraries/graph.php */ ?>
設置方法
手順1上記のライブラリを、application/libraries/graph.phpとして設置する。
(エンコードはUTF-8。Linux環境以外は知らん。)
手順2
phplot.phpを、http://sourceforge.net/projects/phplot/ からダウンロードして、
解凍したファイルをapplication/libraries/phplot.php として設置する。(他のファイルも同様)
手順3
日本語を表示したいときは、
任意の日本語ttfフォント(デフォルトでは、sazanami-gothic.ttf)を、
system/fonts/sazanami-gothic.ttf として設置する。
(sazanami-gothic.ttf自体は、Fedora8の場合は、/usr/share/fonts/sazanami-fonts-gothic/sazanami-gothic.ttf
にあるのでコピーすればよい。他のディストリビューションでも似たような場所にある筈。)
以上
使い方ポイント
- $arr に渡したい配列データを(phplotが認識できる形式で)セットし、
- $paramsに、phplotのメソッド名をキー、引数をvalueとした 配列データをセット、
- $this -> load -> library( 'graph' );
- $this -> graph -> setdata( $arr, $params );で、データとパラメータをセット、
- $this -> graph -> draw();でグラフ画像生成、
- $data['graph_img1'] = $this -> graph -> getimg();で画像のimgタグ生成
という流れ。だいぶ簡単になった。
動作確認ソース
1)コントローラ:application/controllers/graphtest.php
適当なコントローラで、こんな感じにソースを書いてみる。
なおここでは、ランダムにデータを与えて、グラフを2種類作っている。
phplotで指定できるパラメータについては、phplotのマニュアルを参照のこと。
<?php if ( ! defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' ); class Graphtest extends Controller { // コンストラクタ function Graphtest() { parent :: Controller(); // urlヘルパ $this -> load -> helper( 'url' ); // フォームヘルパ $this -> load -> helper( 'form' ); // 文字列ヘルパ $this -> load -> helper( 'string' ); } // phplotのテスト、 // todo:phplot自身のパラメータが多すぎて把握しきれていない function index() { // グラフライブラリのロード $this -> load -> library( 'graph' ); //------------------------- // グラフ生成(1回目) // 渡すデータ、ここではランダムに作ってみる $arr = array( array( '1', random_string( 'numeric', 3 ), ), array( '2', random_string( 'numeric', 3 ), ), array( '3', random_string( 'numeric', 3 ), ), array( '4', random_string( 'numeric', 3 ), ), array( '5', random_string( 'numeric', 3 ), ), array( '6', random_string( 'numeric', 3 ), ), array( '7', random_string( 'numeric', 3 ), ), ); // 追加パラメータ、phplotのメソッド名をキーに、引数をvalueにセット $params = array( 'SetTitle' => 'アンケートその1', // タイトル 'SetLegend' => array( 'らぜる', 'あみ', 'こー', 'かなめ', 'あかり', 'しあ', 'ざんげ' ), // 凡例 'SetDataType' => 'text-data-single', 'SetPlotType' => 'pie', // チャートの種類 area bars linepoints lines pie points squared stackedbars thinbarline ); // データとパラメータのセット $this -> graph -> setdata( $arr, $params ); // グラフ生成 $this -> graph -> draw(); //生成したグラフのIMGタグを取得 $data['graph_img1'] = $this -> graph -> getimg(); //生成したグラフのURLを取得 $data['graph_url1'] = $this -> graph -> geturl(); //------------------------- // グラフ生成(2回目) // initで初期化する $this -> graph -> init(array('width'=>500,'height'=>400)); // 渡すデータ、ここではランダムに作ってみる $arr = array( array( '2005年', random_string( 'numeric', 3 ), random_string( 'numeric', 3 ), random_string( 'numeric', 3 ) , random_string( 'numeric', 3 ) ), array( '2006年', random_string( 'numeric', 3 ), random_string( 'numeric', 3 ), random_string( 'numeric', 3 ) , random_string( 'numeric', 3 ) ), array( '2007年', random_string( 'numeric', 3 ), random_string( 'numeric', 3 ), random_string( 'numeric', 3 ) , random_string( 'numeric', 3 ) ), array( '2008年', random_string( 'numeric', 3 ), random_string( 'numeric', 3 ), random_string( 'numeric', 3 ) , random_string( 'numeric', 3 ) ), array( '2009年', random_string( 'numeric', 3 ), random_string( 'numeric', 3 ), random_string( 'numeric', 3 ) , random_string( 'numeric', 3 ) ), array( '2010年', random_string( 'numeric', 3 ), random_string( 'numeric', 3 ), random_string( 'numeric', 3 ) , random_string( 'numeric', 3 ) ), ); // 追加パラメータ、phplotのメソッド名をキーに、引数をvalueにセット $params = array( 'SetTitle' => 'アンケートその2', // タイトル 'SetLegend' => array( 'なかすぎ', 'いんでっくす', 'いんく', 'あむ' ), // 凡例 'SetPlotType' => 'stackedbars', // チャートの種類 area bars linepoints lines pie points squared stackedbars thinbarline ); // データとパラメータのセット $this -> graph -> setdata( $arr, $params ); //メソッドを直接呼んでみる $this -> graph ->obj-> SetBackgroundColor( '#f0f000' ); // グラフ生成 $this -> graph -> draw(); //生成したグラフのIMGタグを取得 $data['graph_img2'] = $this -> graph -> getimg(); //生成したグラフのURLを取得 $data['graph_url2'] = $this -> graph -> geturl(); $data['title'] = 'PHPLOTのライブラリ化テスト'; // ビューの生成 $this -> load -> view( 'graphtest_index', $data ); //$tpl["main_content"] = $this -> load -> view( 'graphtest_index', $data , true ); // 大枠のテンプレートに、タスクリストのビューをはめ込む //$this -> load -> view( 'base_view', $tpl ); } } //Endofclass /** * End of file graphtest.php */ /** * Location: ./application/controllers/graphtest.php */ ?>
2)ビュー:application/views/graphtest_index.php
こんな感じ
<h2><?= $title ?></h2> <h3><?= $graph_url1 ?></h3> <?= $graph_img1 ?> <hr> <h3><?= $graph_url2 ?></h3> <?= $graph_img2 ?>
疲れたので今日はここまで。
気が向いたら続きを書く。(明日じゃないかも)
そろそろ書くネタが少なくなってきたよん。複雑なネタはちょっと書きにくいし。更新ペースは落ちるかも。