Edited at

chart.js で複数軸の複合グラフを描く

More than 1 year has passed since last update.


複合チャートが描きたい

1.png

棒グラフと折れ線グラフを1つのチャート内に表示したりするアレが描きたかった。英語ではMixed Chartって言うんですかね。Google Chartではわりと以前からできていたようですが、Chart.jsでは、Ver.2.0(2016/04リリース)からの新機能だそうです。

4.png

このコンテンツでは、このグラフを作ります。


chart.js の基礎

この章は chart.js を使ったことがある人は読み飛ばしてください。


chart.jsとは

WEB上にグラフを描くための、Javascriptライブラリです。

詳しくはググってください。実はあまり知りません。げふげふ……。

http://www.chartjs.org/


Ver.2 ってどうやって使うの?

いきなりコケたんですが、上記公式サイトのGet Started!で始めると、Node.jsで使うことが前提になっていて、ふつうにWebブラウザ上への組み込み方が出てこなかったんですよね。見かたが悪かったのかもしれませんが……。

(2017年9月現在 CDNは下記サイトにわかりやすくリンクされています!)

組み込み用のコードはCDNに公開されているので、無理にダウンロードせず、それをそのまま使うのがカンタンです。

https://cdnjs.com/libraries/Chart.js

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.bundle.min.js"></script>

bundle とそうでないのと2種類ありますが、bundle は、Moment.js というライブラリがバンドルされているそうです。他のところで Moment.js を組み込んでいるとよろしくないようですが、なんじゃそれ?と思う場合は bundle 版を使っておくのが無難と思います。


まずはふつうに描いてみる

chart.js を使うには、まず canvas を用意して…

<div class="container" style="width:100%">

<canvas id="canvas"></canvas>
</div>

スクリプトで描く。これがキホン。

※たとえ後々 line チャートしか使わなくなったとしても、ここでは bar を指定する必要があります。おそらく「外枠」を含めた指定で、line でロードされる外枠は複合チャートに対応していない、ということと思われます。

※Ver.2.7.1では bar だと bar しか表示されないという指摘がありましたが、当方では再現されませんでした。何か条件があるのか調査中……。(2018年2月)

<script>

window.onload = function() {
ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx, {
type: 'bar', // ここは bar にする必要があります
data: barChartData,
options: complexChartOption
});
};
</script>

あえて順番を前後させましたが、データセットと…

<script>

// とある4週間分のデータログ
var barChartData = {
labels: ['8/26','8/27','8/28','8/29','8/30','8/31','9/1',
'9/2','9/3','9/4','9/5','9/6','9/7','9/8',
'9/9','9/10','9/11','9/12','9/13','9/14',
'9/15','9/16','9/17','9/18','9/19','9/20','9/21','9/22'
],
datasets: [
{
label: 'sample-line',
data: ['0.155','0.118','0.121','0.068','0.083','0.060','0.067',
'0.121','0.121','0.150','0.118','0.097','0.078','0.127',
'0.155','0.140','0.101','0.140','0.041','0.093','0.189',
'0.146','0.134','0.127','0.116','0.111','0.125','0.116'
],
borderColor : "rgba(254,97,132,0.8)",
backgroundColor : "rgba(254,97,132,0.5)",
},
{
label: 'sample-bar',
data: ['0.3','0.1','0.1','0.3','0.4','0.2','0.0',
'0.2','0.3','0.11','0.5','0.2','0.5','0.4',
'0.0','0.3','0.7','0.3','0.6','0.4','0.9',
'0.7','0.4','0.8','0.7','0.4','0.7','0.8'
],
borderColor : "rgba(54,164,235,0.8)",
backgroundColor : "rgba(54,164,235,0.5)",
},
],
};
</script>

チャート全体のオプションも用意します。チャートオプションは、今はまずこれだけ。

<script>

var complexChartOption = {
responsive: true,
};
</script>

以上を1つのファイルにまとめると、こんなグラフができあがります。

2.png


複合チャートにする


データセットオプションに type

そのまま複合チャートにするのはとってもカンタンで、データセットの各データに、type: というオプションを付けるだけです。「データセット」のオプションです。お間違えなきよう。

<script>

// とある4週間分のデータログ
var barChartData = {
labels: [
/*(略)*/
],
datasets: [
{
type: 'line', // 追加
label: 'sample-line',
data: [
/*(略)*/
],
borderColor : "rgba(254,97,132,0.8)",
backgroundColor : "rgba(254,97,132,0.5)",
},
{
type: 'bar', // 追加
label: 'sample-bar',
data: [
/*(略)*/
],
borderColor : "rgba(54,164,235,0.8)",
backgroundColor : "rgba(54,164,235,0.5)",
},
],
};
</script>

こうすると、こんなグラフができあがります。

25.png


縦軸の設定を変更する

が、データのスケールが大きくずれている!ということ、よくありますよね。(今回は見やすくするためあえて近づけています)複合チャートでなくても必要になることがありますが。そこで、それぞれのデータを別のスケールで表示してみます。ここがちょっとややこしかったです。


