データの視覚化: 第 1 回 SVG と D3 でブラウジング・メトリクスを視覚化する

データをグラフィックで表現する手法を学ぶ

この全 2 回からなる連載記事では、SVG (Scalable Vector Graphics) とオープンソースの D3 JavaScript ライブラリーを使用してデータを視覚化する方法を学びます。ビジネスでデータの大きさを把握する上では、形状、色、レイアウトが大いに役立つ場合があります。サンプル・シナリオでは、SVG と D3 を使用して、ソーシャル・メディアのブラウジング・メトリクスから、豊富な情報を伝えるグラフィックを作成する方法を実演します。

Bilal Siddiqui , Freelance consultant, XML4Java

Bilal Siddiqui は、電子工学エンジニア、XML コンサルタント、テクノロジー・エバンジェリスト、そして活発に著作活動を行っている技術書の著者であり、e-business の簡易化を専門とする会社、XML4Java.com の設立者でもあります。1995年にパキスタンのラホールにある University of Engineering and Technology を卒業した後、産業用制御システムを対象としたソフトウェア・ソリューションの設計を始めました。その後、XML に転向し、Web ベースや WAP ベースの XML 処理ツール、サーバー・サイドの構文解析ソリューション、そしてサービス・アプリケーションを作成しました。2006年からは、Java や XML をベースとしたオープンソースのツールおよびソリューションに専門的に取り組んでいます。オープンソース・ツールの熱烈な支持者である彼は、オープンソース・ツールをベースとしたソリューションを設計するだけでなく、ラホールの大学でオープンソース技術の使用方法について、ソフトウェアおよび IT 担当者のトレーニングも行っています。彼は、『JasperReports 3.6 Development Cookbook』(Packt Publishing、2010年) の著者です。



2013年 8月 29日

この記事は、データからビジネスにとって価値のある情報を抽出するのに役立つ視覚化手法について、具体的な例を用いて説明する全 2 回からなる連載の第 1 回です。今回は、SVG (Scalable Vector Graphics) とオープンソースの D3 JavaScript ライブラリーを使用して、ブラウザーで表示可能な視覚化を行い、形状と色で情報を伝える方法を紹介します。これらの視覚化手法を実演する例として、ソーシャル・メディアの使用状況に関するブラウジング・メトリクスを視覚化します。この第 1 回では、いくつかの基本的な例を用いて、SVG と D3 が連携する仕組みを概説します。第 2 回では、この強力なオープン・スタンダード・テクノロジーの組み合わせが実現する視覚化機能をさらに詳しく掘り下げます。

ソーシャル・メディアのメトリクス分析

ソーシャル・メディアのビッグ・データに関する課題

Twitter、Facebook、YouTube などのソーシャル・メディア・サイトでは、そのサイトの機能を公開する包括的な Web サービス・インターフェースを提供しています。例えば、YouTube Data API を使用すれば、アプリケーションで動画を YouTube にアップロードしたり、Web サイトにアップロードされている YouTube の動画を再生したりすることができます。現在、これらのソーシャル・メディア・サイトでは、分析用の API も開発しているところです。YouTube Analytics API はその一例で、プログラムを利用したクライアントに表示回数や「いいね!」の数などの統計を提供します。これにより、より多くのビジネス・アプリケーションがプログラムを利用した視覚的なインターフェースを介してソーシャル・メディアとやり取りできるようになっています。このことから、あらゆる規模の企業にとって当然の次の課題は、大量のソーシャル・データをビッグ・データ・アナリティクスという手段を通じて、最大限ビジネスで活用することです。この連載では、あらゆるアナリティクスに共通する要素の 1 つである、データの視覚化に焦点を当てます。IBM ビッグ・データ・プラットフォームの IBM InfoSphere Streams 製品および IBM InfoSphere BigInsights 製品の包括的なアナリティクス機能について学んでください。

企業が顧客の動向を理解する創造的な方法として、ソーシャル・メディアを介して自社の考えを提示し、潜在的なクライアントをインタラクティブなディスカッションに参加させる方法があります。ソーシャル・メディアでの交流は、人間同士が互いに直接交流する方法と非常によく似ています。積極的に交流したいと思う相手を理解するにはその人の話を聞く必要があるように、人々の好き嫌いを理解するには人々の声を聞く必要があります。

仮定のシナリオとして、あるインテリア会社が、ブログ、動画、Facebook ページ、そしてディスカッション・フォーラムという形でオープン・コンテンツを公開しているとします。このコンテンツの目的は、ソーシャル・メディア・リソースを介して自社の考えを提示し、ディスカッションやその他の形でユーザーとの交流を開始することです。コンテンツは個々の顧客のセンスと好みに応じたものであり、それに基づいて顧客があるソーシャル・リソースから別の適切なソーシャル・リソースへとナビゲートできるようにします。顧客の動向の変化を判断し、新しい手法や新しいデザインを考え出すには、この会社はブラウジング・データを以下の 3 つの次元で分析する必要があります。

  • ソーシャル・リソースごとの表示回数によって示される人気度
  • リソース上で交流に参加したユーザー数
  • ユーザーが行ったリソース間でのナビゲーションの方向

