Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

D3によるデータビジュアライゼーション 2013.09.13

  • Be the first to comment

D3によるデータビジュアライゼーション 2013.09.13

  1. 1. ウルシステムズ株式会社 http://www.ulsystems.co.jp mailto:info@ulsystems.co.jp Tel: 03-6220-1420 Fax: 03-6220-1402 ULS Copyright © 2013 UL Systems, Inc. All rights reserved. D3によるデータビジュアライゼーション 2013/9/13 講師役:近棟 稔
  2. 2. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. はじめに 1 Webブラウザーの進歩は速く、パソコンやスマートフォンやタブレットや電子書籍リーダーに搭載されている多くのモダンなWebブラウ ザーは、既にインラインSVGをサポートしています。インラインSVGとは、HTML内にSVGタグを埋め込むことにより、その領域内にベ クター形式の図形を描画することの出来る仕様です。(SVG: Support Vector Graphics) このインラインSVGが多くのデバイスで利用可能になったことにより、従来のHTML表現の限界は大きく引き上げられました。 一方、データビジュアライゼーション分野が発展・普及してきました。データによっては、単に数値を羅列しても人間が直感的にそ のデータの傾向を把握することが難しいことがあります。そのため、従来から棒グラフや円グラフ、散布図といった標準的なデータの 表現方法が要所要所で用いられてきています。データビジュアライゼーションの分野では、既存のデータ表現に加えて、様々な表 現方法が考案され、それが実際に用いられるようになって来ています。 そして現在、データビジュアライゼーションとインラインSVGが融合し、Webページ上でインタラクティブに操作可能なデータビジュアラ イゼーション方式が登場しました。可視化したいデータをJavaScriptで保持し、そのデータをJavaScriptで加工し、それをJavaScri ptからインラインSVGを用いて描画します。描画されたものをマウスで操作すると、見たい角度からデータを見たり、加工したりする 事が出来るようになります。 このような、HTML上でインタラクティブなデータビジュアライゼーションを行うライブラリーとして有名になったのが、D3(Data-Driven Documents)です。 この勉強会ではSVGの基礎からはじめ、D3を用いたデータビジュアライゼーション方法の一部をご紹介します。D3を用いたデモンス トレーションは以下のURLに沢山掲載されていますので、勉強会に参加されない方も、「今ならWebブラウザー上でこんな事が可 能になっている」という事を知ることが出来ると思います。 (キーの←や→でスライドがめくれます) http://mbostock.github.io/d3/talk/20111018/#3 http://bost.ocks.org/mike/ https://github.com/mbostock/d3/wiki/Gallery
  3. 3. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. インラインSVG入門:Web画面にSVGで点を描く  インラインSVGを使えば、HTMLを記述するのと同じ要領で画面に点を描画できます。 2 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <style type="text/css">svg {border: dashed 1px blue;}</style> </head> <body> <svg width="100" height="100"> <circle cx="50" cy="50" r="10"></circle> </svg> </body> </html> ここがインラインSVGの部分
  4. 4. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. D3入門:Web画面にD3で点を描く  D3を用いて点を描いてみると、以下のようになります。D3はSVGにおけるjQueryのような感触です。 3 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <style type="text/css">svg {border: dashed 1px blue;}</style> </head> <body> <svg width="100" height="100"> <circle cx="50" cy="50" r="10"></circle> </svg> </body> </html> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <style type="text/css">svg {border: dashed 1px blue;}</style> </head> <body> <script type="text/javascript" src="js/d3.v3.js"></script> <script type="text/javascript"> d3.select("body") .append("svg").attr("width", 100).attr("height", 100) .append("circle").attr("cx", 50).attr("cy", 50).attr("r", 10); </script> </body> </html> 元の姿 D3での書き方 d3.select("body")で bodyのDOMをつかむ <svg width="100" height="100"> と同じ。 <circle cx="50" cy="50" r="10"> と同じ。 描画結果はどちらも同じ
  5. 5. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. D3入門:基本のAPIを使ってsinカーブを描画 4 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <style type="text/css">svg {border: dashed 1px blue;}</style> </head> <body> <div id="area"></div> <script type="text/javascript" src="js/d3.v3.js"></script> <script type="text/javascript"> var svg = d3.select("#area").append("svg").attr("width", 360).attr("height", 100); for (var deg = 0; deg < 360; deg++) { svg.append("circle") .attr("cx", deg) .attr("cy", 50 - 40 * Math.sin(deg * Math.PI / 180)) .attr("r", 1); } </script> </body> </html>  circleを用いてsinカーブを描画してみる事も簡単にできます。 上記ソースの面倒な点: SVGで簡単に点を描画できるのは良いけれども、描画の原点が左上にあり、数学でよく使う座標系とは異なっていて、 変換が面倒。また、sinカーブの場合はy軸のオフセットや拡大率の計算も面倒。軸の描画も無いのでさみしい。 SVGの 原点 オフセット 拡大率
  6. 6. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. D3入門:基本のAPIを使ってsinカーブを描画その2:スケールの導入  座標系の変換処理は、D3の「スケール」を使えば楽になります。座標系の種類は、ここで利用して いるリニアスケール以外にも、対数軸なども利用可能です。 5 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <style type="text/css">svg {border: dashed 1px blue;}</style> </head> <body> <div id="area"></div> <script type="text/javascript" src="js/d3.v3.js"></script> <script type="text/javascript"> var svg = d3.select("#area").append("svg").attr("width", 360).attr("height", 100), x = d3.scale.linear().domain([0,360]).range([0,360]), y = d3.scale.linear().domain([-1,1]).range([90,10]); for (var deg = 0; deg < 360; deg++) { svg.append("circle") .attr("cx", x(deg)) .attr("cy", y(Math.sin(deg * Math.PI / 180))) .attr("r", 1); } </script> </body> </html> domain: データの取りうる範囲 range: 描画の範囲 →これをリニアに変換してくれる xやyの関数は、データ値が与えられたら、 描画時の座標を返却するような関数。
  7. 7. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. 以後、HTMLからCSSとJSを分離します 6 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" type="text/css" href="sample.css"></link> </head> <body> <div id="d3area"></div> <script type="text/javascript" src="js/d3.v3.js"></script> <script type="text/javascript" src="sample.js"></script> </body> </html> svg {border: dashed 1px blue;} var svg = d3.select("#d3area").append("svg").attr("width", 360).attr("height", 100), x = d3.scale.linear().domain([0,360]).range([0,360]), y = d3.scale.linear().domain([-1,1]).range([90,10]); for (var deg = 0; deg < 360; deg++) { svg.append("circle") .attr("cx", x(deg)) .attr("cy", y(Math.sin(deg * Math.PI / 180))) .attr("r", 1); } 使用するHTML sample.html →以降、これに固定 sample.css sample.js
  8. 8. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. DOMノードにデータを持たせる  D3の最も特徴的なアーキテクチャは、HTMLのDOMノードに対して __data__ というキー名でデータを保持する 事にあります。これを徐々に説明していきます。まず、今までのsinカーブの各circleにデータを付けてみます。 7 var svg = d3.select("#d3area").append("svg").attr("width", 360).attr("height", 100), x = d3.scale.linear().domain([0,360]).range([0,360]), y = d3.scale.linear().domain([-1,1]).range([90,10]); for (var deg = 0; deg < 180; deg++) { // 今後の説明のために描画は180度までとする svg.append("circle") .attr("class","dot") // circle一つ一つに「dot」クラスを設定 .attr("cx", x(deg)) .attr("cy", y(Math.sin(deg * Math.PI / 180))) .attr("r", 1); } // 上記circleにデータを付与する var data = d3.range(360); // [0,1,2, ... ,359] つまり、データ側は359度まで svg.selectAll(".dot").data(data); // これでDOMノードに __data__ が付与される デ ー タ を 持 た せ る 前 デ ー タ を 持 た せ た 後 jQueryのように、 selectAll関数を 用いれば様々なセレクション方法で DOMノードを掴む事ができます。 その掴んだDOMノードに対してデー タを割り振ることも出来ます。 ちゃんとデータが付いて います
  9. 9. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. DOMノードに付けたデータを活用する  データを持たせたセレクション結果に対して、まとめてDOM操作を行うことが出来ます。ここではDOM操作が可視 化出来るようにするためにアニメーション処理を入れ、cosカーブに変更してみます。 8 var svg = d3.select("#d3area").append("svg").attr("width", 360).attr("height", 100), x = d3.scale.linear().domain([0,360]).range([0,360]), y = d3.scale.linear().domain([-1,1]).range([90,10]); for (var deg = 0; deg < 180; deg++) { // 今後の説明のために描画は180度までとする svg.append("circle") .attr("class","dot") // circle一つ一つに「dot」クラスを設定 .attr("cx", x(deg)) .attr("cy", y(Math.sin(deg * Math.PI / 180))) .attr("r", 1); } // 上記circleにデータを付与する var data = d3.range(360); // [0,1,2, ... ,359] つまり、データ側は359度まで svg.selectAll(".dot").data(data) // これでDOMノードに __data__ が付与される .transition() // DOMの書き換えをアニメーションさせる指定。この指定がなければ一瞬で変化する .delay(function(d){return 10 * d;}) // DOMの書き換えをX座標に依存して遅らせる指定 .duration(function(d){return 500 + 10 * d;}) // アニメーション速度の指定 .style("fill","green").attr("r",2) // CSSスタイルを変更 .attr("cy",function(d){return y(Math.cos(d * Math.PI / 180));}); // cosカーブに変更 attr関数やstyle関数やdelay関数やd uration関数など、多くのDOM操作を 伴う関数は、引数として実際の値の他 に、関数を渡すことが可能です。 関数の第一引数には __data__ が渡 され、第二引数にはインデックス番号が 渡されます。 このような仕組みとなっているため、D3 ではDOMノードに持たせたデータを 様々な局面で有効活用できます。 ここがD3の強みです。
  10. 10. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. 既存のDOMノードの数がデータより少ない状況で、新規DOMノードを追加する (D3のenter関数を理解する)  DOMのセレクション結果とデータを関連付けた後、データ側が余った場合に、DOMに関連付け出来なかったデー タを元に新規のDOMノードを追加する操作が可能です。 9 var svg = d3.select("#d3area").append("svg").attr("width", 360).attr("height", 100), x = d3.scale.linear().domain([0,360]).range([0,360]), y = d3.scale.linear().domain([-1,1]).range([90,10]); for (var deg = 0; deg < 180; deg++) { // 今後の説明のために描画は180度までとする svg.append("circle").attr("class","dot") // circle一つ一つに「dot」クラスを設定 .attr("cx", x(deg)) .attr("cy", y(Math.sin(deg * Math.PI / 180))) .attr("r", 1); } // 上記circleにデータを付与する var data = d3.range(360); // [0,1,2, ... ,359] つまり、データ側は359度まで svg.selectAll(".dot").data(data) // これでDOMノードに __data__ が付与される .enter() // DOMのセレクション結果よりdata側が多かった場合、そのはみ出した部分の処理に入る .append("circle").attr("class","dot") .attr("cx",function(d){return x(d);}) .attr("cy",function(d){return y(Math.sin(d * Math.PI / 180));}) .attr("r",2).style("fill","red"); 実はこの部分もenterで処理可能です。 ここがenterによって 追加されました。 svg.selectAll(".dot").data(d3.range(180)) .enter() .append("circle").attr("class","dot") .attr("cx",function(d){return x(d);}) .attr("cy",function(d){return y(Math.sin(d * Math.PI / 180));}) .attr("r",1); 書き換えてみると こうなります。 この方式ではセレクション結果が空っぽの状態から開始します。データをDOMに紐付ける dataメソッドの処理も、「すべてのデータがDOMとは紐付かない」という結果になります。 enter関数で新規DOMを作成すると、全データに対するDOMノードが作成されます。
  11. 11. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. enterの理解を深める その1  D3でのenterの仕組みは、なかなか理解できないことで有名です。ステップに分けて説明します。 10 svg.selectAll(".dot").data(d3.range(180)) .enter() .append("circle") svg.selectAll(".dot").data(d3.range(180)) .enter() svg.selectAll(".dot").data(d3.range(180)) svg.selectAll(".dot") クラス「dot」が付いているDOMノードをDOMツリーから検索します。 クラス「dot」が付いているDOMノードの一覧と、リスト構造のデータを結合します。 DOMノード一覧 = ◯ ◯ ◯ ◯ データのリスト = ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ←これらを先頭から組にする DOMに関連づいていないデータの一覧に絞ったデータの配列+D3ロジックが返ります。 DOMノード一覧 = ◯ ◯ ◯ ◯ データのリスト = ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ←DOMに関連づいていないデータ svg.selectAll(".dot").data(d3.range(180)) .enter() .append("circle").attr("class","dot") DOMに関連づいていなかったデータに対してcircleのDOMが生成され、 その配列が返ります。 DOMノード一覧 = ◯ ◯ ◯ ◯ ◯ ◯ ◯ ◯ データのリスト = ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ この処理の中で、生成したDOMノードに __data__ プロパティを付与してデータを 関連付ける処理も行われます。 circleのDOM配列に対してclassを指定します。典型的にはselectAllのセレクションで 指定したクラスを指定しますが、そうでなくても構いません。 つまり、プログラムの都合で違うものを付与しても構いません。 attr関数の戻り値は、thisです。よって、引続きattr関数やstyle関数やtext関数などを 使ってDOMの属性をセットアップしていくことが出来ます。
  12. 12. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. enterの理解を深める その2  以下の書き方はD3ではよくあるけれども、どうもしっくりこない・・・  疑問1:何もセレクションされないことが分かっている時にselectAllを真面目に書く必要があるか? →その必要はないです。  疑問2:ノードにクラス指定する事が多いけど、D3ではクラス指定は必須なの? →その必要はないです。単に後々セレクションなどで使えて便利だからやっているだけです 11 svg.selectAll(".dot").data(d3.range(180)) .enter() .append("circle").attr("class","dot") .attr("cx",function(d){return x(d);}) .attr("cy",function(d){return y(Math.sin(d * Math.PI / 180));}) .attr("r",1); svg.selectAll().data(d3.range(180)) .enter() .append("circle").attr("class","dot") .attr("cx",function(d){return x(d);}) .attr("cy",function(d){return y(Math.sin(d * Math.PI / 180));}) .attr("r",1); svg.selectAll().data(d3.range(180)) .enter() .append("circle") .attr("cx",function(d){return x(d);}) .attr("cy",function(d){return y(Math.sin(d * Math.PI / 180));}) .attr("r",1);
  13. 13. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. 既存のDOMノードの数がデータより多い状況で、既存DOMノードを削除する (D3のexit関数を理解する)  既存のDOMのセレクション結果とデータを関連付けた後、既存DOMノード側の数が多く、余った場合に、その余っ たDOMノードを対象に処理をする事が可能です。 12 var svg = d3.select("#d3area").append("svg").attr("width", 360).attr("height", 100), x = d3.scale.linear().domain([0,360]).range([0,360]), y = d3.scale.linear().domain([-1,1]).range([90,10]); for (var deg = 0; deg < 180; deg++) { // 今後の説明のために描画は180度までとする svg.append("circle").attr("class","dot") // circle一つ一つに「dot」クラスを設定 .attr("cx", x(deg)).attr("cy", y(Math.sin(deg * Math.PI / 180))).attr("r", 1); } // 上記circleにデータを付与する。DOMノードは余る。 var data = d3.range(90); // [0,1, ... ,89] svg.selectAll(".dot").data(data).exit() .transition() // DOMの書き換えをアニメーションさせる指定。この指定がなければ一瞬で変化する .duration(function(_,i){return 10*i;}) // アニメーション速度の指定 .style("opacity",0) .remove(); データがアサインされ なかったDOMノード が徐々に消えます
  14. 14. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. 軸の導入 13 svg {border: dashed 1px blue; font-size: 12px;} .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } var data = d3.range(360).map(function(deg){return {x:deg,y:Math.sin(deg * Math.PI / 180)};}); var margin = {top: 15, right: 10, bottom: 25, left: 40}, width = 500 - margin.left - margin.right, height = 200 - margin.top - margin.bottom, x = d3.scale.linear().domain(d3.extent(data.map(function(d){return d.x;}))).range([0,width]), y = d3.scale.linear().domain(d3.extent(data.map(function(d){return d.y;}))).range([height,0]), g = d3.select("#d3area").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); g.append("g").attr("class", "x axis").attr("transform", "translate(0," + height + ")") .call(d3.svg.axis().scale(x).orient("bottom")); g.append("g").attr("class", "y axis") .call(d3.svg.axis().scale(y).orient("left")); g.selectAll(".dot").data(data).enter() .append("circle").attr("class","dot") .attr("cx", function(d){return x(d.x);}) .attr("cy", function(d){return y(d.y);}).attr("r", 1); SVGのtransformの指定をすると、 座標系をずらす事が可能です 軸の描画に関しては、D3がそのような図形描画処 理を提供してくれています d3.extentを利用すると、データの最小値と最大 値が算出可能です。
  15. 15. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. おまけ:sinカーブをcosカーブに「にゅーっ」と変形 14 var data = d3.range(360).map(function(deg){return {x:deg,y:Math.sin(deg * Math.PI / 180)};}); var margin = {top: 15, right: 10, bottom: 25, left: 40}, width = 500 - margin.left - margin.right, height = 200 - margin.top - margin.bottom, x = d3.scale.linear().domain(d3.extent(data.map(function(d){return d.x;}))).range([0,width]), y = d3.scale.linear().domain(d3.extent(data.map(function(d){return d.y;}))).range([height,0]), g = d3.select("#d3area").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); g.append("g").attr("class", "x axis").attr("transform", "translate(0," + height + ")") .call(d3.svg.axis().scale(x).orient("bottom")); g.append("g").attr("class", "y axis") .call(d3.svg.axis().scale(y).orient("left")); g.selectAll(".dot").data(data).enter() .append("circle").attr("class","dot") .attr("cx", function(d){return x(d.x);}) .attr("cy", function(d){return y(d.y);}).attr("r", 1); var newData = d3.range(360).map(function(deg){return {x:deg,y:Math.cos(deg * Math.PI / 180)};}); g.selectAll(".dot").data(newData) .transition() .duration(function(d){return 500+x(d.x);}) .delay(function(d){return 10*x(d.x);}) .attr("cy", function(d){return y(d.y);});
  16. 16. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. イベント処理  D3はjQueryと同じようにon関数によって各種イベントを扱うことが出来るようになっています。 ここではclickイベントを拾って円の形を変える例を示します。 15 var svg = d3.select("#d3area").append("svg").attr("width",100).attr("height",100); svg.append("circle").attr("cx",50).attr("cy",50).attr("r",10) .on("click",function(){ svg.selectAll("circle") .transition().duration(300).attr("r",50) .transition().duration(300).attr("r",10) .transition().duration(300).attr("cx",80) .transition().duration(300).attr("cx",20) .transition().duration(900).attr("cx",50); }); 書き方はjQueryと同じ ちなみに・・・ D3はDOMノードの処理やイベント処理を記述可能 ですので、jQueryの代替として使う人も増えてきてい ます。jQueryと役割が重なる部分が多いのです。 ちなみにD3はSVGに特化したものではなく、実はHT MLのDOMノードやイベント全般が扱えます。 クリック 色々動く
  17. 17. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. イベント処理 その2  イベントの処理例として、もう一つ、mousemoveイベントを拾って輪を描画するサンプルを紹介します。 16 var color = d3.scale.category20c(), i = 0; var svg = d3.select("#d3area") .append("svg").attr("width",640).attr("height",480) .style("pointer-events", "all") .on("mousemove", function(){ svg.append("circle") .attr("cx", d3.event.x).attr("cy", d3.event.y).attr("r", 1e-6) .style("fill","none").style("stroke", color(i++)).style("stroke-opacity", 1) .transition() .duration(5000) .ease(Math.sqrt) .attr("r", 100) .style("stroke-opacity", 1e-6) .remove(); }); 書き方はjQueryと同じ [処理内容] マウスポインタが動く際に発生するイベントに反応して動きます。 circleを作って、色はd3.scale.category20cという色生成関数で 生成した色を指定しています。 transition指定をして徐々に半径が広がるように、また、不透明 度(opacity)が下がるように、つまり透明になっていくように指定し 、 最後に透明になった後、DOMノードも消えるように指定しています。
  18. 18. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. 散布図  散布図の実現は簡単です。単純に軸を描画し、circleで点を描くだけです。 17 var data = [[3,5], [7,2], [1,10], [9,12], [5,13]]; var margin = {top: 15, right: 10, bottom: 25, left: 40}, width = 500 - margin.left - margin.right, height = 200 - margin.top - margin.bottom, x = d3.scale.linear().domain(d3.extent(data,function(d){return d[0];})).range([0,width]), y = d3.scale.linear().domain(d3.extent(data,function(d){return d[1];})).range([height,0]), g = d3.select("#d3area").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); g.append("g").attr("class", "x axis").attr("transform", "translate(0," + height + ")") .call(d3.svg.axis().scale(x).orient("bottom")); g.append("g").attr("class", "y axis").call(d3.svg.axis().scale(y).orient("left")); g.selectAll().data(data).enter() .append("circle") .attr("cx",function(d){return x(d[0]);}) .attr("cy",function(d){return y(d[1]);}).attr("r",5);
  19. 19. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. 散布図で見るD3(およびJavaScript)のパフォーマンス  100,000個(10万個)のデータを散布図でプロットしました。HTMLの描画部分も含めて、全体で約2秒でプロット 可能でした。なお、現在関わっているプロジェクトでは約10万件のデータをJavaScriptのメモリー上に保持し、さま ざまな処理をしていますが、やはり問題にはなっていません。なお、100万件程度になると、インタラクティブな操 作が出来なくなるほど遅くなると思われます。 18
  20. 20. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. 円グラフ  以下に円グラフの例を示します。 19 var data = [["A",4], ["B",3], ["C",2], ["D",1]]; var width = 400,height = 400,radius = 200, arc = d3.svg.arc().innerRadius(0.3*radius).outerRadius(0.9*radius); var c = d3.scale.category20c(); var g = d3.select("#d3area").append("svg").attr("width",width).attr("height",height) .append("g").attr("transform","translate(" + width / 2 + "," + height / 2 + ")") .selectAll().data(d3.layout.pie().sort(null).value(function(d){return d[1];})(data)) .enter().append("g").attr("class","arc"); g.append("path").style("fill",function(_,i){return c(i);}).style("stroke","black").attr("d",arc); g.append("text") .attr("transform",function(d){return "translate(" + arc.centroid(d) + ")"; }) .attr("dy","0.35em").style("text-anchor","middle").style("font-size","30px") .text(function(d){return d.data[0];}); ここが円グラフの弧の部分の形を生 成するコア部分 ここは円グラフ用のデータを作るため に必要な部分。ここも重要。 <sunburst> 円グラフのプリミティブである円弧を組合せていくと、 sunburstというモダンな表現も可能になります。 プリミティブの円弧
  21. 21. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. Chord diagram に挑戦  以降のスライドでChord diagramを扱ってみます。通常目にする散布図、折れ線グラフ、棒グラフ、 円グラフなどとは違うものです。見た目は以下の様なものです。 20 このような円弧は円グラフ(パイチャート)で使った 円弧の表現を応用します。ラベル部分も円グラフと 同じです。オフセットが異なるだけです。 Chord diagram 特有のこの円弧は、D3が提供す る d3.svg.chord() で描画可能なものになります。
  22. 22. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. Chord diagram: bigramをChord diagramで表現してみます  Chord diagramは、相互に数値的な関係のあるノード間の強さを表現します。なかなか具体例がな いと説明出来ないため、ここではbigramを例に用いて説明します。  bigram(バイグラム)とは  英単語の「the」を用いて説明します。theはtの後にhが来て、hの後にeが来ます。こうなる確率は以下の通 りです。このような、英文字間の遷移確率データをbigramと呼びます。  英語でtの後にhの来る確率=33%  英語でhの後にeの来る確率=52%  bigramのデータを表形式で表現することも出来ます。たとえば以下のようなものになります。  bigramを3次元グラフで描画することも可能です。(下記はExcelで描画したもの) 21 t h e 33% 52% aが来る bが来る cが来る dが来る eが来る ・・・ aのあとに 20 3279 4961 5105 65 bのあとに 1754 164 112 13 6150 cのあとに 8507 8 865 50 5204 dのあとに 3254 133 129 1304 13219 ・・・ ← 数字は、ある英文テキストにおける 出現回数 ← 横軸は「aのあとに」などの最初の文字 奥行き方向の軸は「bが来る」などの次の文字 棒の高さは、そのようなパターンの出現回数 この中で飛び抜けて高い棒は「th」のパターン。
  23. 23. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. Chord diagram: bigramはネットワーク構造をしたデータ  bigramは、「エッジに数値の付いた有向サイクリックグラフ」です。ここで言うグラフは、ネットワーク 構造の事です。bigramを素直にノードとエッジを用いたグラフ構造として表現すると以下のようにな ります。なお、すべてのノードについて記述するとクモの巣状になってしまうので、4文字のみ取り上 げました。 22 t h e 51626 34984 21256 3004 312 13969 i 186341 1233 6159 00 数字は、あるドキュメントでそのような遷移が出現した回数。 本当にaからzまでのすべての単語について記述するとなると、 1つのノードからaからzまでの26ノードへの関連が発生する。 本当に描画してしまうとグチャグチャに・・・ → そこでChord diagram! 3177 2 71 3893
  24. 24. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. Chord diagram: D3を用いてbigramをChord diagramで表現する  以下はD3を用いてbigramをChord diagramで表現してみたものです。 23 たとえば 「t」 のノードにフォーカスすると、アルファベット「t」の 次に来やすいアルファベットに対して線が引かれます。 ノード「t」に接続している側の線の太さは、遷移のしやすさを 意味します。たとえば「t」の次は「h」が来やすいため太い線と して表現されています。 逆に「h」のノードから「t」のノードに行く事を考えると、「h」の 側は細く描画されていることが分かります。そのため「ht」のような 並びは英語ではレアであることが分かります。 太い 細い
  25. 25. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. Chord diagram のソースコード 24 var width = 500, height = 500, innerRadius = 0.35 * width, outerRadius = 1.2 * innerRadius; var color = d3.scale.category20(); // 座標の原点をSVGのエリアの中心に var svg = d3.select("body").append("svg").attr("width", width).attr("height", height) .append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); // chord用データを生成 var chord = d3.layout.chord().padding(.05).sortSubgroups(d3.descending).matrix(matrix); // chord特有の弧の部分を描画 svg.selectAll().data(chord.chords).enter() .append("path").attr('class','chord-path') .attr("d", d3.svg.chord().radius(innerRadius)) .style("fill",function(d){return color(d.target.index);}) .style('stroke',function(d){return color(d.target.index);}) .style('stroke-width','1').style("opacity", 0.8).style("stroke-opacity",1); // 周囲の円弧の土台を作成してデータを投入 var g = svg.selectAll().data(chord.groups).enter().append("g").attr('class','chord'); // 周囲の円弧を描画 g.append("path").style("fill", function(d){return color(d.index);}) .style("stroke", function(d){return color(d.index);}) .attr("d", d3.svg.arc().innerRadius(innerRadius).outerRadius(outerRadius)) .on("mouseover", fade(0.1,0.1)) .on("mouseout", fade(0.8,1)); function fade(opacity,s_opacity) { return function(g, i) { svg.selectAll(".chord-path") .filter(function(d) { return d.source.index != i && d.target.index != i; }) .transition().style("opacity",opacity).style("stroke-opacity",s_opacity); }; } // 周囲のテキストを描画 g.append("text") .attr("dy","0.35em").style("text-anchor","middle").style("font-size","14px") .text(function(d,i){return String.fromCharCode('a'.charCodeAt()+i);}) .attr("transform",function(d){ return "translate(" + d3.svg.arc().innerRadius(outerRadius) .outerRadius(1.15*outerRadius).centroid(d) + ")"; });
  26. 26. ULS Copyright © 2013 UL Systems, Inc. All rights reserved. 他にも色々・・・。data visualization の世界は研究分野の1つなので本当に沢山のア イディアがあるようです。 D3を使えば、その新しいアイディアをより楽に実装できます。 25 http://bl.ocks.org/mbostock/4063269 http://bl.ocks.org/mbostock/raw/1044242/ http://bl.ocks.org/mbostock/4063570 http://bl.ocks.org/mbostock/1062288 http://bl.ocks.org/mbostock/950642 http://bl.ocks.org/mbostock/4063582 http://bl.ocks.org/mbostock/4060366 http://bl.ocks.org/mbostock/4063530 [データビジュアライゼーションのセオリー:人は可視化されたデータをどう見るか]  人は、オブジェクトの面積に敏感です。データのスカラー値を面積に比例させると、人はデータ間の相対的な比較を感覚的に行えます。古典 的にはこのような人の性質を用いて円グラフや棒グラフを作っていました。  人は、色をある程度認識できます。しかし、色の認識は面積ほどではありません。人に傾向を読み取らせるために有向に使える場合がありま す。たとえばヒートマップは色の使い方の有名な例です。  人は連続的な変化を好みます。そのため、似たデータは近くに配置するなどの工夫が有効な場合があります。また、アニメーションも連続的 な変化の一種なので、アニメーションもデータを理解させるツールとして使うと効果的なことがあります。

×