Chapter1

D3.js in Actionの1章の勉強ノートです。

これまで、d3.v3.min.jsを以下のようにロードしていましたが、nvd3のinitialize_javascriptでこれが不要になりました。

ただし、kernelはPython2を使用するため、sageは%load_extでロードします。

<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
In [1]:
%load_ext sage
from IPython.core.display import HTML
from string import Template
import json
import nvd3
nvd3.ipynb.initialize_javascript(use_remote=True)
loaded nvd3 IPython extension
run nvd3.ipynb.initialize_javascript() to set up the notebook
help(nvd3.ipynb.initialize_javascript) for options

要素の選択とデータバインド

要素の選択には、select, selectAll関数が用意されいます。要素の選択パターンはjQueryと同じです。

  • #<要素のID>: 要素のIDで選択
  • <タグ>: HTMLタグ名で選択
  • .<クラス>: 要素のclass名で選択

リスト1.1をjupyterでためす

In [2]:
%%html
<div id="someDiv" style="width:200px;height:100px;border:black 1px solid;">
<input id="someCheckbox" type="checkbox" />
</div>

javascriptのmagic関数をこんな形で使うことは考えたことがなかったので、とても重宝します。

通常はhtmlのscriptタグかブラウザのconsoleでしかjavascriptを操作できないのですが、 jupyterノートブックでは、このように結果を確認しながら処理を進めることができます。

以下の例では、以下の処理をします。

  • divタグのid=someDivのstyleをborder="5px darkgray dashed"に変更
  • divタグのid=someDivのidをnewIDに変更
  • inputタグのid=someCheckboxの変数checkedをtrueにセット
In [3]:
%%javascript
d3.select("#someDiv").style("border", "5px darkgray dashed");
d3.select("#someDiv").attr("id", "newID");
d3.select("#someCheckbox").property("checked", true);

Chromeの「表示」>「開発/管理」から「デベロッパーツール」を開くと上記の処理でどのようにHTMLが変化したか確認することができます。

Developer-Tool

データバインディング

次に「データバインディング」を使ってみます。

データバインディングは、選択された要素に配列で与えられた個々のデータを割り当てる機能です。

以下の例では、4個のdivにsomeDataの4つの文字列をバインドします。

  • html関数のfunction (d)で個々のデータが渡されます

次の行を実行すると、「データバインディングの例です」と表示し、%%javascriptを実行すると

Test1
Test2
Test3
Test4
が追加されます。

In [4]:
%%HTML
<div id="ex2">
データバインディングの例です。
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</div>
データバインディングの例です。
In [5]:
%%javascript
var someData = ["Test1", "Test2", "Test3", "Test4"];

d3.select("#ex2").selectAll("div")
    .data(someData)
    .append("div")
    .html(function (d) { return d;});

D3.js のHello Worldを試す

D3アプリのHello Worldとして、円を動かす例が紹介されているので、これをjupyterで試してみます。

最初にHTMLを定義します。

In [6]:
%%HTML
<div id="ex3">
    <svg style="width:300px;height:300px;border:1px lightgray solid;" />
</div>

SVGキャンパスに様々な図形を追加します。

In [7]:
%%javascript
d3.select("#ex3").select("svg")
  .append("line")
      .attr("x1", 20).attr("y1", 20)
      .attr("x2",250).attr("y2",250)
      .style("stroke", "black").style("stroke-width","2px");
d3.select("svg")
  .append("text")
      .attr("x",20).attr("y",20)
      .text("HELLO");
d3.select("svg")
  .append("circle")
      .attr("r", 20).attr("cx",20).attr("cy",20)
      .style("fill","red");
d3.select("svg")
  .append("circle")
      .attr("r", 50).attr("cx",250).attr("cy",250)
      .style("fill","lightblue");
d3.select("svg")
  .append("text")
      .attr("x",250).attr("y",250)
      .text("WORLD");

SVGでは表示順序で上書きするので、HELLOの文字が赤い丸に潰されています。

次の例は、アニメーションです。 これもtransitionとdurationを使ってとても簡単に実現しています。

In [8]:
%%HTML
<div id="ex4">
    <svg style="width:300px;height:300px;border:1px lightgray solid;" />
</div>
In [9]:
%%javascript
d3.select("#ex4").select("svg")
    .append("circle")
        .attr("r", 20).attr("cx",20).attr("cy",20).style("fill","red");
d3.select("#ex4").select("svg")
    .append("text")
        .attr("id", "a").attr("x",20).style("opacity", 0).attr("y",20)
        .text("HELLO WORLD");
d3.select("#ex4").select("svg")
    .append("circle")
        .attr("r", 50).attr("cx",250).attr("cy",250).style("fill","lightblue");
d3.select("#ex4").select("svg")
    .append("text")
        .attr("id", "b").attr("x",250).attr("y",250).style("opacity", 0).text("Uh, hi.");

d3.select("#a").transition().delay(1000).style("opacity", 1);
d3.select("#b").transition().delay(3000).style("opacity", .75);

d3.select("#ex4").selectAll("circle").transition().duration(4000).attr("cy", 150);
In [ ]: