Chart.jsで作成する折れ線グラフの実例

たまに必要に迫られて、ブラウザで完結するように生のJavaScriptを書くことがあります。
今回はそんなシンプルな構成でも案外きれいなUIを作成するのに役立つグラフ作成ライブラリ、Chart.jsについてメモしておきます。

機能の豊富さとコーディングの簡潔さは往々にしてトレードオフなので、ライブラリの選択が重要ですね。
D3ほど高機能でなくてもいいが、できるだけ簡単にグラフを書きたい、という時に扱いやすい(と個人的に思っている)ライブラリです。

■ シンプルな記述
■ よく使われるような種類のグラフなら標準の機能だけでも作成できる
■ (ちょっとサイズが大きいが)ファイルひとつで動く
■ デフォルトでアニメーション(パフォーマンス要件が厳しければ無効化することもできる)

もくじ:

Chart.jsの設置

静的コンテンツだけで済むのであれば、ローカルのHTMLファイル一式として置いておけば、サーバを立てられない環境でもブラウザで表示させられて便利です。

ファイル構成はこんな感じにしました。

といっても見た目のためにBootstrapを設置している程度で、最小限にはChart.js本体(Chart.bundle.min.js)と、そのAPIを呼ぶHTML+Scriptブロックがあれば十分です。ディレクトリ構成もHTML内でパスが通っていれば何でも構いません。

ちゃんとしたインストールはもちろん公式マニュアルの指示通りが推奨。今回はGithubのレポジトリからVersion 2.7.2の本体を入手してスタンドアローンに設置しています。

ちゃんとバックエンドが構築できる環境ではCDNを参照させたり、bowerやらnpmに管理させるなりしたほうが効率的です。
また、時系列を扱う関係でMoment.jsをバンドルしたファイル(Chart.bundle...)を使っていますが、日付の操作が必要ない場合や別途参照させる場合は単にminifyしたものでOKです。

HTMLはこんな記載にしました。グラフを表示する領域のためのdiv要素と、スクリプトの読み込みをしているだけの記述です。

別のファイルとして、Chart.jsのAPIを呼び出すためのスクリプトmycharts.jsを用意していますが、この規模かつ生のJavascriptなので何でもアリ、このあたりの組み込み方も特に制約があるわけではありません。もちろんNode、というかCommonJSでは明示的に管理しますが。。。

スクリプトmycharts.jsの詳細は後述しますが、ここでは一旦内容を掲載しておきます。

基本の折れ線グラフ

Chart.jsは棒グラフや円グラフなど、某Excelのテンプレにあるような大抵のグラフはサポートしていますが、その機能のぶん分量が多くなってしまうので、今回は個人的によく使う折れ線グラフについて記載します。
ただし、見た目の調整など他の種類のグラフでも共通的に使える部分も多いです。

今回はmycharts.jsにまとめて記載しますが、大まかな構成はこんな感じ。

基本的には必要なデータ(ここではconst chartDataSet)をセットし、グラフを描画したい領域に確保したcanvas要素を指定してChart.jsのAPIを呼び出す、という手順です。
今回はハードコードしてますが、グラフの元データとなるデータ系列(ここではconst sampleData)は通常静的に書くことはなく、Ajaxか何かで動的に読むことになるかと思いますが、その場合も手順自体は変わりません。

デフォルトでアニメーション付き、ツールチップ付きなど特に設定を作りこまなくても比較的きれいなグラフが作成できます。下記は上記のmycharts.jsで記載した簡単な例です。

グラフの表示方法により、主にAPIに渡すconst chartDataSetの作り方にバリエーションがあります。その他の記述は大抵同じなので、以下に異なる部分のみ記載しておきます。

線のスタイル

線の色と背景色

data:datasets[]:borderColor/backgroundColor
折れ線グラフの色については主に線の色borderColorと背景色backgroundColorが設定できます。背景色はグラフ領域の塗りつぶしや凡例の塗りつぶし(デフォルト)に使用されます。