チャート全体のオプションに yAxes

今度はチャート全体のオプションに、下記のように、yAxes を設定します。複数設定して、それぞれに、ID を与えているのがポイントです。

<script>

var complexChartOption = {
responsive: true,
scales: {
yAxes: [{
id: "y-axis-1", // Y軸のID
type: "linear", // linear固定
position: "left", // どちら側に表示される軸か?
ticks: { // スケール
max: 0.2,
min: 0,
stepSize: 0.1
},
}, {
id: "y-axis-2",
type: "linear",
position: "right",
ticks: {
max: 1.5,
min: 0,
stepSize: .5
},
}],
}
};
</script>


データセットのオプションに yAxisID

今度はデータセット。各データセットが、先程作った2つの軸のうち、どちらの軸に属するデータなのかを指定するわけですね。

<script>

// とある4週間分のデータログ
var barChartData = {
labels: [
/*(略)*/
],
datasets: [
{
type: 'line',
label: 'sample-line',
data: [
/*(略)*/
],
borderColor : "rgba(254,97,132,0.8)",
backgroundColor : "rgba(254,97,132,0.5)",
yAxisID: "y-axis-1", // 追加
},
{
type: 'bar',
label: 'sample-bar',
data: [
/*(略)*/
],
borderColor : "rgba(54,164,235,0.8)",
backgroundColor : "rgba(54,164,235,0.5)",
yAxisID: "y-axis-2", // 追加
},
],
};
</script>

こうすると、こんなグラフができあがります。

3.png


あるとキレイになる欲張りオプション

ひとまず複合チャートになりましたが、まだあまり美しくないので、もう少しオプションを加えてみます。


ラインチャートを中抜きに

ラインだけにするのに fill:false とします。実はよく見るとポインタの中身が抜けていたので、それも追加します。

<script>

datasets: [
{
type: 'line',
label: 'sample-line',
data: [
/*(略)*/
],
borderColor : "rgba(254,97,132,0.8)",
// 削除 backgroundColor : "rgba(254,97,132,0.5)",
pointBackgroundColor : "rgba(254,97,132,0.8)", // 追加
fill: false, // 追加
yAxisID: "y-axis-1",
},
</script>


第2軸の横グリッドを非表示に

横グリッド線が、2つの軸両方に表示されていて等間隔になっていないので、第2軸のみ消します。

        }, {

id: "y-axis-2",
type: "linear",
position: "right",
ticks: {
max: 1.5,
min: 0,
stepSize: .5
},
gridLines: { // このオプションを追加
drawOnChartArea: false,
},
}],
</script>


完成!

こんな感じにできましたーー!

4.png

最後に、全体のコードを載せておきます。

(HTMLもBODYも無いけど、動くので……)


complex-chart-sample.html


<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.bundle.min.js"></script>

<div class="container" style="width:100%">
<canvas id="canvas"></canvas>
</div>

<script>
window.onload = function() {
ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: complexChartOption
});
};
</script>

<script>
// とある4週間分のデータログ
var barChartData = {
labels: ['8/26','8/27','8/28','8/29','8/30','8/31','9/1',
'9/2','9/3','9/4','9/5','9/6','9/7','9/8',
'9/9','9/10','9/11','9/12','9/13','9/14',
'9/15','9/16','9/17','9/18','9/19','9/20','9/21','9/22'
],
datasets: [
{
type: 'line',
label: 'sample-line',
data: ['0.155','0.118','0.121','0.068','0.083','0.060','0.067',
'0.121','0.121','0.150','0.118','0.097','0.078','0.127',
'0.155','0.140','0.101','0.140','0.041','0.093','0.189',
'0.146','0.134','0.127','0.116','0.111','0.125','0.116'
],
borderColor : "rgba(254,97,132,0.8)",
pointBackgroundColor : "rgba(254,97,132,0.8)",
fill: false,
yAxisID: "y-axis-1",// 追加
},
{
type: 'bar',
label: 'sample-bar',
data: ['0.3','0.1','0.1','0.3','0.4','0.2','0.0',
'0.2','0.3','0.11','0.5','0.2','0.5','0.4',
'0.0','0.3','0.7','0.3','0.6','0.4','0.9',
'0.7','0.4','0.8','0.7','0.4','0.7','0.8'
],
borderColor : "rgba(54,164,235,0.8)",
backgroundColor : "rgba(54,164,235,0.5)",
yAxisID: "y-axis-2",
},
],
};
</script>

<script>
var complexChartOption = {
responsive: true,
scales: {
yAxes: [{
id: "y-axis-1",
type: "linear",
position: "left",
ticks: {
max: 0.2,
min: 0,
stepSize: 0.1
},
}, {
id: "y-axis-2",
type: "linear",
position: "right",
ticks: {
max: 1.5,
min: 0,
stepSize: .5
},
gridLines: {
drawOnChartArea: false,
},
}],
}
};
</script>