12、3 のそれぞれに、3 週間でユーザーが表示した回数、交流に参加したユーザー数、ナビゲーション数を示します。これらの表では、会社が使用しているソーシャル・メディア・リソース (ブログや Facebook ページなど) のタイプを色の名前で表していることに注意してください。

表 1 に、各リソースをユーザーが表示した回数を記載します。

表 1. ソーシャル・リソースごとにユーザーが表示した回数
ソーシャル・リソース
第 1 週70577483374938464598
第 2 週23717397458928618249
第 3 週59725672915297258983

表 1 を見ると、第 1 週では、青のリソースが 7,057 回表示されたこと、そしてこの週に最も表示回数が多かったのは金のリソースであることがわかります。

表 2 に、ユーザーの交流データを示します。

表 2. 各ソーシャル・リソース上で交流したユーザー数
ソーシャル・リソース
第 1 週20522089158614262632
第 2 週20712190721437822721
第 3 週30763190453238254831

表 2 からは、第 1 週に青のリソース上で交流したユーザーは 2,052 人であること、そしてこの週にユーザーの交流が最も多く行われたのは茶のリソースであることがわかります。

表 3 に、青のリソースから他のリソースにナビゲートしたユーザーの数を示します。

表 3. 青のソーシャル・リソースでのナビゲーション・データ
ソーシャル・リソース青から金青から緑青から赤青から茶
第 1 週3057348387498456
第 2 週2371739745892861
第 3 週5972567291529725

表 3 からは、第 1 週では、青のリソースにアクセスした後に金のリソースにナビゲートしたユーザー数は 3,057 人であり、青のリソースから赤のリソースにナビゲートしたユーザー数が最も多かったことがわかります。


ブラウジング・データの視覚化

ビジュアル表現を利用すると、数値が記載された表よりも迅速かつ容易に大きなデータの解釈をすることができます。表 123 のデータをグラフィックで表現するには、さまざまな方法があります。一例として、図 1 に表 1 の第 1 週のデータを表示する簡単な方法を示します。

図 1. ソーシャル・リソースごとにユーザーが第 1 週に表示した回数を円で表したもの
表示回数

図 1 は、各リソースの表示回数を円で表しています。円の相対サイズは、その円が表す回数に比例するため、最も多く表示されたリソース (金) が最も大きな円で表されています。それぞれの円には、第 1 週にそのリソースが表示された実際の回数も示されています。

図 2 は、図 1 とは少し異なるレイアウトで円を配置したものです。

図 2. 多少異なるレイアウトの円で示された第 1 週の表示回数
図 1 と同じ円が、今度は水平方向ではなく、円弧状に配置されています。

各リソースの人気度は、会社が分析する必要のあるデータの 1 つの次元でしかありません。図 3 に、第 1 週の各リソースの表示回数と各リソース上で交流したユーザー数の両方を示します。つまり、1 つのビジュアル表現で 2 つの次元を示すというわけです。

図 3. 第 1 週にユーザーが表示した回数と交流したユーザー数を示すネストされた円
リソースごとに、ユーザーが表示した回数を表す円の中に、交流したユーザー数を表す円をネストした視覚化

図 3 では、外側の円がリソースの合計表示回数を表し、内側の円がリソース上での交流ユーザー数を表しています。各円には、実際の表示回数およびユーザー交流数のデータを示す数値も示しました。

123 で示しているのは、データを表現する色、形状、そして実際の数値を組み合わせた単純な方法です。図 3 を見ると、第 1 週では金のリソースがユーザーに最も多く表示され、茶のリソースで最も盛んに交流が行われたことがわかります。


オープン・テクノロジーを使用したデータの視覚化

視覚化用に動的に生成される JavaScript

D3、DVG、JavaScript を組み合わせると、ブラウザー・ベースの完全なデータ視覚化スイートが誕生します。この連載では、これらのテクノロジーを組み合わせて使用する方法を実演するために、サンプル・コードにサンプル・データをハードコーディングしましたが、実際のプロジェクトのほとんどの JavaScript コードは、サーバー・サイドのコンポーネントによって動的に編成されます。ビッグ・データの分析アプリケーションでは、このようなサーバー・サイドのコンポーネントには、Apache Hadoop、サーバー・サイドの各種モジュールをホストする Web およびアプリケーション・サーバー、データベース・サーバーといった要素で構成されるクラスターが組み込まれる場合があります。これらのソースから提供される JavaScript と併せて、SVG コードを生成する D3 を使用するという方法は、JavaScript をサポートする IBM Business Process Manager IBM Business Process Manager (「参考文献」を参照) などの最近のビジネス・アプリケーションには最適です。

最近のオープン・スタンダードとオープンソース・ツールは、データのグラフィック表現をサポートできるだけの強力なものになっています。SVG は、2 次元グラフィカル・オブジェクトを描画するための XML ベースのフォーマットを定義する、W3C (World Wide Web Consortium) のオープン・スタンダードです (「参考文献」に、SVG を紹介する記事へのリンクが記載されています)。SVG をサポートしているブラウザーはいくつかありますが、この記事のすべての SVG コードと JavaScript コードは Google Chrome でテストしました。

