Anatomy

ANATOMY BLOG

マクロ視点のアクセス解析と品質管理ツール「ANATOMY(アナトミー)」のブログです

2016年10月7日金曜日

【D3.js講座】D3.jsで折れ線グラフを描画する(前編)

今回は、D3.jsを使った折れ線グラフの描画をご紹介します。
前回は簡単なsvg描画を紹介しましたが、今回はデータビジュアライゼーションを目的としているD3.js本来の利便性を感じられるかと思います。

さっそく実装を紹介します。


日本のオリンピックにおけるメダル取得数の推移グラフ

今回もオリンピックに関連したデータの可視化を行いたいと思います。 

*日本のメダル取得数データ

var data = [{"year":1996,"all":14,"gold":3,"name":"アトランタ"},
{"year":2000,"all":18,"gold":5,"name":"シドニー"},
{"year":2004,"all":37,"gold":16,"name":"アテネ"},
{"year":2008,"all":25,"gold":9,"name":"北京"},
{"year":2012,"all":38,"gold":7,"name":"ロンドン"},
{"year":2016,"all":41,"gold":12,"name":"リオデジャネイロ"}];

メダル取得数を縦軸、開催年を横軸において折れ線グラフを作ります。
4年間隔で開催されるので、横軸に対しては等間隔のグラフです。

プログラム実行前のhtmlはこの状態から始めます。

<div></div>

D3.jsを使用しsvg要素でグラフを描画します。

実装

1:svgの用意

まずは、大枠となるsvg要素とg要素を用意します。
描画領域は高さ500px, 横500pxとします。

var w =500;
var h = 500;
var svg = d3.select("div").append("svg").attr({
 "width" : w,
 "height" : h
});
var g = svg.append("g");

2:スケールの定義

縦軸にはメダル数(all)が入るので、dataを目で見てわかるように、最小の値は14, 最大は41となります。
この数値を描画領域(500px × 500px)にうまくフィッティングして描画するためには座標を計算する必要があります。
高さを目いっぱい使うとした場合、メダル個数 n個のy座標は以下のようになります。

y = n × 500(高さ)/41 -14(メダルの最小値、最大値の差)

しかし、D3ではd3.scale.linear()を使うことによって上記の計算を省くことができます。

var y_scale = d3.scale.linear()
.domain([d3.min(data, function(d){ return d.all; }), d3.max(data, function(d){ return d.all; })])
.range([h,0]);

d3.scale.linear()を呼び出してスケールを定義します。
domain関数にはデータの最大値、最小値を入れます。データの最大値、最小値を取得する機能もD3にはあり、以下のように取得できます。

d3.max(data, function(d){ return d.all; });
d3.min(data, function(d){ return d.all; });

range関数には描画領域となる座標の最大値:h、最小値:0を入れます。
(y軸が画面下方向に正をとる座標系なので、range関数に与える引数の順番を入れ替えています。)

この定義以降は座標をいちいち計算しなくてもy_scale(数値)と実行すれば、スケールを計算した値が返ってきます。

 x軸についても同じようにスケールを定義します。

var x_scale = d3.scale.linear()
.domain([d3.min(data, function(d){ return d.year; }), d3.max(data, function(d){ return d.year; })])
.range([0,w]);

3:path要素の配置

今回は折れ線をpath要素のd属性を使用し描画します。

var line = d3.svg.line()
.x(function(d,i) { return x_scale(d.year); })
.y(function(d,i) { return y_scale(d.all); });

g.append("path")
.datum(data)
.attr({
"d": line,
"stroke": "#f00",
"fill": "none",
"stroke-width": "3px"
});

d3.svg.line()はd属性に与えるべき値を生成します。
x関数はx座標の取り方、y関数はy座標の取り方を決めています。

append関数によりpath要素を追加し、datum関数によりデータをバインドしています。
前回まではデータのバインドにdata関数を使用していましたが、
今回はdatum関数を使用しています。
data関数は複数の要素に配列の各データを一つずつバインドし、
datum関数では一つの要素に配列のデータをまとめてバインドします。

var data = [[1,2]];

とした場合は、以下のコードが等価になります。

d3.select("div").data(data).data(); ⇒ [[1,2]]
d3.select("div").datum(data[0]).data(); ⇒ [[1,2]]

4:頂点

折れ線グラフの各頂点に点を配置します。

g.selectAll(".c").data(data).enter().append("circle")
.attr({
 "cx":line.x(),
 "cy":line.y(),
 "r":5,
 "fill":"#000"
});

3で生成したlineオブジェクトを使用し、x座標、y座標を指定しています。

実行結果

実行結果はこのようになります。

(描画領域の上限下限にそのままスケールをあわせたため、端の点がかけています。) 

データからグラフを作成する際には座標計算、スケール計算が必須ですが、D3.jsを使えば比較的簡単に計算が行えます。
また、d3.scale.linear() は線形スケールを行う関数なので、グラフ以外にも応用できる場面があります。

実際のサービスで確認!

オンラインデモではPV数、流入数を簡単なグラフに置き換え可視化しています。


次回は今回作ったグラフをもとに、x軸、y軸、目盛りの追加し、以下のような形まで発展させます。

Related Posts Plugin for WordPress, Blogger...