色(文字列)の書式は上記のようなRGBAのほか、RGBや#RRGGBB、色名が使えます。色の指定方法については他のプロパティでも同じです。

破線

data:datasets[]:borderDash[]

破線にするにはborderDashに線分の長さと間隔の長さを設定します。

作成例はこんな感じ(緑色の系列)。

直線

data:datasets[]:lineTension

デフォルトではベジェ曲線で描画され見た目が滑らかな線グラフになりますが、単に直線で各点を繋ぐにはlineTensionをゼロに設定します。

表示させたもの(水色の系列)はこんな感じ。

ステップ

data:datasets[]:steppedLine
steppedLineを指定すると、離散値であることを強調するステップ状の線グラフ(↑の図緑色の系列を参照)になります。

data:datasets[]:pointRadius
線グラフの頂点を描画しないように指定するには、pointRadiusをゼロに設定します(先の絵水色の系列を参照)。

data:datasets[]:pointStyle
また、pointStyleに指定する文字列により、頂点の形を変更することができます。デフォルトでは円('circle')になっています。

作成例の図は後の塗りつぶしのところにあります。

欠損値

データにNaNを設定すると、その頂点で途切れた形状になります。

実際に作成させるとこんな感じ。

塗りつぶし(fill)

塗りつぶさない

data:datasets[]:fill
デフォルトの折れ線グラフでは塗りつぶし(fill)が設定されていますが、同時に表示させるデータ系列が多くなり見づらい場合には、塗りつぶしをさせず頂点・線のみを表示させるよう指定することができます。

fillfalseをセットすると塗りつぶしをさせない設定になります。

塗りつぶしはdatasets内の各データ系列毎に指定できます。

上側・下側

data:datasets[]:fill
デフォルトでは原点から(X軸との間)塗りつぶしますが、グラフ領域の上端から(end)または下端(start)からの面積を塗りつぶすこともできます。

作成例は下記にあります。頂点が四角の系列の上側を塗りつぶす({fill: 'end'})例です。

差分

data:datasets[]:fill
ちょっと変わった塗りつぶしの方法としては、データ系列同士の差となる部分を指定させる設定があります。

対となるデータ系列はデータ系列のインデックスで指定します。fillに正数を設定した場合はデータ系列の(絶対)インデックス(1, 2…)、文字列を指定した場合は相対インデックス('-1':一つ前, '+1':一つ後,…)となります。

文章で説明するよりグラフを見たほうがはやいですね。頂点が三角の系列とスターの系列の差となる部分を塗りつぶす例です。

軸の設定

目盛りの設定

options:scales:xAxes[]/yAxes[]:ticks

各X軸・Y軸の設定のなかで、ticksで各軸の目盛りの設定を指定することができます。
よく使うと思われるのは最大値max・最小値minの指定や、開始点をゼロに設定する指定beginAtZeroでしょうか。描画させる範囲を指定することができますが、想定外のデータがセットされた場合は線グラフが見切れてしまったりするので、suggestedMaxsuggestedMinなどの値を使って弱い制約にする指定もあります。

グリッドの設定

options:scales:xAxes[]/yAxes[]:gridLines

ここでいうグリッドは、グラフの背景に表示される目盛り毎の線のことです。デフォルトでは灰色の実線で表示されますが、色や線のスタイルを変えることができます。

各X軸・Y軸の設定のなかで、gridLinesプロパティを指定することで書式を変更することができます。
設定可能なプロパティは主軸(zeroLine...)とその他の目盛りとで名称が別れています。例えば色を設定する場合には、軸はzeroLineColorプロパティ、その他はcolorプロパティに指定します。

上記の指定で作成した例はこんな感じ。

タイトルと凡例

タイトル

options:title
デフォルトではグラフのタイトルが非表示になっているので、明示的に指定({display: true})することで表示させることができます。

作成例は先ほどの絵のようになります。

凡例(legend)

