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

  • 35
    いいね
  • 1
    コメント

複合チャートが描きたい

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ブラウザ上への組み込み方が出てこなかったんですよね。見かたが悪かったのかもしれませんが……。

組み込み用のコードは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>

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

<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: [
    {
        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>