データと SVG を扱っている場合には、D3 ライブラリーがちょっとした魔法を提供します。D3 ライブラリーは描画の指示とともにデータを取得し、そのデータを必要な SVG タグに関連付けて、ブラウザーで表示できる SVG コードを即時に生成します。D3 は複雑なグラフィック・オブジェクトを描画する際に、データをすぐに使える状態で保持するため、開発者は描画する図のより詳細な部分に踏み込んで、一度に 1 ステップずつ、その図の小さな各部分を描画するために必要なデータだけを扱うことができます。

この記事と第 2 回の例では、単純な図の描画から複雑な図の描画へと進みながら、D3 の機能を探り、それぞれに描画した図に対応する SVG コードと JavaScript コードを記載します。まずは単純な例として、図 1 に示した円を生成する SVG コードから始めます。

SVG のデータ表現

リスト 1 に、図 1 の円を描画する SVG コードを記載します。

リスト 1. 図 1 の円を描画する SVG コード
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
 width="1000" height="1000">

 <g transform="translate(70,143)">
  <circle r="70.57" style="fill: #000fff;"></circle>
  <text x="-10" fill="grey">7057</text>
 </g>

 <g transform="translate(216,143)">
  <circle r="74.83" style="fill: #fff555;"></circle>
  <text x="-10" fill="grey">7483</text>
 </g>

 <g transform="translate(329,143)">
  <circle r="37.49" style="fill: #aaf000;">
  </circle>
  <text x="-10" fill="grey">3749</text>
 </g>


 <g transform="translate(404,143)">
  <circle r="38.46" style="fill: #cc0000;"></circle>
  <text x="-10" fill="grey">3846</text>
 </g>

 <g transform="translate(489,143)">
 <circle r="45.98" style="fill: #993344;"></circle>
 <text x="-10" fill="grey">4598</text>
 </g>

</svg>

ご覧のとおり、リスト 1 のルート・タグは <svg> となっています。<svg> タグは、ユーザーが他の SVG タグを使用して描画するためのキャンバスを作成するとともに、これらのタグのラッパーとしても機能します。SVG キャンバスのサイズを指定するのは、<svg> タグの width および height 属性です。リスト 1 では、キャンバスの幅と高さを 1,000 × 1,000 に設定しています。

ルート <svg> タグには合計 5 つの <g> 子タグがあります (図 1 の円ごとに 1 つの子タグ)。<g> タグは、各円とそこに表示するテキストを作成するために行われる描画のラッパーとして機能します。各 <g> タグには、transform という名前の属性が 1 つあります。この属性の値は translate (X, Y) です。translate (X, Y) 値によって、描画する円の中心が決まります。例えば、リスト 1 の最初の <g> タグの transform 属性は、最初の円の中心を 70、143 の位置に設定します。

5 つの <g> タグの transform 属性には、それぞれに異なる X 値が設定されていますが、Y 値はすべて同じです。その結果、5 つの円は横に並んで配置されることになります。<g> タグの X 値を変えることによって、隣り合う円の間に目に見える余白ができないように、各円を前の円に隣接させて描画します。この後すぐに、これらの値を生成する単純な JavaScript を記載します。

リスト 1 を詳しく見てみると、<g> タグごとに 2 つの子 (<circle> タグと <text> タグ) があることがわかります。これらのタグはそれぞれ、円と、円に表示するテキストを描画します。各 <circle> タグには、円の半径を定義する r 属性があります。ぞれぞれの <circle> タグの r 属性の値は、表示回数を 100 で割った値です。<circle> タグには、円を塗りつぶす色を指定する style 属性もあります。ここでは、6 桁の 16 進数フォーマットを使用して、色の RGB (Red Green Blue) コードを表しています (色の使用方法についての詳細は、「参考文献」を参照してください)。<text> タグは、各円の内側に表示されるテキストをラップします。上記では、テキストを見やすくするために、各 <text> タグに x="-10" という属性を指定してテキストの位置をずらしています。<tag> タグの fill 属性は、テキストの色を指定します。

記事のすべてのサンプル・コードは、ダウンロードしてブラウザー・ウィンドウで開くことができます。リスト 1 の SVG コードに円やテキストを追加して、ブラウザーで SVG がどのように表示されるか確かめてみてください。

JavaScript と D3 を使用して SVG を生成する

リスト 2 に記載する JavaScript コードは、D3 を使用してリスト 1 の SVG コードを生成します。

リスト 2. D3 を使用して図 1 の SVG を生成する
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>

<script>

//Step 1:
var views = [
  [7057, 7483, 3749, 3846, 4598],
  [ 2371, 7397, 4589, 2861, 8249],
  [ 5972, 5672, 9152, 9725, 8983],
            ];

var width = 1000, height = 1000;
var colors = [  "blue",
                "yellow", 
                "green", 
                "red", 
                "maroon"
             ];
var week = 0;

//Step 2:
var svg = d3.select("body").append("svg")
   .attr("width", width)
   .attr("height", height)

//Step 3:
   .selectAll("g")
   .data(views[week])
   .enter();

//Step 4:
var g = svg.append("g")

//Step 5:
    .attr("transform", function(d,i){
  var x = 0;
  for (var count=0;
           count<i;
   	        count++   )
             x+=views[week][count];
  for (var count=0;
           count<=i;
           count++   )
             x+=views[week][count];
  return "translate(" + x/100 + "," + height / 7 + ")" }
         );