凡例はデフォルトで表示されますが、サイズや位置などを変えることができます。

options:legend

表示位置はpositionプロパティに文字列('top', 'right'…)をセットすることで設定できます。
表示の大きさはlabels.fontSizeプロパティを指定することで調整できますし、凡例の左側に表示されるボックスの幅labels.boxWidthなども設定することができます。
デフォルトで、ボックスのスタイル(border/fill)はグラフのスタイルを継承するので、塗りつぶさないときでもデータセットにbackgroundColorを設定しておくといいと思います。

さらにfilterプロパティに自前のFunctionを設定することで、データの値に応じて表示方法を切り替えることもできます。例えば特定のラベルを隠したい場合には、表示させたいものについてtrueを返すFunctionを記述すればOKです。上記の例ではラベルに文字列'3'を含むもの(ここでは{label: 'sample3'}の凡例)を非表示にします。

作成例はこんな感じ。

時系列

折れ線グラフにデータ系列をセットするとX軸の値が何であろうと暗黙的に左から右へ並べますが、X軸が時間軸の場合はさらに表示を工夫することができます。
時系列データの場合、各データを不定期に取得した場合など、各頂点を等間隔に並べる表示では正確ではないかもしれません。

明示的に日付型を経由させることで、X軸を時系列として表現します。Chart.jsには含まれないMoment.jsを内部的に使用しているようなので、バンドル版を使うか、別途セットアップする必要があります。

data:datasets[]:data
データ系列dataには、Y軸上の値(y)と日付型(t)からなるオブジェクトをセットします。今回はサンプルのデータ系列に文字列で定義した時刻(sampleData.timestamp)を定義しています。
options:scales:xAxes[]
また、X軸を時間軸として設定するため、定義xAxes{type: 'time'}を指定します。

表示方法としては、時刻を表現する設定と、セットされたデータ系列を等間隔に表現する設定があります。時刻型の軸xAxes内でdistributionに指定します。
違いは絵で見たほうがはやいと思います。もとのデータ系列は途中大きく時間が空いた(マウスカーソルが映りこんでいる部分)ものをサンプルにしています。よく見ると目盛りの表示間隔が違うことが分かります。

時間軸という意味では取得時刻のばらつきに関わらず時刻スケールで表示({distribution: linear})したほうが直感的に理解しやすいものの、あまりデータがない時間が続く場合には間延びしてしまうので、用途によりけりですね。

複数軸

振幅(スケール)の異なるデータ系列を扱うときには、Y軸を左右に分けて表示させたくなる場合があると思います。先に作成例の図を載せるとこんな感じ。

この場合は、Y軸にIDを設定しデータ系列に対応付けることで、半自動的に異なる軸を作図させることができます。

options:scales:yAxes[]
まず、optionsで複数のY軸を定義します。yAxes(配列)に各Y軸を記述し、ID(一意な文字列)や位置('left'または'right')を設定します。

data:datasets[]:yAxisID
各データセットがいずれのY軸に関連付けられるかの設定は、yAxisIDに指定します。単数axisと複数axesでスペルが微妙に変化するのが非英語圏の人間には辛いところですね。

また、各Y軸の表示名やサイズなどの書式設定はyAxes内に書きます。色など見た目で各データ系列と共通点を持たせると見やすくなるかもしれません。

複数種類のグラフ

data:datasets[]:type

datasetsの内側でグラフの種類を指定すると、同じ軸に対して別種類のグラフを組み合わせて表示(混合グラフ)させることができます。

こんな感じのグラフですね。

下記の例では基本の種類に棒グラフ(type: 'bar')、1-2番目の系列に折れ線グラフ(type: 'line')を指定しています。3番目の系列ではtypeを指定していないので外側の基本設定(ここでは棒グラフ)が適用されます。

異なる種類でも、データ系列の形式が大きくことなるようなグラフは組み合わせることができません。例えば折れ線グラフと円グラフとか。

おわり。