スコット・マレイ
コード・アーティスト

Tutorials > D3 > 散布図の作成

散布図の作成

最終更新日 2012年12月30日(原文)  2013年04月21日(翻訳 / h.sakai

前章で作成したグラフは一次元のデータで作った単純な棒グラフです。

2 つの独立した数の組を扱う場合には、もう一つの次元が必要になります。水平軸と垂直軸、あるいは X 軸と Y 軸上の値の組み合わせを表現するような場合です。こうしたデータを視覚的に表現するのによく使われるのが、本章で取り上げる散布図です。

データ

12章の「データ型で学んだように、D3 は幅広い種類のデータセット構造を扱うことができます。単純な配列やオブジェクトの他に、配列の配列、オブジェクトの配列、オブジェクトのオブジェクトなどです。散布図で使うのは配列の配列です。内側の配列はデータセットの各要素、つまり一つの「点」に対応しており、x と y の二つの値だけで構成される配列です。メインの配列(外側の配列)は、点に対応した各要素の配列を格納するための配列です。

var dataset = [
                  [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
                  [410, 12], [475, 44], [25, 67], [85, 21], [220, 88]
              ];

角カッコ [] は配列を表す記号でした。したがってネストした角カッコ [[]] は、配列の中にもう一つ配列があることを意味します。配列の要素はカンマで区切ります。したがって三つの配列を含む配列は、[[],[],[]] となります。

JavaScript はホワイトスペース(空白、タブ、改行文字)を無視するのでしたね?上の配列を読みやすいように書き換えてみましょう。

var dataset = [
                  [   5,   20 ],
                  [ 480,   90 ],
                  [ 250,   50 ],
                  [ 100,   33 ],
                  [ 330,   95 ],
                  [ 410,   12 ],
                  [ 475,   44 ],
                  [  25,   67 ],
                  [  85,   21 ],
                  [ 220,   88 ]
              ];

こうすれば、10 個の配列と散布図上のそれぞれの点が対応していることも一目瞭然です。たとえば一行目の配列 [5, 20]5 が x の値、20 が y の値となります。

散布図

ではコードを書いて行きましょう。SVG 要素の生成を初め、棒グラフで試したコードの大部分がそのまま使えます。

//Create SVG element
   var svg = d3.select("body")
   .append("svg")
   .attr("width", w)
   .attr("height", h);

しかし各データポイントに対応するのは、今回は rect 要素ではなく circle 要素となります。

svg.selectAll("circle")
   .data(dataset)
   .enter()
   .append("circle")

そして指定する属性は、rect 要素では xywidthheight 属性でしたが、circle 要素では cxcyr の各属性となります。

    .attr("cx", function(d) {
        return d[0];
    })
    .attr("cy", function(d) {
        return d[1];
    })
    .attr("r", 5);

Simple scatterplot

ここまでのコードのサンプル画面がこちらです

ここで無名関数がどのようにデータの値にアクセスし、どのようにそれを cxcy の値に渡しているのかに注意してください。function(d) という関数を見つけると、D3 は自動的に現在のデータの値を関数の引数 d に渡します。ここでは dataset 全体配列の中の、一つの部分配列が渡されます。

関数に渡された d が値の配列であった場合(つまり 3.14159 のような単一の値でない場合)、配列内の値にアクセスするためにはブラケット記法を使う必要があります。従ってここでは d ではなく、d[0]d[1] を返しています。d[0] が配列の最初の要素、d[1] が配列の二番目の要素です。

たとえば最初のデータポイントの配列 [5, 20]の場合、配列の最初の値(配列の 0 番目)は 5 であり、二番目の値(配列の 1番目)は 20 となります。

d[0] : 5 を返す
d[1] : 20 を返す

さて、もし全体配列の dataset の値にアクセスしたい場合はどうすればいいでしょうか?たとえば D3 の外でアクセスしたい場合です。その場合もやはりブラケット記法を使います。

dataset[5] : 配列 [410, 12] を返す。

ネストした配列内の値にアクセスするには各カッコを数珠つなぎにします。

dataset[5][1] :12 を返す。

腑に落ちない場合は、もう一度先ほどのサンプル画面を開き、JavaScript コンソール画面を開いて dataset[5]、あるいは dataset[5][1] とタイプしてみましょう。どんな結果になりましたか?

コンソール画面

サイズ

せっかくですから円のサイズをデータに応じて変えてみましょう。y の値で半径を決めるようにしてみます。すべてのr 属性(半径)を一律に 5 にするかわりに、データポイントごとに計算して求めます。

.attr("r", function(d) {
    return Math.sqrt(h - d[1]);
});

内部配列の 2 番目の値( y )を高さ h から引き、「上」にある点ほど半径が大きくなるようにします。円があまり大きくなり過ぎないよう、平方根を取っています。

Scatterplot with sized circles

サンプル画面はこちらです。あまりパッとしない見栄えの上、それほど有益な視覚化にもなっていませんが、ここでは引数 d の使い方、ブラケット記法、データの値から r を設定する方法を理解するようにしてください。

半径に y の値を連動させるのではなく、独立の値を設定したい場合は、内部配列に半径専用の 3 つめの要素を用意し、 d[2] で参照します。

.attr("r", function(d) {
   return d[2];
});

ラベル

次に各データポイントに text 要素でラベルを設定します。ここでも棒グラフで試したコードが再利用できます。

svg.selectAll("text")
    .data(dataset)
    .enter()
    .append("text")

このコードは、SVG の中のすべての text 要素を探し、(ここではまだ一つも text 要素は存在していませんので)各データポイントごとに新しい text 要素を追加しています。次に text メソッドを使って各 text 要素の内容を指定します。

    .text(function(d) {
        return d[0] + "," + d[1];
    })

またややこしそうなコードが出てきましたが、ちょっとだけ辛抱してください。ここでも function(d) を使って各データポイントにアクセスしています。そして関数内で、d[0]d[1]両者を用いることにより、内部配列の両方の値を得ているのです。

プラス(+)記号は、文字列(ここではダブルクォーテーションマークに囲まれたコンマ)と共に使われた場合、結合演算子として働きます。早く言えばこの一行の意味は「d[0]d[1] の値をとりだし、間にカンマを挟んでくっつけろ」です。結果は、例えば 5,2025,67 のような文字列になります。

次に、xy 属性を用いてテキストをどこに配置するかを決めます。ここでは単に d[0]d[1] の値を使っています。circle要素の位置を決めたのと同じ値です。

    .attr("x", function(d) {
        return d[0];
    })
    .attr("y", function(d) {
        return d[1];
    })

最後にフォントスタイルを整えます。

   .attr("font-family", "sans-serif")
   .attr("font-size", "11px")
   .attr("fill", "red");

Scatterplot with labels

これが出来上がりのサンプルです

次のステップ

データを読み込み、新しい要素を生成し、データを用いて新要素の属性値を設定する。こうした D3 のコアとなる概念も、ここまでの説明でご理解いただけたのではないかと思います。

しかしここまで理解してようやくデータ視覚化の入り口に立ったところなのです。出来上がった散布図もお世辞にも見やすいとは言えません。プログラムはせっかくのデータの柔軟性を生かしきれていません。正直、エクセルのグラフウィザードと大差ない出来栄えです(気を悪くされませんように…)。

心配には及びません。D3 はグラフウィザードよりはるかに優れたツールです。しかし美しくインタラクティブなグラフを作成するためには、D3 のスキルをもう一段引き上げる必要があります。次の章では、データの柔軟性を生かすため、D3 のスケールについて学習します。最終章では、散布図をより見やすくするため、軸ゼネレータと軸ラベルについて学習します。ついでグラフにインタラクティブな機能を持たせ、実行時にデータを更新する方法を学習します。

次章はスケール

インタラクティブ・データ・ヴィジュアライゼーション このチュートリアルの書籍版の翻訳がオライリー・ジャパンより発売されました。タイトルは『インタラクティブ・データビジュアライゼーション ―D3.jsによるデータの可視化』です(画像をクリックするとアマゾンに飛びます)。

このチュートリアルを大幅に拡充し、3倍近い内容となっています。JavaScriptを中心に基礎編をさらに詳しく解説し(書籍版第3章)、応用編としてモーション、イベント、レイアウト、地図の作成法、データのエクスポート(PDFやSVG等)の章が追加されています(同9章~13章)。アマゾンのページで目次を見ることができます。

本チュートリアルがわかりにくいと感じられた方、あるいは本チュートリアルを終え、さらに応用力を身につけたいと思われた方のどちらにもお勧めの内容となっています。

翻訳はコンピュータ・プログラミング関連書籍を多数翻訳されている長尾高弘氏です。