Google Chartsを利用してHPやブログにチャート(グラフ等)を描く方法
ブログなどのウェブ・ページに自分の意見や主張や考えを掲載するときにそれを裏付けるデータがあると説得力が増すかもしれない。そのデータをチャートとして描いて視覚化できれば尚更。
その場合、一般的なのはそれを専門にしている表計算アプリを使うこと。表計算ソフトウェアにはデータを各種チャートの形にして視覚化してくれる機能が大抵備わっている。LibreOfficeのCalcの場合、そのチャートをコピーしてInkscape上に貼り付けることができる。それをPNG形式の画像やSVG形式の画像として保存し、それをウェブ・ページに掲載する方法がある。
他の選択肢としては、HTML5 CanvasやJavaScriptのライブラリを使う手がある。データを視覚化してくれるJavaScriptのライブラリが最近では数え切れないくらい多くある。
今回はGoogle Chartsのライブラリを利用させていただいた。その手順についてこの投稿に書き留める。
2種類のチャートの完成図
同じデータ・セットで2種類のチャートを作ってみた。その完成図が次のとおり。
1つ目のチャートは日本のマクロ経済のインフレ率の時系列データを折線グラフにしたもの。
2つ目のチャートは同じ時系列データを縦の棒グラフにしたもの。棒グラフだと0に近い値が見えなくなってしまっているためか、そこにマウスのポインタを合わせても値を表示してくれるイベント処理が機能しない。
これらのチャートを描くためのコードをHTMLから順に説明する。
HTMLのコード
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Google Chartでチャートを描いてみた</title> <!-- loader.jsを読み込む --> <script src="https://www.gstatic.com/charts/loader.js"></script> </head> <body> <!-- --> <div id="chartA">Google Chartsが有効ではありません。</div> <div id="chartB">Google Chartsが有効ではありません。</div> </body> <script defer> <!-- ここにJavaScriptのソースコードを記述 --> </script> </html>
- チャートを埋め込むHTML文書を用意。
- div要素にid属性を与えてbody要素内のチャートを埋め込みたい場所に置く。
- loader.jsの場所をsrc属性に持つ1つ目のscript要素をhead要素内に置く。
- JavaScriptのコードをHTMLのソース内に埋め込むための2つ目のscript要素をhead要素内に置く。
JavaScriptのコードが最後に読み込まれることを期待してここでは2つ目のscript要素をbody要素の下に置くことにした。
script要素のtype属性はデフォルトで"text/javascript"なのでtype属性を省略した。
JavaScriptのコードをHTML文書の中に直接埋め込まずに別のファイルに分離してもオーケー。その場合にはscript要素にsrc属性を設けてその値としてJavaScriptのソースコードの場所とそのファイル名(拡張子は.js)を指定する必要がある。
チャートを貼り付ける場所はHTML文書のbody要素の中にdiv要素を用いて指定する。チャートの数だけ用意し、それぞれにid属性を割り振っておく。
今回は2つのチャートを描画するため、2つのdiv要素を記した。それぞれに異なるidを持つ。
JavaScriptのコード
ここで使用したJavaScriptのコードの内容は次のとおり。
<script defer> // 匿名関数でコード全体を袋とじ (function() { // データセットを連想配列として定義 const dataSet = [ {"年":"1960","インフレ率":3.57}, {"年":"1961","インフレ率":5.36}, {"年":"1962","インフレ率":6.83}, {"年":"1963","インフレ率":6.7}, {"年":"1964","インフレ率":3.8}, {"年":"1965","インフレ率":6.65}, {"年":"1966","インフレ率":5.04}, {"年":"1967","インフレ率":3.98}, {"年":"1968","インフレ率":5.33}, {"年":"1969","インフレ率":5.24}, {"年":"1970","インフレ率":6.92}, {"年":"1971","インフレ率":6.39}, {"年":"1972","インフレ率":4.84}, {"年":"1973","インフレ率":11.6}, {"年":"1974","インフレ率":23.22}, {"年":"1975","インフレ率":11.73}, {"年":"1976","インフレ率":9.37}, {"年":"1977","インフレ率":8.16}, {"年":"1978","インフレ率":4.2}, {"年":"1979","インフレ率":3.7}, {"年":"1980","インフレ率":7.77}, {"年":"1981","インフレ率":4.91}, {"年":"1982","インフレ率":2.74}, {"年":"1983","インフレ率":1.89}, {"年":"1984","インフレ率":2.26}, {"年":"1985","インフレ率":2.03}, {"年":"1986","インフレ率":0.59}, {"年":"1987","インフレ率":0.12}, {"年":"1988","インフレ率":0.67}, {"年":"1989","インフレ率":2.27}, {"年":"1990","インフレ率":3.07}, {"年":"1991","インフレ率":3.25}, {"年":"1992","インフレ率":1.76}, {"年":"1993","インフレ率":1.24}, {"年":"1994","インフレ率":0.69}, {"年":"1995","インフレ率":-0.12}, {"年":"1996","インフレ率":0.13}, {"年":"1997","インフレ率":1.74}, {"年":"1998","インフレ率":0.66}, {"年":"1999","インフレ率":-0.34}, {"年":"2000","インフレ率":-0.67}, {"年":"2001","インフレ率":-0.74}, {"年":"2002","インフレ率":-0.92}, {"年":"2003","インフレ率":-0.25}, {"年":"2004","インフレ率":0}, {"年":"2005","インフレ率":-0.28}, {"年":"2006","インフレ率":0.24}, {"年":"2007","インフレ率":0.06}, {"年":"2008","インフレ率":1.38}, {"年":"2009","インフレ率":1.35}, {"年":"2010","インフレ率":-0.71}, {"年":"2011","インフレ率":-0.26}, {"年":"2012","インフレ率":-0.05}, {"年":"2013","インフレ率":0.34}, {"年":"2014","インフレ率":2.76}, {"年":"2015","インフレ率":0.78}, {"年":"2016","インフレ率":-0.11}, {"年":"2017","インフレ率":0.46}, {"年":"2018","インフレ率":0.97}, {"年":"2019","インフレ率":0.47}, {"年":"2020","インフレ率":-0.01} ] // 配列dataSetの第1要素の2つのキー名を取得 const dataKey = Object.keys(dataSet[0]); const dataKey1 = dataKey[0]; const dataKey2 = dataKey[1]; // オブジェクト定数 const cht = google.charts; // Google Chartsのパッケージを読み込む cht.load( 'current', // バージョン {'packages':['corechart'], // パッケージ名 'language':'ja',} // ロケール ); // パッケージの読込完了後に呼び出す匿名函数を定義 cht.setOnLoadCallback( function() { // 函数を呼び出す(引数はデータセットと標題) drawChartA('chartA', 'LineChart', dataSet, '日本のインフレ率 1960-2020'); drawChartB('chartB', 'ColumnChart', 'dataSet, '日本のインフレ率 1960-2020'); } ); // チャートを描く函数A(引数はデータセットと標題) function drawChartA(div, chartType, data, title) { // データ表のオブジェクトを作成 const dTable = new google.visualization.DataTable(); // データ表の列のデータ型と列名を定義 dTable.addColumn(typeof data[0][dataKey1], dataKey1); dTable.addColumn(typeof data[0][dataKey2], dataKey2); // データセットから値を順番に取り出してデータ表の行に入力 for (let i = 0; i < data.length; i++) { dTable.addRow( [data[i][dataKey1], data[i][dataKey2]] ); } // チャートの標題などのオプションを定義 const options = { 'title': title, // チャートの標題 'width':670, // 幅 'height':500 // 高さ }; // 折線グラフのオブジェクトを作成 const chart = new google.visualization[chartType]( document.getElementById(div)); // div要素を取得 // チャートを描く(引数はデータ表とオプション) chart.draw(dTable, options); } })(); // 袋とじのための匿名函数の終わり </script>
以下はJavaScriptのコードについての説明。
まず、インフレ率の数値とその年を時系列に並べたデータ・セットを連想配列オブジェクトとして定義した。
// データ・セットを連想配列として定義 const dataSet = [ {"年":"1960","インフレ率":3.57}, {"年":"1961","インフレ率":5.36}, {"年":"1962","インフレ率":6.83}, {"年":"1963","インフレ率":6.7}, {"年":"1964","インフレ率":3.8}, {"年":"1965","インフレ率":6.65}, {"年":"1966","インフレ率":5.04}, {"年":"1967","インフレ率":3.98}, {"年":"1968","インフレ率":5.33}, {"年":"1969","インフレ率":5.24}, {"年":"1970","インフレ率":6.92}, {"年":"1971","インフレ率":6.39}, {"年":"1972","インフレ率":4.84}, {"年":"1973","インフレ率":11.6}, {"年":"1974","インフレ率":23.22}, {"年":"1975","インフレ率":11.73}, {"年":"1976","インフレ率":9.37}, {"年":"1977","インフレ率":8.16}, {"年":"1978","インフレ率":4.2}, {"年":"1979","インフレ率":3.7}, {"年":"1980","インフレ率":7.77}, {"年":"1981","インフレ率":4.91}, {"年":"1982","インフレ率":2.74}, {"年":"1983","インフレ率":1.89}, {"年":"1984","インフレ率":2.26}, {"年":"1985","インフレ率":2.03}, {"年":"1986","インフレ率":0.59}, {"年":"1987","インフレ率":0.12}, {"年":"1988","インフレ率":0.67}, {"年":"1989","インフレ率":2.27}, {"年":"1990","インフレ率":3.07}, {"年":"1991","インフレ率":3.25}, {"年":"1992","インフレ率":1.76}, {"年":"1993","インフレ率":1.24}, {"年":"1994","インフレ率":0.69}, {"年":"1995","インフレ率":-0.12}, {"年":"1996","インフレ率":0.13}, {"年":"1997","インフレ率":1.74}, {"年":"1998","インフレ率":0.66}, {"年":"1999","インフレ率":-0.34}, {"年":"2000","インフレ率":-0.67}, {"年":"2001","インフレ率":-0.74}, {"年":"2002","インフレ率":-0.92}, {"年":"2003","インフレ率":-0.25}, {"年":"2004","インフレ率":0}, {"年":"2005","インフレ率":-0.28}, {"年":"2006","インフレ率":0.24}, {"年":"2007","インフレ率":0.06}, {"年":"2008","インフレ率":1.38}, {"年":"2009","インフレ率":1.35}, {"年":"2010","インフレ率":-0.71}, {"年":"2011","インフレ率":-0.26}, {"年":"2012","インフレ率":-0.05}, {"年":"2013","インフレ率":0.34}, {"年":"2014","インフレ率":2.76}, {"年":"2015","インフレ率":0.78}, {"年":"2016","インフレ率":-0.11}, {"年":"2017","インフレ率":0.46}, {"年":"2018","インフレ率":0.97}, {"年":"2019","インフレ率":0.47}, {"年":"2020","インフレ率":-0.01} ]
この連想配列オブジェクトは"年"と"インフレ率"という2つのキーとその値を持っている。"年"の値がstring型で"インフレ率"の値がnumber型。
Object.keysメソッドを使ってこの連想配列の第1要素から2つのキーを取り出す処理が次のコード。
// 配列dataSetの第1要素の2つのキー名を取得 const dataKey = Object.keys(dataSet[0]); const dataKey1 = dataKey[0]; const dataKey2 = dataKey[1];
Object.keysメソッドの引数に連想配列の第1要素を指し示すdataSet[0]を与えた。これによってdataKeyには"年"と"インフレ率"という2つのキーが代入された。そしてそれらをそれぞれ取り出し、dataKey1に"年"を、dataKey2に"インフレ率"を割り当てた。いずれもstring型。
google.charts.loadメソッドを用いてGoogle Chartsのライブラリを読み込むように指示するのが次のコード。
const cht = google.charts; // パッケージを読み込む cht.load('current', // バージョン {packages:['corechart'], // パッケージ 'language':'ja'} // ロケール );
loadメソッドの第1引数にはバージョンを指定。'current'は公式にリリースされている最新のバージョンを意味している。'upcoming'とすると、公式にまだリリースされていないテスト・バージョンを指定したことになる。
バージョンを固定したい場合にはバージョン番号を直接指定する。
loadメソッドの第2引数はいくつかの設定をするためにあり、波括弧の中に複数の項目をカンマで区切って指定できる。そのうちpackageは必須。'corechart'を指定すると、用意されている基本的なチャート・クラスをインスタンス化して利用できるようになる。
packageの値は角括弧の中にカンマで区切って複数指定できる。例えば次のように。
cht.load('current', // 複数のパッケージを読み込む {packages:['corechart','table',''geochart'], 'language':'ja'} );
loadメソッドの第2引数の2つ目には'language'としてロケールを指定した。これは言語や通貨単位などを特定するためのもの。jaが日本語や日本の通貨単位(円)を意味する。チャートに日本語の文字列を描画したければ指定しておいたほうがよいかもしれない。
次にコールバック函数を登録する。この函数はパッケージの読み込みが完了した後に呼び出されるためのもの。C言語で言えばmain函数に当たるようなものだろうか。
これを行うにはsetOnLoadCallbackメソッドを用いてその引数に匿名函数を与える方法がある。例えば次のように。
// パッケージの読込完了後に呼び出す匿名函数を定義 cht.setOnLoadCallback( function() { // 函数を呼び出す(引数はデータ・セットと標題) drawChartA('chartA', 'LineChart', dataSet, '日本のインフレ率 1960-2020'); drawChartB('chartB', 'ColumnChart', dataSet, '日本のインフレ率 1960-2020'); } );
この匿名函数の中には、各々のチャートを作成するためにこれから定義する函数を呼び出すステートメントが2つある。それらの引数には、HTMLのdiv要素のid、チャートのタイプ名、データ・セット、チャートの標題を与える必要があるようにしてある。
各々のチャートを作成する函数を定義
チャートを描くための函数を1つ定義した。函数名はdrawChart。この函数はdiv要素のid名(div)とチャートのタイプ名(chartType)とデータ・セット(data)とチャートの標題(title)の4つの引数を受け取るようにした。函数呼び出すステートメントでこれらの引数の値を具体的に指定する。
function drawChartA(div, chartType, data, title) { // ここのブロックに函数の内容をコーディング }
この函数のブロックの中ではまずデータ・テーブルを作成する。データ・テーブルとは列(a column)と行(a row)の形式にデータを並べた表のこと。作成するチャートに適合したデータ・テーブルを用意する必要がある。
そのためにデータ・テーブルのコンストラクタ函数(クラス)からオブジェクトを作成。いわゆるインスタンス化。
const dTable = new google.visualization.DataTable();
次にaddColumnメソッドを用いてデータ・テーブルの各列のデータ型とラベル名を設定。
dTable.addColumn(typeof data[0][dataKey1], dataKey1); dTable.addColumn(typeof data[0][dataKey2], dataKey2);
addColumnメソッドの第1引数にはデータ型を、その第2引数には列名を指定する。値の指定に定数を使っているので分かりにくいが、要するに次のように指定したことと同じこと。
dTable.addColumn('string', '年'); dTable.addColumn('number', 'インフレ率');
定数を用いることで別のデータ・セットにしたときにも対応できるコードにした。ただしそのデータ・セットは同じ形式の連想配列である必要がある。
addRowメソッドを用いてデータ・テーブルに値を追加していく処理が次のコード。
for (let i = 0; i < data.length; i++) { dTable.addRow( [data[i][dataKey1], data[i][dataKey2]] ); }
その引数に定数を指定しているので分かりにくいが、要するに、addRowメソッドの第1引数に"年"の値を、その第2引数に"インフレ率"の値をそれぞれ指定していることと同じ。
for文なのでカウンター変数iが0から順番に1つずつ増えていきながら連想配列の長さぶんだけこの処理が繰り返される。こうして連想配列の値がデータ・テーブルに転記されるようになるはず。
JavaScriptでの連想配列(オブジェクトの一種)の取扱いについての詳細はまたの機会に。
次のコードではオプションを指定している。オプションとはこのチャートに与える様々な属性のこと。プロパティか。あるいは引数か。
const options = { 'title': title, // チャートの標題 'width':670, // 幅 'height':500 // 高さ };
最初は文字通りこのチャートのタイトル(title)。2つめはチャートの幅(width)。3つめはチャートの高さ(height)。
次のコードではライン・チャート(折線グラフ)のコンストラクタ函数(クラス)からオブジェクト(インスタンス)を作成している。その引数にはgetElementByIdメソッドを使ってdiv要素を取得して与えている。
const chart = new google.visualization[chartType]( document.getElementById(div));
このコードは本来は次のようなものだが、チャート・タイプ名の部分とdiv要素のidの部分をこの函数が引数として受け取るようにした。
const chart = new google.visualization.チャート・タイプ名( document.getElementById('div要素のid'));
Google Chartsにはどのようなチャート・クラスが用意されているかを知るには、Google Chartsのウェブ・サイトを開き、ナビゲート・メニューの「Guides」から「Chart Types」の一覧を参照する。「Chart Gallery」を見ると各種チャートの完成図を見ながら選びやすい。そこにそれぞれのチャートの利用方法が(英文だけど)書かれてある。
最後にdrawメソッドを使ってその引数にデータ・テーブルと先ほど定義したoptionsを指定し、チャートを描けばこの函数は終わり。
chart.draw(dTable, options);
JavaScriptのコード全体を匿名函数で袋とじした。こうすることで擬似的な名前空間になり、函数名、変数名、定数名などの識別子の競合(上書きなど)を防ぐことができるはず。
(function() { // ここにコード全体を記述 })();
このコードを基盤にすれば、データ・セットを与えればそれをチャートとして視覚化してくれるウェブ・アプリを作ることができるかもしれない。その試みはまたの機会に。
参照元: 関連する投稿:
コメント
コメントを投稿