//Step 6:
g.append("circle")
  .attr("r", function(d){return d/100})
  .style("fill", function(d, i){return colors[i];});

g.append("text")
  .attr("x", -10)
  .attr("fill", "grey")
  .text(function(d){return d});

</script>
</body>

リスト 2 には、各ステップを示すためのコメントを入れておきました。

ステップ 1: 最初のステップでは、ユーザーが表示した回数のデータ (ユーザー表示回数データ) を配列に格納します。また、キャンバスのサイズと SVG 描画で使用する色を格納するための変数も設定します。

ステップ 2: d3.select("body").append("svg") で D3 を使用することから始めます。このコードによって、HTML ページの本体に <svg> タグが追加されます。ここでは、SVG キャンバスの幅と高さを設定するために .attr() 関数も呼び出しています。

ステップ 3: .selectAll().data().enter() の 3 つの関数呼び出しが、D3 を使用することでもたらされる長所と使いやすさを形にしています。

  • .selectAll("g") 呼び出しは、ルート SVG タグのすべての <g> 子タグを選択します。現時点ではこの呼び出しによって何も選択されませんが (何も存在しないため)、私が期待しているとおりの動作をします。
  • .data(views[week]) 呼び出しは、5 つすべてのソーシャル・リソースの週ごとのユーザー表示回数データを D3 に渡します。
  • .enter() 呼び出しは、個々の <g> タグをユーザー表示回数データの各レコードに関連付けます。

ステップ 4: .append("g") 呼び出しは、データに含まれるレコードごとに 1 つの <g> タグを割り当てる上で十分な数の <g> タグを追加するよう、D3 に指示します。最初は <g> タグがなく、データ配列を構成する各週には 5 つのレコード (ソーシャル・リソースごとに 1 つのレコード) があるため、D3 はルート <svg> タグに 5 つの <g> タグを追加します。最初の <g> タグは、内部で最初のデータ・レコード (つまり、表示回数データの配列に含まれる 7057) に関連付けられ、2 番目の <g> タグは 2 番目のデータ・レコードに関連付けられ、等々となります。D3 は内部でデータを SVG のタグに関連付けるため、唯一必要なのはコードの生成を行う際にデータ配列を 1 度だけ渡すことであり、SVG の個々のタグに正しいデータを関連付けることについては心配する必要はありません。

ステップ 5: 5 つの <g> タグには、それぞれに transform 属性を追加する必要もあるため、.attr() 関数を呼び出します。この関数を 1 回呼び出せば、D3 が内部でループを処理してくれるため、5 つの <g> タグのそれぞれに確実に transform 属性が追加されます。

.attr() 関数は、生成する属性の名前 (この場合は transform) を最初のパラメーターとして取ります。リスト 1 で説明したように、transform 属性は円の位置を決定することから、この属性の値は、関数の中で計算しなければなりません。このことから、.attr() 関数の 2 番目のパラメーターは、2 つのパラメーター (d および i) を取る別の関数呼び出しとなっています。

D3 が開発者にこのような関数呼び出しの機会を提供している理由は、属性値の生成時に <g> タグに関連付けられたデータが必要になる場合があるためです。d パラメーターは、現在生成している transform 属性値に対応する特定の <g> タグのデータ (例えば、青のソーシャル・リソースのユーザー表示回数を表すレコードに関連付けられた最初の <g> タグの場合、7057) を保持します。D3 の魔法は、データと個々のタグの正しい関連付けを内部で処理することです。したがって、開発者は正しいデータを選択することについて心配する必要はなく、SVG の生成中はデータの処理に専念することができます。

i パラメーターは、0 ベースのデータ・インデックスです (例えば、最初のレコードに関連付けられた最初の <g> タグの場合、i = 0 です)。このステップでは、i パラメーターを使用して <g> タグの適切な位置を計算することによって、最初 (青) のソーシャル・リソースの円を左端に描画し、続いてその円に隣接する 2 番目の円を描画するといった仕組みになっています。

ステップ 1 からステップ 5 までのコードを実行してみると、リスト 3 の SVG コードに示されているように、5 つの <g> 子タグと transform 属性が生成されます (これらの <g> タグはまだ、ブラウザー・ウィンドウに図を表示しません)。

リスト 3. 5 つの <g> タグのみが生成された SVG コード
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
 width="1000" height="1000">

 <g transform="translate(70,143)">
 </g>

 <g transform="translate(216,143)">
 </g>

 <g transform="translate(329,143)">
 </g>

 <g transform="translate(404,143)">
 </g>

 <g transform="translate(489,143)">
 </g>

</svg>

ステップ 6: 残りの作業は、5 つの <g> タグのそれぞれに <circle> タグと <text> タグを追加することです。そのために、.append() 関数を 2 回呼び出します (<circle> に対して 1 回、その <text> タグに対して 1 回)。

.attr("r", function(d){return d/100}) を使用して円の r 属性 (半径) を生成していることに注意してください。この場合、特定のリソースの表示回数さえわかれば、それに比例したサイズの円を描画することができます。そのため、必要なのは d パラメーターのみであり、i パラメーターは必要ないため、私は i パラメーターを省略しています。d パラメーターには自動的に正しいデータ (表示回数) が格納されるので、d の値を 100 で割ることで、円のサイズを設定します。

