dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

[JavaScript]D3.jsを触ってみた

秋のJavaScript祭りに参加しました。

その中のセッションで紹介されていたD3.jsというJavaScriptライブラリを触ってみたのでちょいとメモ。

セッションスライドはこちらです。

D3.jsでのデータビジュアライゼーション -人口統計データから使い方を学ぶ-

インストール

D3用のプロジェクトディレクトリ(ここではd3_sample)を作り
その下にD3.jsをインストールします。

コードは公式サイトからzip形式でダウンロードすることもできますが
今回はGitHubから。

git clone git@github.com:mbostock/d3.git

プロジェクトディレクトリの下にd3というディレクトリが作成されてるはずです。

触ってみる

日本語の丁寧なチュートリアルがあるので、それを一通り読むと大体理解できそうです。

http://ja.d3js.info/alignedleft/tutorials/d3/

ここではd3がどんなものかを確認するために、プロジェクトディレクトリ直下にindex.htmlを作成し、以下を記述します。
(コードは散布図の描画のコード)

<!DOCTYPE html>
<html lang="en">
    <head>
       <meta charset="utf-8">
       <title>D3 Test</title>
       <script type="text/javascript" src="d3/d3.js"></script>
       <style>
            div.bar {
                display: inline-block;
                width: 20px;
                height: 75px;   /* この数値は実行時に上書きされます */
                background-color: teal;
                margin-right: 2px;
            }
        </style>
   </head>
    <body>
        <script type="text/javascript">
       var dataset = [
           [   5,   20 ],
           [ 480,   90 ],
           [ 250,   50 ],
           [ 100,   33 ],
           [ 330,   95 ],
           [ 410,   12 ],
           [ 475,   44 ],
           [  25,   67 ],
           [  85,   21 ],
           [ 220,   88 ]
       ],
           w = 500,
           h = 100;
       // SVG 要素の生成
       var svg = d3.select("body")
           .append("svg")
           .attr("width", w)
           .attr("height", h);
       // 円の描画
       svg.selectAll('circle')
           .data(dataset)
           .enter()
           .append('circle')
           .attr('cx', function(d) {
               return d[0];
           })
           .attr('cy', function(d) {
               return d[1];
           })
           .attr('r', function(d) {
               return Math.sqrt(h - d[1]);
           });

       // ラベルの描画
       svg.selectAll('text')
           .data(dataset)
           .enter()
           .append('text')
           .text(function(d) {
               return d[0] + ',' + d[1];
           })
           .attr('x', function(d) {
               return d[0];
           })
           .attr('y', function(d) {
               return d[1];
           })
           .attr("font-family", "sans-serif")
           .attr("font-size", "11px")
           .attr("fill", "red");
       </script>
    </body>
</html>

保存したら、結果を確認するためにローカルサーバーを立ち上げます。

ここ にも書いてますが、pythonを使うと簡単に実行できます。

# python 2.X
python -m SimpleHTTPServer 8888 &

# python 3
python -m http.server 8888 &

実行したら http://localhost:8888/ にアクセス。
すると、こんな形で散布図が表示されます。

f:id:dackdive:20140908005255p:plain

ポイントだけメモ

svg.selectAll('circle')
    .data(dataset)
    .enter()
    .append('circle')

一番重要なこととして、data(dataset)は受け渡されたデータの数を数え、
それ以降のメソッドはデータを1つずつに対してforループのように実行されます。

また、その後の

.attr('cx', function(d) {
    return d[0];
})

などは要素に属性を指定してますが、ここで呼ばれている無名関数function(d)dにはデータが1件ずつ渡されます。
dは変数名なのでなんでもいいんですが慣習的にdが多いそう。

selectAllはセレクト対象要素(ここではsvg)の中から指定した要素をすべて取得するメソッドですが、
この時点ではcircle要素は1つも存在していません
ですが、それをあまり気にする必要はないとのこと。

なぜなら、その後のenter()メソッドは、最初に DOM を調べ、次にdata(dataset)によって受け渡されたデータを調べます。
もし該当する DOM 要素の数よりデータの値の個数が多い場合は、enter() は新規に要素を追加するからです。

おわりに

というわけで、今回試したチュートリアルのグラフはかなり簡単なものですが
複雑なグラフでのプロットとかも簡単に行えそうで、便利そうだなーと感じました。

メソッドチェインで書けるおかげでコードの見通しも良くなっている気がします。