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
データの変化を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) | - | - |
    ツールチップの作成方法
    0
      JUGEMテーマ:JavaScript

      今回は、D3.jsを使ってグラフにツールチップ (Tooltip) を加える方法を見ていきます。

      ツールチップとは画面の表示要素の一種で、対象にマウスポインタを合わせたときに出現させる小さな領域のことを指します。データ可視化では、グラフ上のデータ点にマウスポインタを合わせたときに詳細な数値や注釈などを表示させる方法としてよく使われるテクニックです。このツールチップを D3.js で実現する方法はいくつかありますが、今回は div 要素を使って実現する方法を紹介します。それでは以前作成した散布図のプログラムをベースに、各データ点にマウスポインタを合わせるとデータの詳細がツールチップ上に表示されるように改修してみましょう。

      サンプルページ



      まず、html ファイルの <style>〜</style> タグ内に以下を追加します。
       

      <style>
        div.tooltip {
          position: absolute;
          text-align: center;
          width: 80px;
          height: 30px;
          padding: 2px;
          font: 14px sans-serif;
          background: lightsteelblue;
          border: 0px;
          border-radius: 8px;
          pointer-events: none;
        }
      </style>


      次に、以前のプログラムにツールチップ表示用のコードを追加します。具体的には、47行目から59行目を追加しています。ツールチップ表示用のイベントハンドラとして mouseover を、またツールチップ非表示用のイベントハンドラとして mouseout を、それぞれ使っています。
      var dataSet = [];
      
      // X,Y軸を表示できるようにグラフの周囲にマージンを確保する
      var margin = {top: 40, right: 40, bottom: 40, left: 100};
      var width = 800 - margin.left - margin.right;
      var height = 500 - margin.top - margin.bottom;
      
      // ツールチップ用の設定
      var div = d3.select("body")
        .append("div")
        .attr("class", "tooltip")
        .style("opacity", 0);
      
      d3.csv("./js/population.csv", function(error, dataSet){
        console.log(dataSet);
      
        // 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 + ", " + margin.top + ")");
          
        // X軸用のスケール関数を作成
        var xScale = d3.scale.linear()
          .domain([1920,2000])
          .range([0,width]);
      
        // Y軸用のスケール関数を作成
        var yScale = d3.scale.linear()
          .domain([0,130000])
          .range([height,0]);
      
        // 散布図を描画
        svg.selectAll("circle")
          .data(dataSet)
          .enter()
          .append("circle")
          .attr("r", 5)
          .attr("cx", function(d){
            return xScale(d.Year);
          })
          .attr("cy", function(d){
            return yScale(d.Population);
          })
          .attr("fill","rgba(0, 0, 255, 0.0)")
          .on("mouseover", function(d) { // マウスオーバー時にツールチップを表示
            div.transition()
              .duration(500)
              .style("opacity", 1.0);
            div.html(d.Year + "年
      " + d.Population + "千人") .style("left", (d3.event.pageX) + "px") .style("top", (d3.event.pageY - 28) + "px"); }) .on("mouseout", function(d) { // マウスアウトするとツールチップを非表示 div.transition() .duration(500) .style("opacity", 0.0); }) .transition() // 最初に散布図をアニメーションで表示 .delay(function(d,i){ return i*20; }) .duration(500) .attr("fill","rgba(0, 0, 255, 1.0)"); // Y軸を描画 svg.append("g") .attr("class", "axis") .call(d3.svg .axis() .scale(yScale) .orient("left") ); // X軸を描画 svg.append("g") .attr("class", "axis") .attr("transform", "translate(0," + height + ")") .call(d3.svg .axis() .scale(xScale) .orient("bottom") ); // 凡例 svg.append("g") .append("text") .attr("x", 20) .attr("y", 20) .text("[単位:千人]"); })

       
      このエントリーをはてなブックマークに追加
      | D3.js | 23:47 | comments(0) | - | - |
      【D3.js】 バラ曲線 (Rose curve) を描画する
      0
        JUGEMテーマ:JavaScript

        前回は D3.js を使って、プルダウンメニューで選択した数値によって変化するリサージュ曲線 (Lissajous curve) を描画しました。リサージュ曲線と同じように sin, cos を使った曲線として、バラ曲線 (Rose curve) があります。そこで今回は、このバラ曲線 (別名「正葉曲線」とも呼ばれます) を描画するプログラムを作成してみました。

        バラ曲線は、局座標表示で下式によって現される曲線です。

        r = sin((a/b)θ)

        とてもシンプルな方程式ですが、変数 a, b を変化させることで、驚くほど多様な変化を見せてくれます。

        前回リサージュ曲線を描画したときの html ファイルはそのまま流用して、JavaScript プログラムだけを下記のように変更します。変数 a, b を変化させて、ぜひバラ曲線が変化する様子を楽しんでみて下さい。

        サンプルページ



        // グラフの周囲にマージンを確保する
        var margin = {top: 40, right: 40, bottom: 80, left: 80};
        var width = 600 - 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 + ", " + margin.top + ")");
        
        var n = 2001;
        
        var dt = 20.0*Math.PI/n;
        var t = d3.range(0, 20.0*Math.PI, dt);
        var x = d3.range(n);
        var y = d3.range(n);
        
        // X軸のスケール関数を生成
        var x_scale = d3.scale.linear()
          .domain([-1, 1])
          .range([(width/2) - 200, (width/2) + 200]);
            
        // Y軸のスケール関数を生成
        var y_scale = d3.scale.linear()
          .domain([-1,1])
          .range([(height/2) - 200, (height/2) + 200]);  
          
        // (x,y) の軌跡を描画するための関数
        var line = d3.svg.line()
          .x(function(d, i){ return x_scale(x[i]);})
          .y(function(d, i) { return y_scale(y[i]);})
          .interpolate("linear");
        
        var polyline = svg.append('path')
          .attr("class", "line")
          .attr('stroke', 'black')
          .attr('stroke-width', '1')
          .attr('fill', 'transparent');
        
        // 初期値として a = 1, b = 1のグラフを描画
        update(1,1);
        updateLine();
        
        // 対象となる html 内のプルダウン要素を選択 
        var select_a = document.getElementById( 'listbox_a' );
        var select_b = document.getElementById( 'listbox_b' );
        
        var a = 1;
        var b = 1;
        
        // プルダウンメニューが更新されるとグラフを更新する
        select_a.onchange = function(){
          // プルダウンで選択されているoption要素を取得する
          var selectedItem = this.options[ this.selectedIndex ];
          a = selectedItem.value;
          update(a, b);
          updateLine();
        }
        
        select_b.onchange = function(){
          // プルダウンで選択されているoption要素を取得する
          var selectedItem = this.options[ this.selectedIndex ];
          b = selectedItem.value;
          update(a, b);
          updateLine();
        }
        
        // バラ曲線 (Rose curve) を計算する
        function update(a, b){
          for (var i = 0; i < n; i++){
            x[i] = Math.sin((a/b)*t[i])*Math.cos(t[i]);
            y[i] = Math.sin((a/b)*t[i])*Math.sin(t[i]);
          }
        }
        
        // バラ曲線を更新する
        function updateLine(){
          polyline
            .transition()
            .duration(1500)
            .ease("bounce")
            .attr('d', line(y));
        }
        
        // X軸を描画
        svg.append("g")
          .attr("class", "axis")
          .attr("transform", "translate(0," + height/2 + ")")
          .call(d3.svg
            .axis()
            .scale(x_scale)
            .orient("bottom")
          );
          
        // Y軸を描画
        svg.append("g")
          .attr("class", "axis")
          .attr("transform", "translate(" + width/2 + ",0)")
          .call(d3.svg
            .axis()
            .scale(y_scale)
            .orient("left")
          );
          
        

         
        このエントリーをはてなブックマークに追加
        | D3.js | 21:03 | comments(0) | - | - |
        【D3.js】 リサージュ曲線 (Lissajous curve) を描画する
        0
          JUGEMテーマ:JavaScript

          前回は D3.js を使って、プルダウンメニューで選択した数値に従って変化するグラフを作成しました。今回はその応用として、リサージュ曲線 (Lissajous curve) を描画してみます。

          リサージュ曲線とは、x = cos(at), y = sin(bt)t を変化させたときに x-y 平面上に描かれる (x, y) の軌跡です。今回は 2 つのプルダウンメニューを用意して、a, b それぞれの数値をユーザが選択すると、画面上のリサージュ曲線がそれに従って変化するページを作ってみます。

          まず準備として、html ファイルに以下を追加します。ここでは D3.js で描画するグラフの線として、幅2ピクセルのオレンジ色の線を指定しています。また、プルダウンメニューとして a, b それぞれ 1 〜 10 まで選択可能としました。

          サンプルページ


           

          <style> 
            .line{ 
              fill: none; 
              stroke: orange; 
              stroke-width: 2px; 
            } 
          </style> 

          (中略)

          <p>
          a = <select id="listbox_a">
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
            <option value="4">4</option>
            <option value="5">5</option>
            <option value="6">6</option>
            <option value="7">7</option>
            <option value="8">8</option>
            <option value="9">9</option>
            <option value="10">10</option>
          </select>
          , b = <select id="listbox_b">
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
            <option value="4">4</option>
            <option value="5">5</option>
            <option value="6">6</option>
            <option value="7">7</option>
            <option value="8">8</option>
            <option value="9">9</option>
            <option value="10">10</option>
          </select>
          </p>
          <svg id="MyGraph"></svg>


          ここで、対象となるプルダウンメニューを特定できるよう、id = "listbox_a", "listbox_b" として、それぞれのプルダウンに ID を設定しています。
          次に、プルダウンメニューで選択された a, b の値を取得して、リサージュ曲線を描画する D3.js プログラムを以下に示します。

          // X,Y軸を表示できるようにグラフの周囲にマージンを確保する
          var margin = {top: 40, right: 40, bottom: 80, left: 80};
          var width = 600 - 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 + ", " + margin.top + ")");
          
          var n = 800;
          
          var dt = 2.0*Math.PI/n;
          var t = d3.range(0, 2.0*Math.PI, dt);
          var x = d3.range(n);
          var y = d3.range(n);
          
          // X軸のスケール関数を生成
          var x_scale = d3.scale.linear()
            .domain([-1, 1])
            .range([(width/2) - 200, (width/2) + 200]);
              
          // Y軸のスケール関数を生成
          var y_scale = d3.scale.linear()
            .domain([-1,1])
            .range([(height/2) - 200, (height/2) + 200]);  
            
          // (x,y) の軌跡を描画するための関数
          var line = d3.svg.line()
            .x(function(d, i){ return x_scale(x[i]);})
            .y(function(d, i) { return y_scale(y[i]);})
            .interpolate("linear");
          
          var polyline = svg.append('path')
            .attr("class", "line")
            .attr('stroke', 'black')
            .attr('stroke-width', '1')
            .attr('fill', 'transparent');
          
          // 初期値として a = 1, b = 1のグラフを描画
          update(1,1);
          updateLine();
          
          // 対象となる html 内のプルダウン要素を選択 
          var select_a = document.getElementById( 'listbox_a' );
          var select_b = document.getElementById( 'listbox_b' );
          
          var a = 1;
          var b = 1;
          
          // プルダウンメニューが更新されるとグラフを更新する
          select_a.onchange = function(){
            // プルダウンで選択されているoption要素を取得する
            var selectedItem = this.options[ this.selectedIndex ];
            a = selectedItem.value;
            update(a, b);
            updateLine();
          }
          
          select_b.onchange = function(){
            // プルダウンで選択されているoption要素を取得する
            var selectedItem = this.options[ this.selectedIndex ];
            b = selectedItem.value;
            update(a, b);
            updateLine();
          }
          
          
          // リサージュ曲線 (Lissajous curve) を計算する
          function update(a, b){
            for (var i = 0; i < n; i++){
              x[i] = Math.cos(a*t[i]);
              y[i] = Math.sin(b*t[i]);
            }
          }
          
          // グラフを更新する
          function updateLine(){
            polyline
              .transition()
              .duration(300)
              .attr('d', line(y));
          }
          
          // X軸を描画
          svg.append("g")
            .attr("class", "axis")
            .attr("transform", "translate(0," + height/2 + ")")
            .call(d3.svg
              .axis()
              .scale(x_scale)
              .orient("bottom")
            );
            
          // Y軸を描画
          svg.append("g")
            .attr("class", "axis")
            .attr("transform", "translate(" + width/2 + ",0)")
            .call(d3.svg
              .axis()
              .scale(y_scale)
              .orient("left")
            );
          
          このエントリーをはてなブックマークに追加
          | D3.js | 19:20 | comments(0) | - | - |
          D3.js でギブス現象を見る
          0
            JUGEMテーマ:JavaScript

            今回は、プルダウンメニューで選択した数値によって変化するグラフを作成します。とはいっても、ただの練習のためだけのプログラムを書いても面白くないので、フーリエ変換 (Fourier transform) のギブス現象 (Gibbs phenomenon) が発生する様子を D3.js を使って可視化してみます。

            ギブス現象というのは、周期関数のフーリエ級数において、元の周期関数の不連続点付近でフーリエ級数の m 次部分和が大きく振動する現象のことを指します。

            言葉で書いてもなかなか分かりにくい現象なので、実際の例で見てみましょう。簡単のために元信号 f(x) を次のような x = π で不連続点を持つ矩形信号とします。


            この関数をフーリエ級数展開すると、次式のようになります。

            ではいよいよ、D3.js を使ってこのフーリエ級数展開の m 次部分和を描画してみます。加えて今回は、m の数値をプルダウンメニューから選択できるようにしてみます。こうすることで、m の値を増やすと次第に不連続点 (x = π) 周辺で振動が発生するギブス現象を可視化することができます。

            サンプルページ



            まず準備として、html ファイルに以下を追加します。ここでは D3.js で描画するグラフの線として、幅2ピクセルのオレンジ色の線を指定しています。また、プルダウンメニューとして m = 1 〜 100 まで選択可能としました。
             

            <style>
              .line{
                fill: none;
                stroke: orange;
                stroke-width: 2px;
              }
            </style>

            (中略)

            <p>
            m = <select id="listbox">
              <option value="1">1</option>
              <option value="2">2</option>
              <option value="3">3</option>
              <option value="4">4</option>
              <option value="5">5</option>
              <option value="10">10</option>
              <option value="20">20</option>
              <option value="50">50</option>
              <option value="100">100</option>
            </select>
            </p>
            <svg id="MyGraph"></svg>


            ここで、対象となるプルダウンメニューを特定できるよう、id = "listbox" として ID を設定しています。

            次に、プルダウンメニューで選択された m の値を取得して、フーリエ級数展開の m 次部分和を描画する D3.js プログラムを以下に示します。44 行目でまず html 内のプルダウン要素を選択しています。そのうえで、47 行目でこのプルダウンメニュー選択の更新を検知して、グラフを更新しています。具体的には、プルダウンにより選択された m の値を 49, 59 行目で取得しています。そのうえで 56 行目以降で定義する update() 関数でフーリエ級数展開の m 次部分和を計算し、70 行目以降で定義する updateLine() 関数でグラフを更新しています。

            // X,Y軸を表示できるようにグラフの周囲にマージンを確保する
            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 + ", " + margin.top + ")");
            
            var dx = 2.0*Math.PI/800.0;
            var x = d3.range(0,2.0*Math.PI,dx);
            var y = d3.range(0,x.length);
            
            // 時間軸のスケール関数を生成
            var x_scale = d3.scale.linear()
              .domain([0, 2.0*Math.PI])
              .range([0, width]);
                
            // 縦軸のスケール関数を生成
            var y_scale = d3.scale.linear()
              .domain([-2,2])
              .range([height, 0]);  
              
            // データごとに折れ線グラフを描画するための関数
            var line = d3.svg.line()
              .x(function(d, i){ return x_scale(x[i]);})
              .y(function(d, i) { return y_scale(y[i]);})
              .interpolate("linear");
            
            var polyline = svg.append('path')
              .attr("class", "line")
              .attr('stroke', 'black')
              .attr('stroke-width', '1')
              .attr('fill', 'transparent');
            
            // 初期値として m = 1 のグラフを描画
            update(1);
            updateLine();
            
            // 対象となる html 内のプルダウン要素を選択 
            var select = document.getElementById( 'listbox' );
            
            // プルダウンメニューが更新されるとグラフを更新する
            select.onchange = function(){
              // プルダウンで選択されているoption要素を取得する
              var selectedItem = this.options[ this.selectedIndex ];
              var value = selectedItem.value;
              update(value);
              updateLine();
            }
            
            // フーリエ級数展開の m 次部分和を計算する
            function update(k){
              for (var i = 0; i < k; i++){
                for (var j = 0; j < x.length; j++){
                  if (i == 0){
                    y[j] = (4/Math.PI)*(1/(2*(i+1)-1))*Math.sin((2*(i+1)-1)*x[j]);
                  }
                  else{
                    y[j] = y[j] + (4/Math.PI)*(1/(2*(i+1)-1))*Math.sin((2*(i+1)-1)*x[j]);
                  }
                }
              }
            }
            
            // グラフを更新する
            function updateLine(){
              polyline
                .transition()
                .duration(300)
                .attr('d', line(y));
            }
            
            // X軸を描画
            svg.append("g")
              .attr("class", "axis")
              .attr("transform", "translate(0," + height/2 + ")")
              .call(d3.svg
                .axis()
                .scale(x_scale)
                .orient("bottom")
              );
              
            // Y軸を描画
            svg.append("g")
              .attr("class", "axis")
              .call(d3.svg
                .axis()
                .scale(y_scale)
                .orient("left")
              );
              
            

             
            このエントリーをはてなブックマークに追加
            | D3.js | 07:51 | comments(0) | - | - |
            【D3.js】 フォースレイアウトの作成例
            0
              JUGEMテーマ:JavaScript

              D3.js では力学モデルに基づく描画をおこなうフォースレイアウト (force layout) が準備されています。フォースレイアウトを使うと、ノードとリンクによって表現されたグラフ (Graph) 形式のデータをアニメーションとして可視化することができます。

              フォースレイアウトでは、d3.layout.force() を使って、ノード間の距離やノード間に働く力、リンクの伸び縮みのしやすさなどを設定して、動きのあるデータ可視化を実現することができます。フォースレイアウトで設定できる主なパラメータは、以下のとおりです。
               
              パラメータ 意味
              .node ノードを指定
              .links ノード間を結ぶリンクを指定
              .size 表示領域のサイズを指定
              .linkDistance リンクの長さを指定
              .linkStrength リンクの伸び縮みのしやすさを指定
              .gravity 表示領域の中心に引き寄せる重力の強さを指定
              .charge ノード間の引力/斥力を指定

              サンプルページ


              なお、サンプルページのプログラムでは、リンクの線幅や色を指定するために css (あるいは html ファイルの <style type="text/css"> 〜 </style>) に次の記述を追加しています。
               
                .line{
                  fill: none;
                  stroke: orange;
                  stroke-width: 2px;
                }

              サンプルプログラムは、以下のとおりです。
               
              var width = 800;
              var height = 500;

              var color = d3.scale.category20(); //D3.jsが用意する標準10色

              // フォースレイアウトの元となるデータを作成
              var dataSet = {
                nodes : [],
                links : []
              }

              var N1 = 8;

              for(var k=0; k<N1; k++){
                var st = "Node"+k;
                dataSet.nodes.push({name : st});
              }

              for(var k=1; k<N1; k++){
                dataSet.links.push({source : k-1, target : k});
              }

              // SVGの表示領域を生成
              var svg = d3.select("#MyGraph")
                .attr("width", width)
                .attr("height", height)

              // フォースレイアウトの設定
              var force = d3.layout.force()
                .nodes(dataSet.nodes)
                .links(dataSet.links)
                .size([width, height])
                .linkDistance(80)
                .linkStrength(1)
                .gravity(0.01)
                .charge(-20)
                .start()
                
              // ノード間のリンクを描画
              var link = svg.selectAll("line")
                .data(dataSet.links)
                .enter()
                .append("line")
                .attr("class", "line")

              // ノードを描画  
              var node = svg.selectAll("circle")
                .data(dataSet.nodes)
                .enter()
                .append("circle")
                .attr("r", 20)
                .call(force.drag)

              // ノードの名前をテキストで表示
              var nodeText = svg.selectAll("text")
                .data(dataSet.nodes)
                .enter()
                .append("text")

              // フォースレイアウトを描画  
              force.on("tick", function(){
                link
                  .attr("x1", function(d){return d.source.x;})
                  .attr("y1", function(d){return d.source.y;})
                  .attr("x2", function(d){return d.target.x;})
                  .attr("y2", function(d){return d.target.y;})
                node
                  .attr("cx", function(d){return d.x;})
                  .attr("cy", function(d){return d.y;})
                  .style("fill", function(d,i){
                    return color(i%20);
                  })
                  .style("fill-opacity", 0.5)
                nodeText
                  .text(function(d){return d.name;})
                  .attr("x", function(d){return d.x+25;})
                  .attr("y", function(d){return d.y-5;})
              })
              このエントリーをはてなブックマークに追加
              | D3.js | 22:48 | comments(0) | - | - |
              D3.js で六角形を描く (hexbin) その4
              0
                JUGEMテーマ:JavaScript

                これまで 3 回にわたって、hexbin プラグインを使った六角形の描画方法について見てきました。今回は応用編として、hexbin() メソッドによるヒートマップがゆっくりと作成されるアニメーションを作ってみます。また、せっかくなのでヒートマップの色もランダムに変わるようにします。

                下のサンプルプログラムでは、まず基本となる色の選択肢を作成しています (5行目)。そのうえで、この選択肢のなかから 1 色をランダムに取り出して、白からその色へと変化するグラデーションを定義します (8〜12行目)。ちなみにここでは、Floor関数の Math.floor() と 0〜1 の範囲の乱数を生成する Math.random() を組み合わせて、Math.floor(Math.random() * m) とすることで、0 から m-1 までの整数をランダムに生成しています。

                そのうえで、ヒートマップを構成するひとつひとつの六角形を、初期位置 (39行目) からそれぞれのあるべき位置 (52行目) まで時間差をつけて移動させています。移動の動き方として .ease("bounce") で bounce を指定することで、上から落ちてきた六角形がコツンと何かに反射してバウンドしながら止まるような効果を与えています。

                サンプルページ



                // SVGのサイズを指定
                var width = 800;
                var height = 500;
                
                var baseColor = ["royalblue", "orange", "lawngreen", "fuchsia", "goldenrod", "yellow"];
                
                // 白から、選択された色へと変化するグラデーション
                var color = d3.scale
                  .linear()
                  .domain([0, 20])
                  .range(["white", baseColor[Math.floor(Math.random()*6)]])
                  .interpolate(d3.interpolateLab);
                  
                // SVGの幅と高さを指定
                var svg = d3.select("#MyGraph")
                  .attr("width", width)
                  .attr("height", height)
                  .append("g");
                
                // ランダムに400個のデータ点を配置
                var points = [];
                for (var i=0; i<=800; i++){
                  points.push([d3.random.normal(width/2, 80)(), d3.random.normal(height/2, 80)()]);
                }
                
                // 半径20pxの六角形を定義    
                var hexbin = d3.hexbin()
                  .radius(20);
                
                // 領域内にデータ点を含む箇所に六角形を描画
                svg.append("g")
                  .attr("class", "hexagon")
                  .selectAll("path")
                  .data(hexbin(points))
                  .enter()
                  .append("path")
                  .attr("d", hexbin.hexagon())
                  .attr("transform", function(d,i) {
                    return "translate(" + d.x + "," + -50 + ")"; // 初期位置
                  })
                  .style("fill", function(d){
                    if (d.length > 20) return color(20);
                    else return color(d.length); // 領域内のデータ点数 (d.length) によってグラデーション
                  })
                  .transition() // 六角形がぱらぱらと落ちてくるアニメーション
                  .delay(function(d,i){
                    return i*50;
                  })
                  .duration(1500)
                  .ease("bounce")
                  .attr("transform", function(d,i) {
                    return "translate(" + d.x + "," + d.y + ")";
                  });
                

                このエントリーをはてなブックマークに追加
                | D3.js | 22:04 | comments(0) | - | - |
                D3.js で六角形を描く (hexbin) その3
                0
                  JUGEMテーマ:JavaScript

                  前回に引き続き、hexbin プラグインを使ってもう少し遊んでみます。

                  これまで 2 回にわたって、hexbin() メソッドを使った六角形の描画方法についてみてきました。でも、D3.js の醍醐味といえば、やっぱり動的なビジュアル表現ですよね。そこで今回は、マウスの位置によってリアルタイムに変化するヒートマップを作ってみます。

                  下のサンプルプログラムでは、まず、ユーザ画面上でマウスが動くとマウスの位置座標を取得します (18〜19行目) 。マウスの位置座標の取得方法については、以前の記事を参照してください。次に、取得したマウス位置を中心とする正規分布に従って、平面上に800個のデータ点を生成ます (22〜27行目) 。そして最後に、データ点の密度をヒートマップとしてリアルタイムに表示しています。

                  サンプルページ



                  // SVGのサイズを指定
                  var width = 800;
                  var height = 500;
                  
                  // 白からロイヤルブルー(royalblue)へのグラデーション
                  var color = d3.scale
                    .linear()
                    .domain([0, 20])
                    .range(["white", "royalblue"])
                    .interpolate(d3.interpolateLab);
                    
                  // SVGの幅と高さを指定
                  var svg = d3.select("#MyGraph")
                    .attr("width", width)
                    .attr("height", height);
                  
                  // マウスの位置座標を取得
                  svg.on("mousemove", function(){
                    var position = d3.mouse(this);
                    
                    // ランダムに800個のデータ点を配置
                    var points = [];
                    for (var i=0; i<=800; i++){
                      points.push(
                        [d3.random.normal(position[0], 80)(), d3.random.normal(position[1], 80)()]
                      );
                    };
                  
                    // 半径20pxの六角形を定義    
                    var hexbin = d3.hexbin()
                      .radius(20);
                       
                    d3.selectAll(".hexagon").remove();
                      
                    // 領域内にデータ点を含む箇所に六角形を描画
                    var heatmap = svg.append("g")
                      .attr("class", "hexagon")
                      .selectAll("path")
                      .data(hexbin(points))
                      .enter()
                      .append("path")
                      .attr("d", hexbin.hexagon())
                      .attr("transform", function(d,i) {
                        return "translate(" + d.x + "," + d.y + ")";
                      })
                      .style("fill", function(d){
                        if (d.length > 20) return color(20);
                        else return color(d.length); // 領域内のデータ点数 (d.length) によってグラデーション
                      });
                  });
                  
                   
                  このエントリーをはてなブックマークに追加
                  | D3.js | 23:57 | comments(0) | - | - |
                  D3.js で六角形を描く (hexbin) その2
                  0
                    JUGEMテーマ:JavaScript

                    前回につづいて、hexbin を使った基本的なヒートマップの作り方を紹介します。

                    前回は hexbin() メソッドを使って、平面を六角形で分割したうえで、個々の六角形の領域内にデータ点がある場合に六角形を描画していました。今回は、個々の六角形の色を領域内のデータ点数によって変化させることで、ヒートマップを作製します。

                    データ点数によって色を変化させるには、2 つの色の間を補完する interpolateLabメソッドを使います (⇒ 関連記事)。ちなみに今回は、白とロイヤルブルー (royalblue) の間で補完してみました。HTTP で使えるカラーコードについては、ここなどを参照してください。

                    また、今回は個々の六角形を分かりやすく表示するため、css (あるいは html ファイルの <style>〜</style>) に以下の記述を加えて、六角形の枠線を灰色で描画することにしました。
                     
                      .hexagon {
                        stroke: #c0c0c0;
                        stroke-width: 1.5px;
                      }

                    前回は平面上にランダムにサンプル点を配置していましたが、今回はヒートマップ図の雰囲気を出すために、サンプル点の密度が平面の中心位置をピークとする正規分布となるようにサンプル点を配置することにしました。サンプル点の配置には、D3.js  の d3.random.normal() メソッドを使っています。このメソッドは、d3.random.normal(m, s)() とすると平均が m、分散が s の正規分布に従う乱数を生成します。

                    サンプルページ


                     
                    // SVGのサイズを指定
                    var width = 800;
                    var height = 500;
                    
                    // 白からロイヤルブルー(royalblue)へのグラデーション
                    var color = d3.scale
                      .linear()
                      .domain([0, 20])
                      .range(["white", "royalblue"])
                      .interpolate(d3.interpolateLab);
                      
                    // SVGの幅と高さを指定
                    var svg = d3.select("#MyGraph")
                      .attr("width", width)
                      .attr("height", height)
                      .append("g");
                    
                    // ランダムに400個のデータ点を配置
                    var points = [];
                    for (var i=0; i<=800; i++){
                      points.push([d3.random.normal(width/2, 80)(), d3.random.normal(height/2, 80)()]);
                    }
                    
                    // 半径20pxの六角形を定義    
                    var hexbin = d3.hexbin()
                      .radius(20);
                    
                    // 領域内にデータ点を含む箇所に六角形を描画
                    svg.append("g")
                      .attr("class", "hexagon")
                      .selectAll("path")
                      .data(hexbin(points))
                      .enter()
                      .append("path")
                      .attr("d", hexbin.hexagon())
                      .attr("transform", function(d,i) {
                        return "translate(" + d.x + "," + d.y + ")";
                      })
                      .style("fill", function(d){
                        if (d.length > 20) return color(20);
                        else return color(d.length); // 領域内のデータ点数 (d.length) によってグラデーション
                      });
                    
                     
                    このエントリーをはてなブックマークに追加
                    | D3.js | 09:51 | comments(0) | - | - |
                    D3.js で六角形を描く (hexbin)
                    0
                      数値データをヒートマップで表現しようとしたときなどで、六角形を描画したくなることがあります。D3.js を使って六角形を描画する関数を一から自分で作ってみても良いのですが、幸いなことに D3.js には hexbin という六角形を描画するためのプラグインが用意されています。今回はこの hexbin の基本的な使い方を紹介します。

                      まずは d3.hexbin.v0.min.js をダウンロードして、html ファイルに下記の 1 行を追加して d3.min.js と同じように読み込ませます。
                       
                      <script type="text/javascript" src="js/d3.hexbin.v0.min.js"></script>

                      また、六角形の色や枠線を指定するために css (あるいは html ファイルの <style>〜</style>) に次の記述を追加しておきます。
                       
                        .hexagon {
                          fill: steelblue;
                          stroke: white;
                          stroke-width: 1.5px;
                        }

                      それでは下記のプログラムを使って、hexbin プラグインの動作を見てみましょう。

                      サンプルページ



                      インターネットで検索しても日本語の説明がなかなか見つからない hexbin プラグインですが、このプログラムを見てもらえれば基本的な使い方は理解できると思います。hexbin プラグインはまず、hexbin() メソッドを使って、指定された半径 (この例では 20 px) の六角形で平面を分割します (18〜19行目) 。次に、分割された個々の六角形について、その領域内にデータ点を含む場合は六角形を描画し、データ点を含まない場合は何も描画しないという処理を行います (22〜31行目) 。

                      この例では、データ点としてランダムに配置した 400 個の点を使用しました (12〜15行目) 。ページをリロードするたびにデータ点の位置が変わるため、描画される六角形の位置も変化します。
                       
                      // SVGのサイズを指定
                      var width = 800;
                      var height = 500;
                      
                      // SVGの幅と高さを指定
                      var svg = d3.select("#MyGraph")
                        .attr("width", width)
                        .attr("height", height)
                        .append("g");
                      
                      // ランダムに400個のデータ点を配置
                      var points = [];
                      for (var i=0; i<=400; i++){
                        points.push([width * Math.random(), height * Math.random()]);
                      }
                      
                      // 半径20pxの六角形を定義    
                      var hexbin = d3.hexbin()
                        .radius(20);
                      
                      // 領域内にデータ点を含む箇所に六角形を描画
                      svg.append("g")
                        .attr("class", "hexagon")
                        .selectAll("path")
                        .data(hexbin(points))
                        .enter()
                        .append("path")
                        .attr("d", hexbin.hexagon())
                        .attr("transform", function(d,i) {
                          return "translate(" + d.x + "," + d.y + ")";
                        });
                      
                       
                      このエントリーをはてなブックマークに追加
                      | D3.js | 23:29 | comments(0) | - | - |