これで、この D3 ベースの JavaScript コードは図 1 の円を描画できる状態になりました。サンプル・コードのダウンロードに含まれている Listing2.html をブラウザー・ウィンドウで開くと、このコードがリスト 1 の SVG を生成して、図 1 の円を表示することを確認できます。

円のレイアウトを少し変更する

リスト 2 のコードを少し変更して、図 2 に示した円のレイアウトを描画します。リスト 4 に、変更後の JavaScript を記載します。

リスト 4. 図 2 のレイアウトを描画するように変更したコード
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>

<script>

var views = [
  [7057, 7483, 3749, 3846, 4598],
  [ 2371, 7397, 4589, 2861, 8249],
  [ 5972, 5672, 9152, 9725, 8983],
  [ 9763,  8462,  9782, 1953, 5182],
  [ 9567,  1571,  2895, 2783, 1874],
  [ 2371, 7397, 4589, 2861, 8249]
		];

var width = 1000, height = 1000;
var colors = [	"#0000ff", 	//blue
			"#ffd700", 	//gold 
			"#008000", 	//green 
			"#ff0000", 	//red 
			"#800000" 	//maroon
		];
var week = 0, scale = 100;

var svg = d3.select("body").append("svg")
   .attr("width", width)
   .attr("height", height)
   .selectAll("g").data(views[week]).enter();

var g = svg.append("g")
    .attr("transform", function(d,i){

  var x = 10000,  y = 10000;

  if (!(i%2)){
    for (var count=0;
         count<i;
         count++)
           x+=views[week][count];
    for (var count=0;
         count<=i;
         count++)
           y+=views[week][count];
    } else {
    for (var count=0;
         count<i;
         count++)
           y+=views[week][count];
    for (var count=0;
         count<=i;
         count++)
           x+=views[week][count];
    }
    return "translate(" + x/scale + "," + y/scale + ")"}
          );

g.append("circle")
  .attr("r", function(d){return d/scale})
  .style("fill", function(d, i){return colors[i];});

g.append("text")
  .attr("x", -10)
  .attr("fill", "grey")
  .text(function(d){return d});

</script>
</body>

リスト 2リスト 4 を比べてみると、リスト 4 で太字にされた部分で transform 属性値の計算が変更されていることがわかります。

円の中の円

今度はリスト 5 に記載する、図 3 の円 (表示回数データと交流数データを同時に表示するネストされた円) を描画するための SVG コードを見てみましょう。

リスト 5. 図 3 の SVG コード
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
 width="1000" height="1000">

  <g transform="translate(100,170.57)">
    <circle r="70.57" style="fill: #0000ff;">
    </circle>
    <circle r="20.52" style="fill: #add8e6;">
    </circle>
    <text x="-15" y="35.52" fill="white">7057</text>
    <text x="-15" y="5">2052</text>
  </g>

  <g transform="translate(245.4,170.57)">
    <circle r="74.83" style="fill: #ffd700;">
    </circle>
    <circle r="20.89" style="fill: #ffff00;">
    </circle>
    <text x="-15" y="35.89" fill="white">7483</text>
    <text x="-15" y="5">2089</text>
  </g>

  <g transform="translate(245.4,282.89)">
    <circle r="37.49" style="fill: #008000;"></circle>
    <circle r="15.86" style="fill: #90ee90;"></circle>
    <text x="-15" y="30.86" fill="white">3749</text>
    <text x="-15" y="5">1586</text>
  </g>

  <g transform="translate(321.35,282.89)">
    <circle r="38.46" style="fill: #ff0000;"></circle>
    <circle r="14.26" style="fill: #f08080;"></circle>
    <text x="-15" y="29.26" fill="white">3846</text>
    <text x="-15" y="5">1426</text>
  </g>

  <g transform="translate(321.35,367.33)">
    <circle r="45.98" style="fill: #800000;"></circle>
    <circle r="26.32" style="fill: #cd5c5c;"></circle>
    <text x="-15" y="41.32" fill="white">4598</text>
    <text x="-15" y="5">2632</text>
  </g>

</svg>

リスト 5 では、各 <g> タグの中に 2 つの <circle> タグと 2 つの <text> タグが含まれていますが、リスト 1 では <circle> タグと <text> タグのペアが 1 つしかありません。その理由は容易に理解できます。それは、図 3 のネストされた円を表示するには、同じ中心を持つ 2 つの円を描画してネストされた円のビューにし、この 2 つの円のそれぞれに、対応する数字を表示しなければならないためです。

リスト 6 に、図 3 を生成するための D3 ベースの JavaScript コードを記載します。

リスト 6. 図 3 を描画するための JavaScript
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>

<script>

var viewsAndInteraction = [
[ [7057, 2052], [7483, 2089], [3749, 1586],
  [3846, 1426], [4598, 2632]               ],
[ [5972, 2071], [5672, 2190], [9152, 7214],
  [9725, 3782], [8983, 2721]               ],
[ [8749, 3076], [4768, 3190], [6738, 4532],
  [9546, 3825], [6983, 4831]               ]
               ];

var width = 1000, height = 1000;
var viewColors = [  "blue",
                    "gold",
                    "green", 
                    "red", 
                    "maroon"
		];
