-
今回はPHPのプログラムでは必ず使用するであろうデータ形式である 配列(array) について説明したいと思います。
配列(array) とは1個の変数の中に キー とそれに対応する 値 の組み合わせを複数持っているデータ構造です(リスト構造)。
この 値 の中に各種のデータ型を格納できます。別の配列を格納することで配列の入れ子ができます。
そもそも 配列(array) は何に使うのでしょうか?
配列の中に入れるデータはそれらが関連したデータで、ひとかたまりとして処理できるものです。
例えば以下の様な用途で使ってきました。- 固定的なオプションデータとして配列で持った方が良いデータ(例:一週間の"月"、"火"、"水"...の文字列の配列)
- 連続した数値データを持つ配列データ(数値データの配列から平均、標準偏差などの計算...)
- HTML出力用のSELECTタグ用のVALUE値と表示値の配列データ
- HTML出力用のOPTIONタグ用のVALUE値と表示値の配列データ
- $_POST、$_GET の値を格納するための配列
- データベースのテーブルから取得する一覧データのための配列
- CSVファイル、Excelファイルの読込結果のための配列
- 等々...(拾い上げると各種あります)
プログラムで処理するために繰り返し処理に向いているデータを配列として格納し、 各種の処理を行うことが配列を使う理由になります。
通常プログラム言語の「配列」は キー(添字) が数値(インデックス)である「添字配列」と、キー(添字) を文字列とする「連想配列」の2種類があります。
PHP では「添字配列」と「連想配列」の間に違いはなく、配列型は 1 つだけで、 同じ配列で整数のインデックスと文字列のインデックスを同時に使えます。
これは「添字配列」として使っていた配列が、組み方によっては「連想配列」が混在する様なことにもなりますので、注意が必要です。
インデックスを数値のみとして扱えば「添字配列」として処理でき、インデックスを文字列(数値も含む)で処理すれば「連想配列」として 処理できると考えられます。 (PHPの内部ではインデックスと値の組み合わせの「連想配列」として処理される)
【配列の構文:array()で指定】 $var = array( key1 => value1, key2 => value2, key3 => value3, ... ); ・$var :配列を格納する変数。 ・keyX :キー値(数値でも文字列でもOK) ・valueX:要素値(各種のデータで配列もOK)
それでは「添字配列」と「連想配列」の宣言例から使い方の説明を行います。- 添字配列 の宣言例
- 添字配列 の使い方の例
- 添字配列 の使い方の例その2(foreach文)
- 添字配列 の使い方の例その3(foreach文の注意)
- 添字配列 の使い方の例その4(角括弧構文で作成・修正)
- 連想配列 の宣言例
- 連想配列 の使い方の例その1(foreach文)
- 連想配列 の使い方の例その2(foreach文の注意)
- 連想配列 の使い方の例その3(角括弧構文で作成・修正)
■添字配列 の宣言例
「添字配列」として宣言するには array() の中でキー値の指定を省いて、要素値のみ連続して記述します。
以下のソースでは要素が数値のみの配列、要素が文字列のみの配列、要素が数値,文字列が混在の配列を定義しています。
それぞれを宣言した変数の内容を表示するために var_dump() 関数で処理します。 尚、 var_dump() 出力の前後を <pre> タグで囲むことで、 <br> タグ無しで改行出力をブラウザで改行した様にみられます。<?php // 要素が数値のみの配列 $arr1 = array(10, 20, 30); // 要素が文字列のみの配列 $arr2 = array("10", "20", "30"); // 要素が数値,文字列が混在の配列 $arr3 = array("10", 20, "30"); echo "<pre>"; var_dump($arr1); var_dump($arr2); var_dump($arr3); echo "</pre>"; ?>これを実行するとブラウザに以下の様に表示されます。
array(3) { [0]=> int(10) [1]=> int(20) [2]=> int(30) } array(3) { [0]=> string(2) "10" [1]=> string(2) "20" [2]=> string(2) "30" } array(3) { [0]=> string(2) "10" [1]=> int(20) [2]=> string(2) "30" }【var_dump の配列の出力形式】 array(n) { [i]=> int(d) ... [j]=> string(c) "contents" ... } ・array(n) :arrayで配列を示す(n:配列の要素数) ・[i], [j] :キー値(指標) ・int(d) :数値データ (d:要素値) ・string(c) :文字列データ(c:文字列数) ・"contents":文字列の値
■添字配列 の使い方の例
以下の例はよくある配列の反復処理です。 配列の指標を使って「0」から配列の最後の指標までをループで配列の内容を表示処理しています。
この例は必ず指標は「0」から始まり、指標の最後は「配列の要素数-1」であるのが前提です。
(尚、「配列の要素数」を取得するために count() 関数を使用します。)
しかし、この前提が違っているとプログラム実行でエラーが発生しますので、後からこれを回避する方法を記します。<?php // 要素が数値のみの配列 $arr1 = array(10, 20, 30); // 指標を使って「0」から「配列の大きさ-1」までを反復処理 for($i = 0; $i < count($arr1); $i++) { echo "\$arr1[".$i."]=".$arr1[$i]."<br />\n"; } ?>これを実行するとブラウザに以下の様に表示されます。
$arr1[0]=10 $arr1[1]=20 $arr1[2]=30
■添字配列 の使い方の例その2(foreach文)
配列を反復処理するため前述の for文 とは別の foreach文 があります。構文は以下の通りです。
【foreach文の構文】 foreach (array_expression as $value) 文; foreach (array_expression as $key => $value) 文; ・array_expression:配列(指定された配列の反復処理を行う) ・$value :配列の要素 ・$key :指標(キー値)
array_expression で指定した配列に 関して反復処理を行います。 配列に格納されている要素の値を先頭から $value に代入し、 配列の中身を指し示すポインタを先頭に設定し $value に代入します。この時ポインタが次の要素を示す様に一つ進められます。 これを順次処理することで、配列の要素を順次取得できます。
尚、2番目の形式は、さらに各反復で現在の要素のキーを変数 $key に代入します。<?php // 要素が数値のみの配列 $arr1 = array(10, 20, 30); // 配列の内容を順次取得する「foreach」を使って反復処理 foreach($arr1 as $i => $value) { echo "\$arr1[".$i."]=".$value."<br />\n"; } ?>これを実行するとブラウザに上記の様に表示されます。(ここでは表示割愛)
尚、指標の取得が必要無ければ「$i =>」の部分を記述しなくてもOKです。<?php // 要素が数値のみの配列 $arr1 = array(10, 20, 30); // 「foreach」で指標の取得無し foreach($arr1 as $value) { echo "DATA=".$value."<br />\n"; } ?>■添字配列 の使い方の例その3(foreach文の注意)
配列を反復処理で要素を変更したい場合には $value の前に &(アンドマーク) を記述します。
&(アンドマーク) を付加することで反復処理での $value には配列の要素のリファレンス(参照:C言語のポインタの様なもの)が渡されます。<?php // 要素が数値のみの配列 $arr1 = array(10, 20, 30); // 配列の内容を順次取得する「foreach」を使ってループ処理 foreach($arr1 as &$value) { $value = $value * 10; // 要素を10倍する } unset($value); // 最後の要素への参照を解除します echo "<pre>"; print_r($arr1); echo "</pre>"; ?>これを実行するとブラウザに以下の様に表示されます。配列の各要素が10倍されていることが分かります。
Array ( [0] => 100 [1] => 200 [2] => 300 )ここで注意が必要なのは unset($value); です。 ここで変数 $value を破棄しないと $value には $arr1 の3番目の要素 $arr1[2] への参照が残ったままで、 不用意に $value に値を設定したりすると $arr1[2] が書き変ってしまいます。
■添字配列 の使い方の例その4(角括弧構文で作成・修正)
配列に対して角括弧構文でキーを指定し要素値を設定することで、配列の更新をすることが出来ます。
キーを指定が無い場合は、指標の中で最大値の次の値を指標として値が追加されます。<?php // 要素が数値のみの配列 $arr1 = array(10, 20, 30); // 角括弧構文でキーを指定し配列の要素を更新 $arr1[2] = 100; // 角括弧構文でキー指定無しで配列の要素を追加 $arr1[] = 200; echo "<pre>"; print_r($arr1); echo "</pre>"; ?>
これを実行するとブラウザに以下の様に表示されます。
配列の3番目の要素が「100」に更新され、4番目の要素として「200」が追加されます。Array ( [0] => 10 [1] => 20 [2] => 100 [3] => 200 )尚、以下の様に角括弧構文のみで配列を作成することが出来ます。
最初の $arr1[] = で $arr1 が存在していなければ配列として生成され、キー「0」の要素に値が設定されます。
array() 宣言をコメントで消していますが、これがあれば明示的に配列だと宣言できます。(少し冗長なのですが、私はこちらを推奨します。)<?php // 配列宣言 //$arr1 = array(); // 角括弧構文でキー指定無しで配列の要素を追加 $arr1[] = 10; $arr1[] = 20; $arr1[] = 30; echo "<pre>"; print_r($arr1); echo "</pre>"; ?>
■連想配列 の宣言例
今までの 添字配列 ではキー値としていわゆるインデックスとしての数値でしたが、連想配列 としてはキー値に文字列等を用います。
宣言の最初はキーを文字列で行っていますが、最後は数値で宣言しています。<?php // 配列宣言 $arr1 = array( "KEY1" => "11111", "KEY2" => "222", "KEY3" => "3333", "KEY4" => "44444", 0 => 100, // キー:数値!! "KEY5" => "555", ); echo "<pre>"; print_r($arr1); echo "</pre>"; ?>これを実行するとブラウザに以下の様に表示されます。キーが文字列であっても数値であっても、ちゃんと配列が生成されています。 宣言の中で最後の行でカンマを記述していますが、カンマ無しでもOKです。
Array ( [KEY1] => 11111 [KEY2] => 222 [KEY3] => 3333 [KEY4] => 44444 [0] => 100 [KEY5] => 555 )■連想配列 の使い方の例その1(foreach文)
添字配列 の時の様に foreach文 を使った例を示します。
<?php // 配列宣言 $arr1 = array( "KEY1" => "11111", "KEY2" => "222", "KEY3" => "3333", "KEY4" => "44444", 0 => 100, "KEY5" => "555", ); // 配列の内容を順次取得する「foreach」を使ってループ処理 foreach($arr1 as $key => $value) { echo "\$arr1[".$key."]=".$value."<br />\n"; } ?>これを実行するとブラウザに以下の様に表示されます。
$arr1[KEY1]=11111 $arr1[KEY2]=222 $arr1[KEY3]=3333 $arr1[KEY4]=44444 $arr1[0]=100 $arr1[KEY5]=555
■連想配列 の使い方の例その2(foreach文の注意)
添字配列のところで説明しましたが、連想配列でも配列を反復処理で要素を変更したい場合には $value の前に &(アンドマーク) を記述します。 (PHPの配列は連想配列として考えればどちらもおなじことですが)
&(アンドマーク) を付加することで反復処理での $value には配列の要素のリファレンス(参照:C言語のポインタの様なもの)が渡されます。<?php // 要素が数値のみの配列 $arr1 = array( "KEY1" => "11111", "KEY2" => "222", "KEY3" => "3333", "KEY4" => "44444", 0 => 100, "KEY5" => "555", ); // 配列の内容を順次取得する「foreach」を使ってループ処理 foreach($arr1 as &$value) { $value = $value . "AA"; // 要素に文字列 "AA" 付加 } unset($value); // 最後の要素への参照を解除します echo "<pre>"; print_r($arr1); echo "</pre>"; ?>これを実行するとブラウザに以下の様に表示されます。配列の各要素文字列 "AA" 付加されていることが分かります。
指標「0」の要素は数値でしたが、文字列との連結では数値が文字列 "100" に強制的に変換されて "AA" が付加されることになります。
array(6) { ["KEY1"]=> string(7) "11111AA" ["KEY2"]=> string(5) "222AA" ["KEY3"]=> string(6) "3333AA" ["KEY4"]=> string(7) "44444AA" [0]=> string(5) "100AA" ["KEY5"]=> string(5) "555AA" }ここで注意が必要なのは unset($value); です。 ここで変数 $value を破棄しないと $value には $arr1 の3番目の要素 $arr1["KEY5"] への参照が残ったままで、 不用意に $value に値を設定したりすると $arr1["KEY5"] が書き変ってしまいます。
■連想配列 の使い方の例その3(角括弧構文で作成・修正)
配列に対して角括弧構文でキーを指定し要素値を設定することで、配列の更新をすることが出来ます。
キーを指定が無い場合は、指標の中で最大値の次の値を指標として値が追加されます。
<?php // 配列宣言 $arr1 = array(); // 角括弧構文でキー指定で配列の要素を追加 $arr1["KEY1"] = "11111"; $arr1["KEY2"] = "222"; $arr1["KEY3"] = "3333"; $arr1["KEY4"] = "44444"; $arr1[0 ] = 100; $arr1["KEY5"] = "555"; // 配列内部表示 echo "<pre>最初の表示<br>"; var_dump($arr1); echo "</pre>"; // キー指定無しで追加 $arr1[] = 200; // 配列内部表示 echo "<pre>追加後の表示<br>"; var_dump($arr1); echo "</pre>"; ?>
これを実行するとブラウザに以下の様に表示されます。
キー指定無しでの配列への追加は、キーの中で数値の最大値に+1されたものがキーとなりその要素に値が設定されます。 (数値キーがなければキーは「0」となります。)
最初の表示 array(6) { ["KEY1"]=> string(5) "11111" ["KEY2"]=> string(3) "222" ["KEY3"]=> string(4) "3333" ["KEY4"]=> string(5) "44444" [0]=> int(100) ["KEY5"]=> string(3) "555" } 追加後の表示 array(7) { ["KEY1"]=> string(5) "11111" ["KEY2"]=> string(3) "222" ["KEY3"]=> string(4) "3333" ["KEY4"]=> string(5) "44444" [0]=> int(100) ["KEY5"]=> string(3) "555" [1]=> int(200) }
PR -
データを表形式で表示する為に table タグを用いますが、以下のページでは table の外側からデータを取得する方法を説明しました。
⇒JavaScript jQueryで table の操作する方法その1・データ取得
上記の table に thead tbody のタグを記述して、 tr オブジェクトの何番目かを eq() メソッドの使って該当行の tr オブジェクトを取得し、その内部の td オブジェクトに アクセスし内部のデータを取得ていました。
今回の取得方法は、各 tr の中に取得のアクションを起すボタンを置いて、該当行の中身を取得し表示します。
以下のソースを見て下さい。 tbody の中の tr の各 td にクラスを宣言しています。 さらにメモ欄の td には内部に input タグを設置しさらにクラスを宣言しています。
「class="btnGet"」のボタンクリックイベントの関数の中で parent() メソッドを2回使って tr タグのオブジェクトを取得しています。 tr タグのオブジェクトの find() メソッドを使って td および input タグのオブジェクトを取得します。 取得したオブジェクトの text() および val() メソッドで内部の値を取得します。
尚、find()されたオブジェクトの存在をチェックする為に length プロパティが「0」以外かを判定しています。 find() が返すオブジェクトが存在すれば length プロパティが「1」になるので、 if の判定は true となります。
【今回使用したメソッドの説明】 ・find():指定要素が持つ全ての子要素および孫要素から、指定条件式に合致するものを選択します。 ・text():指定した要素が持つテキストノードを結合したものを返します。 ・val() :要素のvalue属性を返します。
<html> <head> <meta charset="utf-8"> <title>test jQuery get-5</title> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> </head> <body> <table border="1"> <thead> <tr> <th>品名</th> <th>数量</th> <th>単価</th> <th>金額</th> <th>メモ</th> <th>取得</th> </tr> </thead> <tbody> <tr> <td class="Name">りんご</td> <td class="Number">2</td> <td class="Price">100</td> <td class="Amount">200</td> <td><input class="Memo" value="りんごです" /></td> <td><button class="btnGet">取得</button></td> </tr> <tr> <td class="Name">みかん</td> <td class="Number">5</td> <td class="Price">50</td> <td class="Amount">250</td> <td><input class="Memo" value="ああああ" /></td> <td><button class="btnGet">取得</button></td> </tr> <tr> <td class="Name">いちご</td> <td class="Number">3</td> <td class="Price">250</td> <td class="Amount">750</td> <td><input class="Memo" value="AAAA" /></td> <td><button class="btnGet">取得</button></td> </tr> </tbody> </table> <script> $(function () { //<button class="btnGet">のクリックイベントの関数を宣言 $(".btnGet").click(function(){ //クリック行のjqueryオブジェクト取得 var objTr = $(this).parent().parent(); //表示用文字列クリア var strMsg = ""; //のjqueryオブジェクト取得 obj = objTr.find(".Name"); if( obj.length ) { strMsg += "Name:" + obj.text() + "\n"; } //のjqueryオブジェクト取得 obj = objTr.find(".Number"); if( obj.length ) { strMsg += "Number:" + obj.text() + "\n"; } //のjqueryオブジェクト取得 obj = objTr.find(".Price"); if( obj.length ) { strMsg += "Price:" + obj.text() + "\n"; } //のjqueryオブジェクト取得 obj = objTr.find(".Amount"); if( obj.length ) { strMsg += "Amount:" + obj.text() + "\n"; } //のjqueryオブジェクト取得 obj = objTr.find(".Memo"); if( obj.length ) { strMsg += "Memo:" + obj.val() + "\n"; } //明細行の内容表示 alert(strMsg); }); }); </script> </body>
今回の方法は、各明細行に対して個別に行う処理が異なる場合に有効になると思います。
例えば、各明細行の修正画面を別に作成し、その画面に飛ばすためのアクションとしてのボタンや、 個別に削除や更新を行う場合に対応する PHP プログラムに遷移させたりできると思います。
-
今回は PhpSpreadsheet\Chart で「Bar Chart:棒グラフ」が作成されているエクセルファイルを読み込み、 そのチャートが参照している系列データ部分を別のデータで書き変えを行う方法を説明します。
おおまかな手順は以下の様になります。- PhpSpreadsheet\IOFactory クラスの createReader メソッドで読込みオブジェクトを生成し、エクセルファイルの読込。 (この時 setIncludeCharts(TRUE) メソッドでチャートの存在を指定する)
- ワークシートの fromArray メソッドで系列データを設定。
- PhpSpreadsheet\IOFactory クラスの createWriter メソッドで書込みオブジェクトを生成し、エクセルファイルの書込。 (この時 setIncludeCharts(TRUE) メソッドでチャートの存在を指定する)
以下の記事のエクセルファイルを元にします。
⇒PHP PhpSpreadsheet\Chart ワークシート上にチャート(Bar Chart:棒グラフ)を作成する方法について
元となるエクセルファイル[test-g-2-1.xlsx]は以下の様になっています。■ワークシートにチャートが存在するエクセルファイル(テンプレート)の系列データ部分を変更し別のファイルとして登録
<?php // ライブラリ読込 require '../vendor/autoload.php'; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\IOFactory; // エクセルファイル読込オブジェクト $objReader = IOFactory::createReader('Xlsx'); $objReader->setIncludeCharts(TRUE); // PHPExcelオブジェクト取得 $objSpreadsheet = $objReader->load("test-g-2-1.xlsx"); // ワークシートオブジェクト取得 $objWorksheet = $objSpreadsheet->getActiveSheet(); // チャート用テストデータ上書 $objWorksheet->fromArray( array( array( 22, 38, 19), array( 25, 49, 20), array( 31, 33, 25), array( 28, 44, 42), array( 40, 31, 13), ), NULL, 'B2' ); // エクセルファイル書込オブジェクト $objWriter = IOFactory::createWriter($objSpreadsheet, 'Xlsx'); $objWriter->setIncludeCharts(TRUE); // エクセルファイル書込 $objWriter->save('test-g-7-1.xlsx'); exit(); ?>出力されたエクセルファイル[test-g-7-1.xlsx]を見てみると以下の様になります。
チャートが参照している系列データを変更すれば、表示されるチャートのグラフは違ったものになります。
このことを利用すれば、テンプレートのエクセルファイルとしてチャート含んだものを登録しておき、 データ部だけを変えるだけで異なるエクセルファイルを出力することができます。
-
今回は先ず2個のチャート上にそれぞれ「Pie Chart:円グラフ」「Donut Chart:ドーナツグラフ」のグラフを作成し、 その後で「Radar Chart:レーダーチャート」作成します。
■2個のチャート上にそれぞれ「Pie Chart:円グラフ」「Donut Chart:ドーナツグラフ」のグラフを作成
「Pie Chart:円グラフ」「Donut Chart:ドーナツグラフ」は共に系列データ等の指定方法は同じで、表示される図形が円かドーナツかの違いがあるだけです。
系列データとして設定できるのは1種類のデータの系列のみになります。 以下のテストデータを例にとると、縦方向には「商品1」の「2016~2020の1列のデータ」が対象となります。 同一チャート上に「商品1」及び「商品2」のグラフを「棒グラフ」等の様に同時には表示できません。// チャート用テストデータ生成 $objWorksheet->fromArray( array( array('売上', '商品1', '商品2', '商品3'), array( 2016, 12, 18, 15), array( 2017, 15, 19, 10), array( 2018, 21, 23, 20), array( 2019, 18, 14, 12), array( 2020, 20, 21, 23), ) );以前は PhpSpreadsheet\Chart\PlotArea クラス生成で先頭の引数には「NULL」を指定していましたが、 円グラフの各要素の値を表示するために PhpSpreadsheet\Chart\Layout クラスのオブジェクトを生成し、 指定します。
PhpSpreadsheet\Chart\Layout クラスの setShowVal メソッドで値表示を指定し setShowPercent メソッドでパーセント表記の指定をします。 (結果、値とパーセントの二つとも表示されます)
実際のソースは以下の様になります。
(「Pie Chart:円グラフ」は「商品1」を「Donut Chart:ドーナツグラフ」は「商品2」を対象とします。)<?php // ライブラリ読込 require '../vendor/autoload.php'; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; use PhpOffice\PhpSpreadsheet\Chart\Layout; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\Chart\Legend; use PhpOffice\PhpSpreadsheet\IOFactory; // Spreadsheetオブジェクト生成 $objSpreadsheet = new Spreadsheet(); // ワークシートオブジェクト取得 $objWorksheet = $objSpreadsheet->getActiveSheet(); // チャート用テストデータ生成 $objWorksheet->fromArray( array( array('売上', '商品1', '商品2', '商品3'), array( 2016, 12, 18, 15), array( 2017, 15, 19, 10), array( 2018, 21, 23, 20), array( 2019, 18, 14, 12), array( 2020, 20, 21, 23), ) ); //===================== // Pie Chart //===================== // 系列ラベルの指定 $arrDataSeriesLabels1 = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', NULL, 1), //商品1 ); // X軸ラベルの指定 $arrCategorysDataSeries1 = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$6', NULL, 5), //2016 to 2020 ); // 描画データの指定 $arrDataSeriesValues1 = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$6', NULL, 5), //商品1 ); // チャート・データシリーズの生成 $objSeries1 = new DataSeries( DataSeries::TYPE_PIECHART, // plotType NULL, // plotGrouping (円グラフはグループ指定必要無し) range(0, count($arrDataSeriesValues1) - 1), // plotOrder $arrDataSeriesLabels1, // plotLabel $arrCategorysDataSeries1, // plotCategory $arrDataSeriesValues1 // plotValues ); // 円グラフ用のレイアウト設定 $objLayout1 = new Layout(); $objLayout1->setShowVal(TRUE); $objLayout1->setShowPercent(TRUE); // プロットエリアにチャート・データシリーズに設定 $objPlotArea1 = new PlotArea($objLayout1, array($objSeries1)); // レジェンド生成(各折れ線の説明を行う) $objLegend1 = new Legend(Legend::POSITION_TOPRIGHT, NULL, false); // チャート・タイトル生成 $objTitle1 = new Title('Pie Chart:商品1'); // チャート生成 $objChart1 = new Chart( 'chart1', // name $objTitle1, // title $objLegend1, // legend $objPlotArea1, // plotArea TRUE, // plotVisibleOnly 0, // displayBlanksAs NULL, // xAxisLabel NULL // yAxisLabel ); // ワークシート内のチャート位置設定 $objChart1->setTopLeftPosition('A8'); // 左上 $objChart1->setBottomRightPosition('G20'); // 右下 // ワークシートにチャート追加 $objWorksheet->addChart($objChart1); //===================== // Donut Chart //===================== // 系列ラベルの指定 $arrDataSeriesLabels2 = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$2', NULL, 1), //商品2 ); // X軸ラベルの指定 $arrCategorysDataSeries2 = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$6', NULL, 5), //2016 to 2020 ); // 描画データの指定 $arrDataSeriesValues2 = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$6', NULL, 5), //商品2 ); // チャート・データシリーズの生成 $objSeries2 = new DataSeries( DataSeries::TYPE_DONUTCHART, // plotType NULL, // plotGrouping (ドーナツグラフはグループ指定必要無し) range(0, count($arrDataSeriesValues2) - 1), // plotOrder $arrDataSeriesLabels2, // plotLabel $arrCategorysDataSeries2, // plotCategory $arrDataSeriesValues2 // plotValues ); // 円グラフ用のレイアウト設定 $objLayout2 = new Layout(); $objLayout2->setShowVal(TRUE); $objLayout2->setShowPercent(TRUE); // プロットエリアにチャート・データシリーズに設定 $objPlotArea2 = new PlotArea($objLayout2, array($objSeries2)); // レジェンド生成(各折れ線の説明を行う) $objLegend2 = new Legend(Legend::POSITION_TOPRIGHT, NULL, false); // チャート・タイトル生成 $objTitle2 = new Title('Donut Chart:商品2'); // チャート生成 $objChart2 = new Chart( 'chart2', // name $objTitle2, // title $objLegend2, // legend $objPlotArea2, // plotArea TRUE, // plotVisibleOnly 0, // displayBlanksAs NULL, // xAxisLabel NULL // yAxisLabel ); // ワークシート内のチャート位置設定 $objChart2->setTopLeftPosition('H8'); // 左上 $objChart2->setBottomRightPosition('N20'); // 右下 // ワークシートにチャート追加 $objWorksheet->addChart($objChart2); // [test-g-6-1.xlsx]:Excel2007形式で保存する $objWriter = IOFactory::createWriter($objSpreadsheet, 'Xlsx'); $objWriter->setIncludeCharts(TRUE); $objWriter->save('test-g-6-1.xlsx'); exit(); ?>出力されたエクセルファイルを見てみると以下の様になります。
■「Radar Chart:レーダーチャート」のグラフを作成
「Radar Chart:レーダーチャート」のグラフを作成してみます。
「Radar Chart:レーダーチャート」とは折れ線グラフの線を環状に繋げたイメージです。
「系列ラベル」「X軸ラベル」「系列(描画)データ」は各参照系列ごと対応するものを同じ個数設定します。
実際のソースは以下の様になります。出力されたエクセルファイルを見てみると以下の様になります。<?php // ライブラリ読込 require '../vendor/autoload.php'; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; use PhpOffice\PhpSpreadsheet\Chart\Layout; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\Chart\Legend; use PhpOffice\PhpSpreadsheet\IOFactory; // Spreadsheetオブジェクト生成 $objSpreadsheet = new Spreadsheet(); // ワークシートオブジェクト取得 $objWorksheet = $objSpreadsheet->getActiveSheet(); // チャート用テストデータ生成 $objWorksheet->fromArray( array( array('売上', '商品1', '商品2', '商品3'), array( 2016, 12, 18, 15), array( 2017, 15, 19, 10), array( 2018, 21, 23, 20), array( 2019, 18, 14, 12), array( 2020, 20, 21, 23), ) ); // 系列ラベルの指定 $arrDataSeriesLabels = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', NULL, 1), //商品1 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', NULL, 1), //商品2 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', NULL, 1), //商品3 ); // X軸ラベルの指定 $arrCategorysDataSeries = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$6', NULL, 5), //2016 to 2020 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$6', NULL, 5), //2016 to 2020 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$6', NULL, 5), //2016 to 2020 ); // 描画データの指定 $arrDataSeriesValues = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$6', NULL, 5), //商品1 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$6', NULL, 5), //商品2 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$6', NULL, 5), //商品3 ); // チャート・データシリーズの生成 $objSeries = new DataSeries( DataSeries::TYPE_RADARCHART, // plotType NULL, // plotGrouping (レーダーチャートはグループ指定必要無し) range(0, count($arrDataSeriesValues) - 1), // plotOrder $arrDataSeriesLabels, // plotLabel $arrCategorysDataSeries, // plotCategory $arrDataSeriesValues, // plotValues NULL, // plotDirection NULL, // smooth line DataSeries::STYLE_MARKER // plotStyle ); // プロットエリアにチャート・データシリーズに設定 $objPlotArea = new PlotArea(NULL, array($objSeries)); // レジェンド生成 $objLegend = new Legend(Legend::POSITION_TOPRIGHT, NULL, false); // チャート・タイトル生成 $objTitle = new Title('Radar Chart'); // チャート生成 $objChart = new Chart( 'chart1', // name $objTitle, // title $objLegend, // legend $objPlotArea, // plotArea TRUE, // plotVisibleOnly 0, // displayBlanksAs NULL, // xAxisLabel NULL // yAxisLabel ); // ワークシート内のチャート位置設定 $objChart->setTopLeftPosition('A8'); // 左上 $objChart->setBottomRightPosition('F20'); // 右下 // ワークシートにチャート追加 $objWorksheet->addChart($objChart); // [test-g-6-2.xlsx]:Excel2007形式で保存する $objWriter = IOFactory::createWriter($objSpreadsheet, 'Xlsx'); $objWriter->setIncludeCharts(TRUE); $objWriter->save('test-g-6-2.xlsx'); exit(); ?>
-
今回は4個のチャート上にそれぞれ「Bar Chart:棒グラフ」「Bar Chart:棒グラフ(積み上げ)」「Line Chart:線グラフ」「Area Chart:面グラフ」のグラフを持つ様にしたいと思います。
- 4個のチャート上にそれぞれ「Bar Chart:棒グラフ」「Bar Chart:棒グラフ(積み上げ)」「Line Chart:線グラフ」「Area Chart:面グラフ」持つ様に作成
- チャートの表示位置でのエラー発生!!
■4個のチャート上にそれぞれ「Bar Chart:棒グラフ」「Bar Chart:棒グラフ(積み上げ)」「Line Chart:線グラフ」「Area Chart:面グラフ」持つ様に作成
グラフの対象データとなるものは全て同じものを使うため PhpSpreadsheet\DataSeries クラスで生成する 「系列ラベル」「X軸ラベル」「描画データ」は最初に生成し、共通で参照します。
// チャート用テストデータ生成 $objWorksheet->fromArray( array( array('売上', '商品1', '商品2', '商品3'), array( 2016, 12, 18, 15), array( 2017, 15, 19, 10), array( 2018, 21, 23, 20), array( 2019, 18, 14, 12), array( 2020, 20, 21, 23), ) ); // 系列ラベルの指定 $arrDataSeriesLabels = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', NULL, 1), //商品1 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', NULL, 1), //商品2 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', NULL, 1), //商品3 ); // X軸ラベルの指定 $arrCategorysDataSeries = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$6', NULL, 5), //2016 to 2020 ); // 描画データの指定 $arrDataSeriesValues = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$6', NULL, 5), //商品1 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$6', NULL, 5), //商品2 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$6', NULL, 5), //商品3 );後は個別にチャートを生成するために以下のオブジェクトを個別に生成します。
- チャート・データシリーズの生成。
- レジェンド生成。(各折れ線の説明を行う)
- チャート・タイトル生成。
- ワークシートにチャート追加。
実際のソースは以下の様になります。
<?php // ライブラリ読込 require '../vendor/autoload.php'; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\Chart\Legend; use PhpOffice\PhpSpreadsheet\IOFactory; // Spreadsheetオブジェクト生成 $objSpreadsheet = new Spreadsheet(); // ワークシートオブジェクト取得 $objWorksheet = $objSpreadsheet->getActiveSheet(); // チャート用テストデータ生成 $objWorksheet->fromArray( array( array('売上', '商品1', '商品2', '商品3'), array( 2016, 12, 18, 15), array( 2017, 15, 19, 10), array( 2018, 21, 23, 20), array( 2019, 18, 14, 12), array( 2020, 20, 21, 23), ) ); // 系列ラベルの指定 $arrDataSeriesLabels = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', NULL, 1), //商品1 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', NULL, 1), //商品2 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', NULL, 1), //商品3 ); // X軸ラベルの指定 $arrCategorysDataSeries = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$6', NULL, 5), //2016 to 2020 ); // 描画データの指定 $arrDataSeriesValues = array( new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$6', NULL, 5), //商品1 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$6', NULL, 5), //商品2 new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$6', NULL, 5), //商品3 ); //===================== // Bar Chart //===================== // チャート・データシリーズの生成 $objSeries1 = new DataSeries( DataSeries::TYPE_BARCHART, // plotType DataSeries::GROUPING_STANDARD, // plotGrouping range(0, count($arrDataSeriesValues) - 1), // plotOrder $arrDataSeriesLabels, // plotLabel $arrCategorysDataSeries, // plotCategory $arrDataSeriesValues // plotValues ); // プロットエリアにチャート・データシリーズに設定 $objPlotArea1 = new PlotArea(NULL, array($objSeries1)); // レジェンド生成(各折れ線の説明を行う) $objLegend1 = new Legend(Legend::POSITION_TOPRIGHT, NULL, false); // チャート・タイトル生成 $objTitle1 = new Title('売上データ:Bar Chart'); // チャート生成 $objChart1 = new Chart( 'chart1', // name $objTitle1, // title $objLegend1, // legend $objPlotArea1, // plotArea TRUE, // plotVisibleOnly 0, // displayBlanksAs NULL, // xAxisLabel NULL // yAxisLabel ); // ワークシート内のチャート位置設定 $objChart1->setTopLeftPosition('A8'); // 左上 $objChart1->setBottomRightPosition('G20'); // 右下 // ワークシートにチャート追加 $objWorksheet->addChart($objChart1); //===================== // Bar Chart:STACKED //===================== // チャート・データシリーズの生成 $objSeries2 = new DataSeries( DataSeries::TYPE_BARCHART, // plotType DataSeries::GROUPING_PERCENT_STACKED, // plotGrouping range(0, count($arrDataSeriesValues) - 1), // plotOrder $arrDataSeriesLabels, // plotLabel $arrCategorysDataSeries, // plotCategory $arrDataSeriesValues // plotValues ); // プロットエリアにチャート・データシリーズに設定 $objPlotArea2 = new PlotArea(NULL, array($objSeries2)); // レジェンド生成(各折れ線の説明を行う) $objLegend2 = new Legend(Legend::POSITION_TOPRIGHT, NULL, false); // チャート・タイトル生成 $objTitle2 = new Title('売上データ:Bar Chart:STACKED'); // チャート生成 $objChart2 = new Chart( 'chart2', // name $objTitle2, // title $objLegend2, // legend $objPlotArea2, // plotArea TRUE, // plotVisibleOnly 0, // displayBlanksAs NULL, // xAxisLabel NULL // yAxisLabel ); // ワークシート内のチャート位置設定 $objChart2->setTopLeftPosition('H8'); // 左上 $objChart2->setBottomRightPosition('N20'); // 右下 // ワークシートにチャート追加 $objWorksheet->addChart($objChart2); //===================== // Line Chart //===================== // チャート・データシリーズの生成 $objSeries3 = new DataSeries( DataSeries::TYPE_LINECHART, // plotType DataSeries::GROUPING_STANDARD, // plotGrouping range(0, count($arrDataSeriesValues) - 1), // plotOrder $arrDataSeriesLabels, // plotLabel $arrCategorysDataSeries, // plotCategory $arrDataSeriesValues // plotValues ); // プロットエリアにチャート・データシリーズに設定 $objPlotArea3 = new PlotArea(NULL, array($objSeries3)); // レジェンド生成(各折れ線の説明を行う) $objLegend3 = new Legend(Legend::POSITION_TOPRIGHT, NULL, false); // チャート・タイトル生成 $objTitle3 = new Title('売上データ:Line Chart'); // チャート生成 $objChart3 = new Chart( 'chart3', // name $objTitle3, // title $objLegend3, // legend $objPlotArea3, // plotArea TRUE, // plotVisibleOnly 0, // displayBlanksAs NULL, // xAxisLabel NULL // yAxisLabel ); // ワークシート内のチャート位置設定 $objChart3->setTopLeftPosition('A21'); // 左上 $objChart3->setBottomRightPosition('G33'); // 右下 // ワークシートにチャート追加 $objWorksheet->addChart($objChart3); //===================== // Area Chart //===================== // チャート・データシリーズの生成 $objSeries4 = new DataSeries( DataSeries::TYPE_AREACHART, // plotType DataSeries::GROUPING_PERCENT_STACKED, // plotGrouping range(0, count($arrDataSeriesValues) - 1), // plotOrder $arrDataSeriesLabels, // plotLabel $arrCategorysDataSeries, // plotCategory $arrDataSeriesValues // plotValues ); // プロットエリアにチャート・データシリーズに設定 $objPlotArea4 = new PlotArea(NULL, array($objSeries4)); // レジェンド生成(各折れ線の説明を行う) $objLegend4 = new Legend(Legend::POSITION_TOPRIGHT, NULL, false); // チャート・タイトル生成 $objTitle4 = new Title('売上データ:Area Chart'); // チャート生成 $objChart4 = new Chart( 'chart4', // name $objTitle4, // title $objLegend4, // legend $objPlotArea4, // plotArea TRUE, // plotVisibleOnly 0, // displayBlanksAs NULL, // xAxisLabel NULL // yAxisLabel ); // ワークシート内のチャート位置設定 $objChart4->setTopLeftPosition('H21'); // 左上 $objChart4->setBottomRightPosition('N33'); // 右下 // ワークシートにチャート追加 $objWorksheet->addChart($objChart4); // [test-g-5-1.xlsx]:Excel2007形式で保存する $objWriter = IOFactory::createWriter($objSpreadsheet, 'Xlsx'); $objWriter->setIncludeCharts(TRUE); $objWriter->save('test-g-5-1.xlsx'); exit(); ?>出力されたエクセルファイルを見てみると以下の様になります。
(4個のチャート上に個別のタイプのグラフが生成されています。)■チャートの表示位置でのエラー発生!!
上記のソースを作成中に一部間違いをしまして、最後のグラフの出力位置を以下の様にしていました。
// ワークシート内のチャート位置設定 $objChart4->setTopLeftPosition('H21'); // 左上 $objChart4->setBottomRightPosition('G33'); // 右下 // ワークシートにチャート追加 $objWorksheet->addChart($objChart4);このまま気が付かずに実行し「test-g-5-1.xlsx」をエクセルで開いたのですが、以下の様なエラー表示がされました。
チャート位置で「左上」が 'H21' で「右下」が 'G33' というのは明らかに指定がおかしいので、 エクセルとしてもチャートの表示ができなかったのでしょう。
皆さんもチャートの位置指定にはご注意ください。