[JavaScript] d3.jsで線グラフが描きたい!

2015/08/3

こんにちは。きんくまです。

今回は「d3.jsで線グラフが描きたい!」です。

参考にした記事
>> Scales — Scott Murray — alignedleft
>> Axes — Scott Murray — alignedleft
>> SVG Paths and D3.js
>> Line Chart

4番目の線グラフデモを理解するために、上の3つの記事を読みました。
というかScott Murrayさんという方の一連のチュートリアルがとても良いので、これを読むと基本的なことはわかると思われです。

今回つくったもの(特に動かないので画像です)
linechart_fig1

scale, domain, range

まずscaleについて。
これは入力と出力の範囲を決めるもので、
domain … 入力
range … 出力
となります。

上の全部見えている画像は入力をdomain([0, 600])ぐらいでとってあります。

            var xScale = d3.scale
                .linear()
                .domain([0, d3.max(dataset, (d)=>{ return d[0];})])
                .range([padding, w - padding]);

もし、これをdomain([100, 300])でとるとどうなるのか?イメージ的には下の図の赤いエリアです。

linechart_domain_target

すると結果はこうなります。(実際には見せたくない部分にも線グラフが描画されていたので、マスク処理したものになっています。)

            var xScale = d3.scale
                .linear()
                //.domain([0, d3.max(dataset, (d)=>{ return d[0];})])
                .domain([100, 300])
                .range([padding, w - padding]);

linechart_domain

上の赤い部分がひきのばされて表示されているのがわかりますでしょうか?

次にrangeは出力なのでどうやって見せるかになります。上の場合は出力する範囲を変えていないので、
同じ位置に出力されています。ためしにxScaleのrangeを半分にしてみます。

            var xScale = d3.scale
                .linear()
                .domain([0, d3.max(dataset, (d)=>{ return d[0];})])
                //.range([padding, w - padding]);
                .range([padding, (w- padding) * 0.5]);

linechart_half_xrange

同じデータなのですが、ぎゅっと左右が縮まっているのがよくわかりますね。

axis(軸)

axisはx軸、y軸などの軸を設定します。
ただ基本的に設定するのは3つぐらいでした。

・scale(上でやってたやつ)
・orient(目盛りの配置する方向)
・ticks(何目盛り=いくつの目盛りで表すか)

            var xAxis = d3.svg.axis()
                .scale(xScale)
                .orient('bottom')
                .ticks(3);

line関数

線グラフのline関数は
・x座標
・y座標
・点の補間
を設定すればOKでした。

            var lineFunc = d3.svg.line()
                                 .x((d)=>{ return xScale(d[0]); })
                                 .y((d)=>{ return yScale(d[1]); })
                                 .interpolate('lenear');

xy座標はデータのどの部分を使うのかを指定します。
点の補間というのはどうやって点を結ぶかの見せ方の方法だと思います。
てっく煮さんの記事が出てきたのでこれをみるとわかりやすいです。
>> D3.js の d3.svg.line() を試してみた

ためしに interpolate(‘basis’) で結ぶとこんな感じに曲線で結ばれました。

linechart_interpolate

Scott Murrayさんの点のチュートリアルを線グラフにする

Scott Murrayさんのは点で打っていたのですが、それを線グラフにしてみます。
そのままプロットするとこんな感じにこんがらがってしまうので、sortをいれます。

linechart_complex_line

            var dataset = [
                [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
                [410, 12], [475, 44], [25, 67], [85, 21], [220, 88],[600, 150]
            ];
            dataset.sort((d1, d2)=>{
                if(d1[0] < d2[0]){
                    return 1;
                }else if(d1[0] > d2[0]){
                    return -1;
                }else{
                    return 0;
                }
            });

あとはそのまま続けていくと最初にお見せした画像のようなものができます。
これです。

linechart_fig1

今回のソース全部です。
上の方にちょろっと書いたのですが、domainをいじると線がはみ出てしまうので、マスク処理をいれてあります。この記事みながらやってみたらできました
>> Clipping and masking

var w = 400;
var h = 400;
var padding = 50;
var dataset = [
    [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
    [410, 12], [475, 44], [25, 67], [85, 21], [220, 88],[600, 150]
];
dataset.sort((d1, d2)=>{
    if(d1[0] < d2[0]){
        return 1;
    }else if(d1[0] > d2[0]){
        return -1;
    }else{
        return 0;
    }
});

var xScale = d3.scale
    .linear()
    .domain([0, d3.max(dataset, (d)=>{ return d[0];})])
    .range([padding, w - padding]);

var yScale = d3.scale.linear()
    .domain([0, d3.max(dataset, (d)=>{ return d[1]; })])
    .range([h - padding, padding]);

var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient('bottom')
    .ticks(3);

var yAxis = d3.svg.axis()
    .scale(yScale)
    .orient('left')
    .ticks(5);

var lineFunc = d3.svg.line()
                     .x((d)=>{ return xScale(d[0]); })
                     .y((d)=>{ return yScale(d[1]); })
                     .interpolate('lenear');

var svg = d3.select('body')
    .append('svg')
    .attr('width', w)
    .attr('height', h);

var mask = svg.append('defs')
              .append('mask')
              .attr('id', 'line_mask')
              .append('rect')
              .attr('width', w - padding * 2)
              .attr('height', h - padding * 2)
              .attr('x', padding)
              .attr('y', padding)
              .attr('fill', 'white');

var lineGraph = svg.append('path')
                   .datum(dataset)
                   .attr('class', 'line')
                   .attr('d', lineFunc)
                   .attr('mask', 'url(#line_mask)');

svg.append('g')
    .attr('class', 'axis')
    .attr('transform', 'translate(0,' + (h - padding) + ')')
    .call(xAxis);

svg.append('g')
    .attr('class', 'axis')
    .attr('transform', 'translate(' + padding + ', 0)')
    .call(yAxis);
LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る