var interactionColors = [  "lightblue",
                           "yellow", 
                           "lightgreen", 
                           "lightcoral", 
                           "indianred"
		];

var week = 0, scale = 100;

var svg = d3.select("body").append("svg")
   .attr("width", width)
   .attr("height", height)
   .selectAll("g")
   .data(viewsAndInteraction[week])
   .enter();

var g = svg.append("g")
    .attr("transform", function(d,i){

  var x = 10000,  y = 10000;

  if (!(i%2)){
    for (var count=0;
         count<i;
         count++)
           x+=viewsAndInteraction[week][count][0];
    for (var count=0;
         count<=i;
         count++)
           y+=viewsAndInteraction[week][count][0];
    } else {
    for (var count=0;
         count<i;
         count++)
           y+=viewsAndInteraction[week][count][0];
    for (var count=0;
         count<=i;
         count++)
           x+=viewsAndInteraction[week][count][0];
    }
    return "translate(" + x/scale + "," + y/scale + ")"}
          );

g.append("circle")
  .attr("r", function(d){return d[0]/scale})
  .style("fill", function(d, i){return viewColors[i];});

g.append("circle")
  .attr("r", function(d){return d[1]/scale})
  .style("fill", function(d, i){return interactionColors[i];});

g.append("text")
  .attr("x", -15)
  .attr("y", function(d){return (15 + d[1]/scale);})
  .attr("fill", "white")
  .text(function(d){return d[0]});

g.append("text")
  .attr("x", -15)
  .attr("y", 5)

  .text(function(d){return d[1]});

</script>
</body>

リスト 2 の JavaScript とリスト 6 のコードを比較すると、ほぼすべての内容が同じであることがわかります。リスト 6 で変更されている点は以下のとおりです。

  • 表示回数データと交流数データを扱う必要があるため、viewsAndInteraction 配列には表示回数と交流数のデータを両方とも格納します。
  • g.append("circle") および g.append("text") 関数呼び出しのペアが 2 つあります。これは、2 つの円をそれぞれのテキストと併せて同じ中心で描画するためです。

これで、3 つすべての図の SVG と JavaScript の説明は終わりです。次の例では、ナビゲーション・データを視覚化します。


ナビゲーション・データのビジュアル表現

図 4 では、さまざまな色の円弧と弦を使用して、第 1 週の特定のナビゲーション・データを表しています。具体的には、青のリソースから他のリソースにナビゲートしたユーザーの数です。

図 4. ナビゲーション・データを示すために色分けされた円弧と弦
円弧と弦の図

図 4 の色分けされた円弧は、それぞれに異なるソーシャル・リソースを表します。青のリソースは他のすべてのリソースと弦で結ばれています。それぞれの弦が表すのが、ナビゲーションです。

青の弦は、青のリソースから始まって青のリソースで終わっています。これは、青のリソースからブラウズを開始した後、他のリソースにはナビゲートしなかったユーザーの数を表します。金の弦は、青のリソースから始まって金のリソースで終わっています。これは、青のリソースから金のリソースにナビゲートしたユーザーの数を表します。図 4 には青のリソースから残りのリソースへのナビゲーションも同じようにして表されています。

弦 (青から始まる弦) は昇順であり、ユーザー数が少ないほど、細い弦で先に表現されていることに注意してください。したがって、数値を見なくても、どのリソースがより多くのユーザー数を獲得したかを見て取れます。

SVG を使用して弧と弦を描画する

リスト 7 に、図 4 を描画する SVG コードを抜粋します。

リスト 7. 図 4 を描画する SVG コードの抜粋
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
 width="500" height="500">

  <g transform="translate(250,250)">
    <path style="fill: #0000ff;" 
      d="M1.1633760361312584e-14,-190A190,190 0 0,1   
      177.80498922385382,-66.97302298019123L140.372
      3599135688,-52.873439194887816A150,150 0 0,0 
      9.18454765366783e-15,-150Z"></path>
    <path style="fill: #ffd700;" 
      d="M177.80498922385382,-66.97302298019123A190,190 0 0,1 
      141.9432774826573,126.30164677264251L112.06048222315049,99
      .71182639945462A150,150 0 0,0 140.3723599135688,-  
      52.873439194887816Z"></path>
    <path style="fill: #008000;"
      d="M141.9432774826573,126.30164677264251A190,190 0 0,1 -
      141.87314929322426,126.38041584684909L-     
      112.00511786307179,99.77401251067033A150,150 0 0,0 
      112.06048222315049,99.71182639945462Z"></path>
    <path style="fill: #ff0000;" 
      d="M-141.87314929322426,126.38041584684909A190,190 0 
      0,1 -136.03537960886078,-132.64379176830383L-
      107.39635232278484,-104.7187829749767A150,150 0 0,0 -
      112.00511786307179,99.77401251067033Z"></path>
    <path style="fill: #800000;" 
      d="M-136.03537960886078,-132.64379176830383A190,190 0 0,1 -
      3.7240908056998534e-13,-190L-2.9400716887104106e-13,-
      150A150,150 0 0,0 -107.39635232278484,-
      104.7187829749767Z"></path>
    <g>

      <!--Drawing SVG code for chords goes here. -->  

    </g>
  </g>
</svg>

