こんにちは。きんくまです。
今回は「d3.jsで線グラフが描きたい!」です。
参考にした記事
>> Scales — Scott Murray — alignedleft
>> Axes — Scott Murray — alignedleft
>> SVG Paths and D3.js
>> Line Chart
4番目の線グラフデモを理解するために、上の3つの記事を読みました。
というかScott Murrayさんという方の一連のチュートリアルがとても良いので、これを読むと基本的なことはわかると思われです。
今回つくったもの(特に動かないので画像です)
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])でとるとどうなるのか?イメージ的には下の図の赤いエリアです。
すると結果はこうなります。(実際には見せたくない部分にも線グラフが描画されていたので、マスク処理したものになっています。)
var xScale = d3.scale .linear() //.domain([0, d3.max(dataset, (d)=>{ return d[0];})]) .domain([100, 300]) .range([padding, w - padding]);
上の赤い部分がひきのばされて表示されているのがわかりますでしょうか?
次に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]);
同じデータなのですが、ぎゅっと左右が縮まっているのがよくわかりますね。
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’) で結ぶとこんな感じに曲線で結ばれました。
Scott Murrayさんの点のチュートリアルを線グラフにする
Scott Murrayさんのは点で打っていたのですが、それを線グラフにしてみます。
そのままプロットするとこんな感じにこんがらがってしまうので、sortをいれます。
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; } });
あとはそのまま続けていくと最初にお見せした画像のようなものができます。
これです。
今回のソース全部です。
上の方にちょろっと書いたのですが、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);
■ 自作iPhoneアプリ 好評発売中!
・フォルメモ - シンプルなフォルダつきメモ帳
・ジッピー電卓 - 消費税や割引もサクサク計算!
■ LINEスタンプ作りました!
毎日使える。とぼけたウサギ