今回のエンジニアブログを担当する藤岡です。
宜しくお願い致します。
今回はD3.jsと呼ばれるJavaScriptのライブラリを使い、配列の可視化を行ってみたいと思います。
D3とは「Data-Driven Documents(データ駆動ドキュメント)」の頭文字を取ったもので、その名の通りデータとDOMを結びつける機能があります。
この機能を使うことでデータセットをループ文等で制御する必要が無くなり、コードをシンプルに書くことが可能となっています。
因みに、海外ではD3.jsの人気が高く、現在非常に注目度の高いライブラリです。
D3.jsは、Scriptタグ内に以下の記述をすることで扱えるようになります。
<script charset="utf-8" type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
全体の流れ
1, 描画領域を生成(SVG領域)
2, データバインディング
3, 表示の調整
1, 描画領域を生成(SVG領域)
var svg_w = 500; // 幅 var svg_h = 200; // 高さ var svg = d3.select("body") // body要素を監視 .append("svg") // svg領域を追加 .attr({ width: svg_w, // 幅を設定 height: svg_h, // 高さを設定 });
※チェイン構文を使わずともコードは動作しますが、個人的にはチェイン構文を使った方がコードが見やすいように感じます。
上記のコードは、bodyタグ内にsvg領域を500 * 200の大きさで生成しています。
JavaScriptコンソールで確認してみるとsvg領域が追加されていることが確認できるかと思います。
2, データバインディング
先ほど用意したSVG領域内に、データセットと対応した棒線を描画します。
var dataset = [10, 20, 30, 40, 50, 60]; // サンプルデータセット // 棒線を生成 svg.selectAll("rect") .data(dataset) // データバインディング .enter() // データセットを参照し、仮データを生成 .append("rect") // 生成された仮データをSVG領域に追加 .attr({ x: 0, y: function(d, i) { return i * 40; }, width: function(d) { return d; }, height: 25, fill: "red", }); // データセット値を文字列としてグラフに表示 svg.selectAll("text") .data(dataset) .enter() .append("text") .text(function(d) { return d; }) .attr({ x: 10, y: function(d, i) { return i * 40 + 20; }, fill: "black" });
datasetは配列なのですが、for文等のループ構文が使用されていません。
.data(dataset)
セレクション対象をrectに設定してから、data()関数でDOMにデータバインドしています。
data()関数はデータセット内の値の個数を数え、解析してくれます。
よって、data()関数がチェインされている全ての要素は、各々のデータセットの個数分繰り返されることになります。
.enter()
セレクト対象の要素rectはまだ生成されていません。
セレクト対象を生成するにはenter()関数が必要です。
enter()関数は、バインドされたデータを受け取り、DOM要素の個数を比べ、足りない分を仮データとして生成します。
.append("rect")
enter()関数が生成した仮データを受け取り、svg領域にrect要素を追加しています。
.attr({ x: 0, y: function(d, i) { return i * 40; }, width: function(d) { return d; }, height: 25, fill: "red", });
attr要素の設定に使われている、d, i等の引数はバインドされたデータを監視しています。
これらの動作のお陰で、ループ制御をする必要が無くなっています。
3, 表示の調整
上記のソースは、データセットを棒線グラフの用に表示させています。
データの値通りの幅で棒線が表示されていますが、svg描画領域を使い余してしまっています。
このような事態を解消するため、スケールという機能でsvgの表示領域で棒線の幅をリサイズします。
今回ですと、サンプルデータセットの最大値である 60 を svg領域幅の 500 にマッピングすることにより、描画領域を余すこと無く使うことが可能でしょう。
// スケールの定義 var scale = d3.scale.linear() .domain([0, d3.max(dataset)]) .range([0, svg_w]) .nice() // 棒線を生成 svg.selectAll("rect") .data(dataset) .enter() .append("rect") .attr({ x: 0, y: function(d, i) { return i * 40; }, width: function(d) { return scale(d); }, // scaleを使用し、幅を設定する height: 25, fill: "red", });
まずスケールを定義します。
線形を取り扱いますので、linear()関数を使用します。
スケールによるマッピングを行うためには、入力ドメイン(domain())と出力レンジ(range())の設定が必要となります。
※入力ドメイン ... 入力データの取りうる範囲のこと。
※出力レンジ ... 出力値の取りうる範囲のこと。
よって、domainには 0 ~ 60(データセットの最大値) の値を設定し、rangeには 0 ~ 500(svg領域の幅)を設定しています。
後は表示幅をscaleを使って設定してあげるだけです。
いかがでしたでしょうか。
大量のデータセットを扱う際も簡素なコードの記述と、柔軟なデータの可視化が可能です。
公式ドキュメントを見て分かるのですが、D3.jsは奥が深いライブラリです。
その奥深さを理解し、より本格的なグラフの描画に挑戦していきたいです。