kansiho's blog

ruby, python, javascript. Rails, wordpress, OpenCV, heroku...

はじめてのグラフの描画 - D3.js を利用してDOM操作・棒グラフを作成してみる

f:id:serendipity4u:20170726232129p:plain

D3.jsはとても便利なグラフ用ライブラリです。データに応じたDOM要素の扱いがとても簡単にできます。

導入

CDNが利用可能です。

<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>

チュートリアルは  D3 入門 | スコット・マレイ | alignedleft が大変わかりやすいです。以下はこのチュートリアルに沿っています。

D3によるDOM要素の操作: select()

jQueryのようなチェーン構文で簡単にDOMを操作することができます。たとえば、 <body> の中に <p> タグで文章を挿入するなら、こうやります。

//CSS セレクタ構文を使って DOM の中から要素を一つ選択
d3.select("body").append("p").text("追加された文章"); // body要素の中の最後のp要素の次に追加する

データ視覚化とは、データをビジュアルにマッピングする(対応付ける)過程のことです。データが入力であり、ビジュアルのプロパティ(属性)が出力となります。例えば数字が大きくなるほど棒を高くしたり、データがあるカテゴリに属する場合に明るい色を用いたりすることです。マッピングのルールを決めるのは自分自身です。

バインディングには、enter() というメソッドを利用します。このメソッドは、 最初に DOM を調べ、次に受け渡されたデータを調べ、もし該当する DOM 要素の数よりデータの値の個数が多い場合は、enter() は新規にプレースホルダ要素を生成し、そのプレースホルダへの参照をチェインの次のステップに渡します。 変数datasetに渡した値が10個ならenter以下のメソッドチェーンが10回繰り返され、200個なら200回繰り返されます。

.graphクラスをselect()して、データをバインディングしてみようと思います。

f:id:serendipity4u:20170726234126p:plain

うまくいきました!

f:id:serendipity4u:20170726234130p:plain

メソッドチェーンにstyle項目を足してみます。.style("color", "red"); の部分です。

f:id:serendipity4u:20170726234704p:plain

f:id:serendipity4u:20170726234700p:plain

赤色になりました!次は条件分岐をしてみましょう。styleメソッドの第二引数をデータセットのうちのひとつdを扱う無名関数にしてみます。style()を以下のように変更します。

.style("color", function(d) {
    if (d > 20) {
      return "red";
    } else {
      return "green";
    }
  }

21以上の数字が赤色、20以下が緑色に表示されました!

f:id:serendipity4u:20170726235208p:plain

D3 を使って要素にクラスを追加するには selection.attr()を用います。たとえば、currentクラスをある要素に追加するには、

(目的のオブジェクト).attr("class", "current")

とします。これを利用して棒グラフを作成します。まず棒グラフの基礎となる長方形を作るために、.barクラスを定義します。 この.barクラスを、データごとに出力するのですが、高さをデータの量によって変えよう(return d + "px";のところ)という発想です。

<style>
.bar {
  display: inline-block;
  width: 20px;
  background-color: blue;
}
</style>

var dataset =  [ 1, 5, 15, 25, 35 ]; // 例
d3.select(".graph").selectAll("div")
  .data(dataset) // データを渡す
  .enter() // DOM 要素とデータを比較
  .append("div")
  .attr("class", "bar")
  .style("height", function(d) {
       return d + "px";
  });
});
</script>

とすることで、データの量に応じて、グラフの高さを変えることができます。

f:id:serendipity4u:20170727000612p:plain

height の箇所を、d*5 として返してあげると、差が強調されて、もっとわかりやすくなります。さらに、.barどうしもmargin-leftを追加して調整します。

f:id:serendipity4u:20170727000806p:plain

データの量を反映して長さを変更する箇所を、height ではなくwidthにして、 display: blockcssプロパティを変更してあげると、横グラフになりますね。

f:id:serendipity4u:20170727001044p:plain

<script>
$(document).on('turbolinks:load', function() {
var dataset =  [ 1, 5, 15, 25, 35 ]; // 例
d3.select(".graph").selectAll("div")
  .data(dataset) // データを渡す
  .enter() // DOM 要素とデータを比較
  .append("div")
  .attr("class", "bar")
  .style("width", function(d) { // 変更箇所. height から width
       return d * 5 + "px";
  });
});
</script>
<style>
.bar {
  display: block; // 変更箇所
  margin-bottom: 10px; // 変更箇所
  height: 20px;
  background-color: blue;
}
</style>
<div class='graph' style='height:500px; width:100%; padding:30px;'>
</div>

次回はもう少し複雑なデータを、svgで描画するところをやりたいと思います。 直感的で楽しいですね、D3js…

参考

D3 入門 : データ型 - スコット・マレイ - alignedleft

pgpg-sou.hatenablog.com

d3js.org