SELECTED ENTRIES
CATEGORIES
ARCHIVES
SPONSORED LINK
MOBILE
qrcode
LINKS
PROFILE
OTHERS

07
--
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
--
>>
<<
--

Agata's Blog

MATLABやPythonとともにD3.jsを使ってデータ解析とデータビジュアライゼーションに挑戦する某エンジニアのBlog
<< ツールチップの作成方法 | main | 世界の総人口の推移を片対数グラフで描画する >>
データの変化をSVG要素に反映する
0
    JUGEMテーマ:JavaScript

    データの要素数や要素の順序が変化する様子を、アニメーションで可視化したい場合があります。今回はそんな場面で役に立つ、セレクションの仕組みについて見ていきます。

    d3.selectAll については、これまでにもしばしば使ってきました。しかしこれまでは、データの要素数や順序が変化しない、いわば「静的」なデータの可視化方法の説明にとどまっていました。データの要素数や要素の順序の変化に応じてDOM要素やSVG要素をダイナミックに操作するためには、D3.js では Enter, Update, Exit という3つの操作を行います。これらの操作は、最初はなかなか理解しにくいのですが、いったん動きを理解してしまうと、D3.js プログラミングの見通しが一気に広がります。

    Enter, Update, Exit という3つの操作によって、それぞれ以下の動作を実現します。
    • Enter:与えられたデータに対応するDOM/SVG要素がないときに、DOM/SVG要素を追加する
    • Update:データに応じてDOM/SVG要素を更新する
    • Exit:DOM/SVG要素に対応するデータがないときに、該当するDOM/SVG要素を削除する
    今回のサンプルプログラムでは、10〜60までの6個の数値を要素として持つ配列 (14行目の dataSet) をもとに、(3つの小円という有名なチュートリアル記事に敬意を表して) まず 6 個の円 (circle要素) を表示しますその後、3秒ごとにこの配列の要素の順番をシャッフルしたうえで要素数もランダムに変化させた配列 (60行目の data) を生成します。そのうえで、配列の要素数が変化していれば表示する円の数も変化させ、また各要素の順番が変化していればそれに応じて円の表示位置も変化させるようにします。

    サンプルページ



    プログラムは以下のとおりです。

    まず、18〜21行目で配列の各要素と circle 要素を紐づけています。紐づけには、data() メソッドのコールバック関数を定義することで、配列の各要素の値を使うよう指定しています。このブログにこれまで掲載したプログラムでは、data() メソッドのコールバック関数は特に指定していませんでした。それでも問題なく動いていたのは、data() メソッドはコールバック関数が指定されないと自動的に配列のインデックスによって各要素と紐づけるよう実装されているからなのです。そのうえで、23行目以降では Update, Enter, Exit 処理を順に実施しています。こうすることで、データの要素数や要素の順序の変化を、DOM要素やSVG要素に反映することができます。

    // 周囲にマージンを確保する
    var margin = {top: 40, right: 40, bottom: 80, left: 80};
    var width = 800 - margin.left - margin.right;
    var height = 500 - margin.top - margin.bottom;
    
    // SVGの表示領域を生成
    var svg = d3.select("#MyGraph")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + ", " + height/2 + ")");
    
    // データセットの初期値
    var dataSet = [10, 20, 30, 40, 50, 60];
    
    function update(data){
      // データセットをSVG要素に紐づける
      var circle = svg.selectAll("circle")
        .data(data, function(d){
          return d;
        });
      
      // Update: SVG要素を更新する
      circle.attr("class", "update")
        .transition()
        .duration(1000)
        .attr("cx", function(d,i){
          return 120*i;
        });
      
      // Enter: SVG要素を表示する
      circle.enter()
        .append("circle")
        .attr("class", "enter")
        .attr("cy", 0)
        .attr("cx", function(d, i){
          return 120*i;
        })
        .style("fill", "royalblue")
        .attr("r", 0)
        .transition()
        .duration(1000)
        .attr("r", function(d, i){
          return d;
        });
            
      // Exit: 不要になったSVG要素を削除する
      circle.exit()
        .transition()
        .duration(1000)
        .attr("r", 0)
        .remove();
    }
    
    // 初期状態
    update(dataSet);
    
    // 3秒ごとにdataSetの要素をシャッフルし要素数も変化させて表示を更新する
    setInterval(function() {
      var data = d3.shuffle(dataSet).slice(0, Math.floor(Math.random() * 7));
      console.log(data);
      update(data);
    }, 3000);
    

     
    このエントリーをはてなブックマークに追加
    | D3.js | 22:35 | comments(0) | - | - |
    スポンサーリンク