リスト 7 のルート <svg> タグには 1 つの <g> 子タグが含まれていて、この子タグには 5 つの <path> タグと別の内部 <g> 子タグが含まれています。5 つの <path> タグが描画するのは、5 つの色分けされた弧です。内部 <g> タグは弧を描画する SVG コードをラップします。これについては追って説明するとして、まずは <path> タグが 5 つの弧を描画する方法を説明します。

一連の色分けされた弧を描画する

SVG の <path> タグを使用すれば、適切な色で一連の弧を描画するのは簡単です。このタグの目的は、ペンを使って紙に線を引くのと同じように、描画パスを定義することです。パスはクローズド・パス (例えば、三角形) にすることも、オープン・パス (例えば、互いに接続された一連の線) にすることもできます。図 5 に示すような弧を描画するには、クローズド・パスを使用する必要があります。

図 5. <path> タグを使用した弧の描画
弧の描画c

図 5 では、弧のクローズド・パスの境界線を黒で描画し、クローズド・パスを黄色で塗りつぶしています。この弧をペンで描くとしたら、2 本の黒い曲線と 2 本の黒い直線で境界線を描画してから、その内側を黄色で塗りつぶすことになります。

図 4 の 5 つの弧は、それぞれに境界線とクローズド・パスの塗りつぶしに同じ色を使用します。したがって、必要となる <path> タグは、円の弧ごとに 1 つで合計 5 つです。

リスト 7 を見ると、5 つの <path> タグのそれぞれに、styled の2 つの属性があることがわかります。style 属性は描画に使用する色を定義し、d 属性は描画パスを定義します。

d 属性の値 (例えば、M8.572244476756641e-15,-140A140,140 0 0,1 93.95877067680189,103.78703875197591L67.11340762628707,74.13359910855422A100,100 0 0,0 6.123031769111886e-15,-100Z) は、長くて複雑なように思えますが、このフォーマットは正式な SVG 仕様で要求されているものであり、この値によって正確な描画パスが定義されます。

このフォーマットの構成は、M に続いてコンマで区切られた 2 つの数値、次に A に続く複数の数値、次に L に続いてコンマで区切られた 2 つの数値、次にもう 1 つの A に続く複数の数値、そして最後に Z が続く形になっています。このシーケンスが意味する内容は、M の後の数値で定義されたポイントに移動 (Move) し、次に A の後の数値で定義された弧 (Arc) を描画し、それから L の後の数値で定義されたポイントまで線 (Line) を描画し、そしてもう 1 つの弧 (Arc) (2 番目の弧) を描画するというものです。最後の Z は、最初の位置に戻って、クローズド・パスの形にすることを意味します。

嬉しいことに、このシーケンスが必要な弧を描画する方法については、これ以上詳しい内容を知る必要はありません。なぜなら、これらの値はすべて D3 ライブラリーを使用して計算されているからです。このように、このライブラリーには複雑な図を描画するために簡単に使える機能が揃っています。この後すぐ、すべての描画計算を行って、図 4 の完全な SVG コードを動的に生成する D3 JavaScript コードを記載します。

弧を描画するために必要となるのは、円ごとの 5 つの <path> タグだけです。ブラウザーで Listing7.svg ファイル (「ダウンロード」を参照) を開くと、図 6 に示す弦のない色分けされた弧が表示されます。

図 6. 色分けされた弧
色分けされた弧

次は、ナビゲーションを表す弦の描画方法を説明します。

弦を描画する

弧と同じように、弦は 5 つ (弦ごとに 1 つ) の <path> タグのラッパーとなる 1 つの <g> タグを使用して描画します (リスト 8 を参照)。

リスト 8. 5 つの弦を描画する SVG コード
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
 width="500" height="500">
  <g transform="translate(250,250)">

      <!--Drawing SVG code for arcs goes here. -->  

    <g>
      <path d="M9.18454765366783e-15,-150A150,150 0 0,1 
        19.52349842170555,-148.72401624948697Q 0,0 
        9.18454765366783e-15,-150Z" 
        style="fill: #0000ff;">
      </path>
        <path d="M19.52349842170555,- 148.72401624948697A150,150 
        0 0,1 41.344235247425466,-144.18964668729006Q 0,0 

        140.3723599135688,-52.873439194887816A150,150 0 0,1 
        144.99722485611238,-38.41620470616511Q 0,0 
        19.52349842170555,-148.72401624948697Z" 
        style="fill: #ffd700;">
      </path>
      <path d="M111.39598065576133,-100.4536484839712A150,150        
        0 0,1 140.3723599135688,-52.873439194887816Q 0,0 
        84.8772338498757,123.67641316756206A150,150 0 0,1 
        50.93706344958661,141.08655345968583Q 0,0 
        111.39598065576133,-100.4536484839712Z" 
        style="fill: #008000;">
      </path>
      <path d="M-149.71409635840777,9.256854302914952A150,150 
        0 0,1 -140.64142529945457,-52.15351847898602Q 0,0 
        68.6764412000974,-133.35496400243062A150,150 0 0,1 
        111.39598065576133,-100.4536484839712Q 0,0 -
        149.71409635840777,9.256854302914952Z" 
        style="fill: #ff0000;">
      </path>
      <path d="M-59.58349836433014,-137.65829696268898A150,150 
        0 0,1 -1.6078040591602227e-13,-150Q 0,0 
        41.344235247425466,-144.18964668729006A150,150 0 0,1 
        68.6764412000974,-133.35496400243062Q 0,0 -
        59.58349836433014,-137.65829696268898Z" 
        style="fill: #800000;">
      </path>

    </g>
  </g>
