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

# 複合チャートが描きたい

![1.png](https://qiita-image-store.s3.amazonaws.com/0/129854/01b38410-fcb3-1659-cfa6-75f626446ad9.png)

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


![4.png](https://qiita-image-store.s3.amazonaws.com/0/129854/250b05aa-e93c-4ef3-78e4-2e7f15bf4bef.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

```html
<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](http://momentjs.com/) というライブラリがバンドルされているそうです。他のところで Moment.js を組み込んでいるとよろしくないようですが、なんじゃそれ？と思う場合は bundle 版を使っておくのが無難と思います。


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

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

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

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

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

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

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

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

```html
<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>
```

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


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

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


![2.png](https://qiita-image-store.s3.amazonaws.com/0/129854/7fcda3d0-b8d4-4248-ff09-04cab60d13cc.png)




# 複合チャートにする

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

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


```html
<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](https://qiita-image-store.s3.amazonaws.com/0/129854/41de91d9-e986-2a77-4307-3648a9ae9dab.png)



## 縦軸の設定を変更する

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

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

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


```html
<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つの軸のうち、どちらの軸に属するデータなのかを指定するわけですね。


```html
<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](https://qiita-image-store.s3.amazonaws.com/0/129854/8230ceb8-e548-6c70-f8fc-6180e4a232da.png)


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

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

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

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

```html
<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軸のみ消します。


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

## 完成！

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

![4.png](https://qiita-image-store.s3.amazonaws.com/0/129854/250b05aa-e93c-4ef3-78e4-2e7f15bf4bef.png)


最後に、全体のコードを載せておきます。
（HTMLもBODYも無いけど、動くので……）

```html: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>

```