jnobuyukiのブログ

JavaScriptとR言語を中心に研究活動に役立つwebアプリケーション技術について考えていきます。twitter ID: @j_nobuyuki

d3.jsを利用した棒グラフの作成(1)

D3.jsを利用して棒グラフを作成する手順をまとめておきます。
今回は、前にGoogleChartsを利用した棒グラフを作成したときの気温データを使いましょう。

準備:データリストの作成
var data = [
              ["date","tempmax","tempmin"],
              ["12/11",12.8,7.3],
              ["12/12",13.2,7.9],
              ["12/13",14.9,4.1],
              ["12/14",11.2,4.6],
              ["12/15",11.4,2.8],
              ["12/16",11.9,5.4],
              ["12/17",12,7],
              ["12/18",8.8,3.6],
              ["12/19",7.6,3.7],
              ["12/20",9.4,3.3],
              ["12/21",11,2.8],
              ["12/22",11.4,5.5],
              ["12/23",8.4,4.4],
              ["12/24",12.5,4.5],
              ["12/25",10.3,3.3],
              ["12/26",10,3.4],
              ["12/27",9.4,5.1],
              ["12/28",9.3,2.7],
              ["12/29",9.5,0.5],
              ["12/30",10.5,0.6],
              ["12/31",12.7,1.3],
              ["1/1",15.5,3.1],
              ["1/2",12.1,3.1],
              ["1/3",8.5,3.8],
              ["1/4",11.7,2.4],
              ["1/5",7.3,3.9],
              ["1/6",10.5,2.1],
              ["1/7",9.9,1.9],
              ["1/8",12.8,2.8],
              ["1/9",11.8,3],
              ["1/10",6.8,1.4],
              ["1/11",9,0.7]
    ];

GoogleChartsを利用したときの同じデータです。他次元配列になっていて、上位の配列の0番目の要素にラベルが格納されています。

D3.jsを利用して棒グラフを書く場合、データを棒の高さに関連付ける以外にたくさんの作業が必要です。

1.SVGオブジェクトを作る
2.縦軸と横軸を作る
3.データを表現する棒を作る

SVGオブジェクトを作る

グラフをのせるステージとしてSVGオブジェクトを設定します。

var width = 400;
var height = 300;
var margin = 50;

var svg = d3.select("#base").append("svg")
.attr("width",function(){return width + (margin * 2);})
.attr("height",function(){return height + (margin * 2);});

widthとheightがグラフエリアの幅と高さ、marginはグラフエリアの余白の幅をあらわしています。

縦軸と横軸を作る
var xScale = d3.scale.linear().range([0,width]);
var yScale = d3.scale.linear().range([height,0]);

linear()というのは各軸が等間隔のスケールを仮定する場合に使います。今回の例の場合、X軸が日付データなので.ordinal()も利用できます。rangeはsvg上の座標の最小値と最大値です。y軸で最大値、最小値となっているところがポイント。y座標の値は、画面の上端で0、下にさがるほど値が増えるので0が一番大きくなるわけです。

var xScalelist = [];

data.forEach(function(d){
    xScalelist.push(d[0]);
    return;
});
var yScalelist = [];
data.forEach(function(d){
    yScalelist.push(+d[1]);
    return;
});

データをスケールに割り振るため、配列に格納します。

xScalelist.splice(0,1);
yScalelist.splice(0,1);

0番目の要素であるラベルを軸用のリストから削除しておきます。

var yScalemax = d3.max(yScalelist);

xScale.domain([0,xScalelist.length]);
yScale.domain([0,yScalemax]);

x軸の値の範囲(domainで指定)は0からリストの長さ分です。y軸は値の最大値を軸の最大値にしました。(少し余裕をもたせても良いかもしれないです)

var xAxis = d3.svg.axis().scale(xScale).orient("bottom")
.tickValues([0,1,2,3,4,5,6,7,8,9,10,11,12,13
,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31])
.tickFormat(function(d,i){return xScalelist[i]});

var yAxis = d3.svg.axis().scale(yScale).orient("left");

x軸につけるラベルは原始的ですが、1から数字を割り振ってしまいました。他に方法があるはずですね。
y軸はそのまま軸に値を関連付けます。

svg.append("g").attr("class","axis")
.attr("transform","translate(" + margin + ", " + (margin + height) + ")")
.call(xAxis);

svg.append("g").attr("class","axis")
.attr("transform","translate(" + margin + ", " + margin + ")")
.call(yAxis);

そして、軸をsvgに貼り付けます。translateで位置を調整しています。

データを表現する棒を作る

y座標の値の割り振り方がポイントです。

var bars = svg.append("g").attr("class","rect").selectAll("rect")
.data(yScalelist).enter().append("rect")
.attr("height",function(d){return height - yScale(d);})
.attr("y", function(d){return (yScale(d));})
.attr("width",function(){return ((width/yScalelist.length)-0.1);})
.attr("x", function(d,i){return i * (width/yScalelist.length);})
.attr("transform","translate(" + margin + ", " + (margin) + ")");

svgオブジェクトの上端が0なので、y軸で示すための値をsvgの高さから引いたものがデータを示す棒の上端の位置になります。長方形の横幅は、軸全体の長さをデータ数で割った値にしてあります。こうするとピッタリと収まります。


ここまでをまとめると以下のようになります。



まとめ:凝ったグラフにしたければD3.js。データの傾向を見たいだけならGoogleCharts。

単純な棒グラフでも、ここまでの作業を必要とするので、グラフ作成にかなり時間がかかります。なので、手軽にデータ全体の傾向を見たければ、GoogleChartsを利用した方がいいでしょう。より複雑なグラフや、ちょっとした位置の変更をしたいような場合には、D3.jsの方が便利です。また、軸の設定や凡例の設置などは、一度きちんと動くコードを作成すれば、再利用ができます。