</svg>

リスト 8 の弦の <path> タグには、いずれも d 属性に長い複雑な値が設定されていますが、これらの値はすべて、D3 によって計算されます。

リスト 8 には、弧の <path> タグが含まれていません。リスト 8 の SVG コードをブラウザーで表示すると、図 7 のように弧のない (しがって、円の境界線もない) 弦が表示されます。

図 7. 円の境界線と弧がない 5 つの弦のセット
弧がない弦

次は、図 4 の SVG コードを生成する D3 ベースの JavaScript コードについて説明します。

D3 を使用して円弧と弦を描画する

リスト 9 に、JavaScript コードで D3 を使用して図 4 の SVG を生成する 5 つのステップが示されています。

リスト 9. 図 4 の SVG コードを生成する 5 つのステップ
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>

//Step 1:
var navigation = [
  [3057, 3483, 8749, 8465, 4598],
  [ 2371, 7397, 4589, 2861, 8249],
  [ 5972, 5672, 9152, 9725, 8983],
  [ 9763,  8462,  9782, 1953, 5182],
  [ 9567,  1571,  2895, 2783, 1874]
];

var navigationChord = d3.layout.chord()
                      .matrix(navigation);

var chordCalculations = navigationChord.chords;

var colors = [	"blue",
			"gold", 
			"green", 
			"red", 
			"maroon"
		];

var width = 500, height = 500, radius = 150, arcStroke = 40;

//Step 2:
var svg = d3.select("body")
            .append("svg")
            .attr("width", width)
            .attr("height", height)

//Step 3:
            .append("g")
            .attr("transform", function(d,i){
              return "translate(" + width/2 + "," + height / 2 + ")"
            });

//Step 4:
svg.selectAll("path")
.data(navigationChord.groups())
.enter()
.append("path")
.style("fill", function(d, i) { return colors[i]; })
.attr("d", d3.svg.arc().innerRadius(radius)
                       .outerRadius(radius+arcStroke));

//Step 5:
navigationChord.sortSubgroups(d3.ascending);
svg.append("g")
   .selectAll("path")
   .data(chordCalculations)
   .enter()
   .append("path")
   .attr("d", d3.svg.chord().radius(radius))
   .style("fill", function(d, i) {
     if (i < colors.length) return colors[i]})
   .style("opacity", function(d, i){
     if (!(i < colors.length)) return 0 });

</script>
</body>

ステップ 1 では、データを格納して変数を設定します。ここでは navigation という名前の配列にナビゲーション・データを格納し、この配列を内部でレイアウトを処理する d3.layout に渡しています。d3.layout によって行われる計算は、chordCalculations という名前の変数に格納します。この変数が、ステップ 5 で弦を描画するために使用されます。

ステップ 2 では、<svg> ラッパーを生成し、そのサイズを設定します。

ステップ 3 では、すべての描画タグのラッパーとして機能する <g> タグを追加します。

ステップ 4 では、リスト 7 の SVG コードで描画される弧に対して、5 つの <path> タグを生成します。d3.svg.arc() を使用して、色分けされた弧の 5 つすべての <path> タグの d 属性値を生成するための計算をすべて内部で行います。

ステップ 5 では、弦の <path> タグを生成します。最初に昇順で弦を配置した後、弦の計算を D3 の 4 つの魔法のステップ、.selectAll().data().enter().append() に渡します。最後に d3.svg.chord() で、5 つの弦を描画する <path> タグの d 属性の値を生成します。


次回の予告

今回の記事では、SVG と D3 の連係による完全なグラフィック機能を理解するためのお膳立てを整えました。第 2 回では、D3 レイアウトの長所を明らかにします。その長所とは、グラフィックの計算を行って、単一の SVG キャンバス上で形状のコピーを複数描画できることです。さらに、人気度、ユーザーの交流、ナビゲーションといったデータをグラフで表して描画する方法も説明します。そして締めくくりとして、円、弧、弦、グラフ、そしてレイアウトを 1 つの SVG 描画にまとめる方法を紹介します。


ダウンロード

内容ファイル名サイズ
Sample codesource-code.zip10KB

参考文献

学ぶために

製品や技術を入手するために

  • D3: D3 JavaScript ライブラリーをダウンロードしてください。
  • InfoSphere BigInsights: InfoSphere BigInsights の評価版を入手して、保管されている膨大な構造化および非構造化データを管理し、分析してください。
  • InfoSphere Streams: InfoSphere Streams の評価版をダウンロードして、何千ものリアルタイム・ソースからの情報を到着と同時に取り込み、素早く分析して相関させるアプリケーションを構築してください。

議論するために

  • developerWorks コミュニティーに加わってください。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者によるブログ、フォーラム、グループ、Wiki を調べることができます。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source, Web development
ArticleID=942381
ArticleTitle=データの視覚化: 第 1 回 SVG と D3 でブラウジング・メトリクスを視覚化する
publish-date=08292013