書籍概要

Software Design plus

エンジニアのための データ可視化[実践]入門
D3.jsによるWebの可視化

著者
発売日
更新日

概要

データの可視化とは,「データに含まれる事実・示唆を効率よく発見する技術」,「データから発見した事実・示唆を明確に伝える技術」ということができます。本書では,データ可視化の基本に始まり,何を可視化すべきで,誤った考え方は何かなどを解き明かしたあと,JavaScriptライブラリD3.jsの使い方,D3.jsによるWebの可視化のさまざまなケーススタディまで,エンジニアの方がさまざまな業務の現場で直面するであろうデータ可視化の考え方と手法をわかりやすく解説します。

こんな方におすすめ

  • アプリケーションエンジニア
  • サーバエンジニア/インフラエンジニア
  • データ分析に携わるエンジニア

目次

第1部 序
第1章 データ可視化とは

  • 1.1 データ可視化の歴史
    • 1.1.1 近代グラフの発明家(18世紀)
    • 1.1.2 初期のグラフによる表現(19世紀)
    • 1.1.3 インフォグラフィクスの始まり(20世紀)
    • 1.1.4 学術的な認知
    • 1.1.5 現代
  • 1.2 まとめ

第2部 理論
第2章 データ可視化の種類

  • 2.1 配列
    • 2.1.1 棒グラフ
    • 2.1.2 積上グラフ
    • 2.1.3 ヒストグラムƒ
    • 2.1.4 ファンネルグラフ
    • 2.1.5 折線グラフ
    • 2.1.6 パラレルチャート/レーダーチャート
    • 2.1.7 面グラフ
    • 2.1.8 円グラフ/ドーナツグラフ
    • 2.1.9 箱ひげ図
    • 2.1.10 散布図
    • 2.1.11 散布図行列
    • 2.1.12 バブルチャート
    • 2.1.13 ヒートマップ
    • 2.1.14 色つきテーブル(カラードテーブル/ヒートマップ)
  • 2.2 グラフ
    • 2.2.1 ツリーマップ
    • 2.2.2 パーティションダイアグラム
    • 2.2.3 Sankeyチャート
    • 2.2.4 力学グラフ(force directed graph)
  • 2.3 まとめ

第3章 データ可視化の基礎

  • 3.1 用語
    • 3.1.1 Webサーバのアクセスログ
    • 3.1.2 ソーシャルグラフ
  • 3.2 データセットから可視化への変換プロセス
    • 3.2.1 Webサーバのアクセスログ(再考)
  • 3.3 データ・データ変数・データ変数の性質
  • 3.4 視覚記号・視覚変数・視覚変数の性質
    • 3.4.1 視覚記号
    • 3.4.2 視覚記号が持つ視覚変数
    • 3.4.3 視覚変数が持つ性質
    • 3.4.4 視覚変数を選ぶときの注意点
  • 3.5 データ変数と視覚変数の対応
  • 3.6 可視化を構成する視覚記号
  • 3.7 データセットと可視化の対応関係
  • 3.8 まとめ

第4章 何を可視化すべきか

  • 4.1 「何を可視化するか」をどう決めるか
    • 4.1.1 なぜ可視化したいのか? 可視化の目的を明確にする
    • 4.1.2 KGIとKPIを決定する
    • 4.1.3 KPIの具体的な中身を定義する
  • 4.2 モデル── 目的変数と説明変数,操作変数
  • 4.3 頻繁に用いられる一般的なKPI
  • 4.4 KPI設計の注意点
    • 4.4.1 KGIとの関係が明確であること
    • 4.4.2 必要最低限のKPIに絞る
    • 4.4.3 定義を明確にする
  • 4.5 データ分類の切り口
    • 4.5.1 質的データ,量的データ
    • 4.5.2 尺度水準
    • 4.5.3 データの種類
  • 4.6 KPIを作る
    • 4.6.1 データを組み合わせる
    • 4.6.2 データを変換する
    • 4.6.3 比較用の指標を使う
    • 4.6.4 要約統計量を用いる
  • 4.7 まとめ

第5章 可視化によくある過ち

  • 5.1 避けるべきグラフ
  • 5.2 グラフの恣意的な加工
    • 5.2.1 グラフの省略
    • 5.2.2 棒の幅
    • 5.2.3 目盛操作
  • 5.3 要約統計量による誤解
    • 5.3.1 要約統計量を使うべきかということから考えるべきケース
    • 5.3.2 どの要約統計量を使うべきか選択が難しいケース
  • 5.4 時系列変化の指標を明記しないケース
  • 5.5 相関と因果
    • 5.5.1 見せかけの相関
    • 5.5.2 因果関係の逆転
    • 5.5.3 こじつけと偶然
  • 5.6 誤った可視化をしないためのチェックリスト
  • 5.7 まとめ

第6章 探索的データ解析入門

  • 6.1 探索的データ解析の基本概念
  • 6.2 可視化による探索的データ解析
    • 6.2.1 分布を把握する――ヒストグラムの使い方
    • 6.2.2 3つ以上の分布を比較する――箱ひげ図の使い方
    • 6.2.3 変数の関係を可視化する――散布図と散布図行列
  • 6.3 まとめ

第7章 Webでの可視化の特徴

  • 7.1 インタラクション
    • 7.1.1 選択範囲の絞り込み
    • 7.1.2 ドリルダウン/ドリルアップ
    • 7.1.3 インタラクションと探索的データ解析
  • 7.2 URLによる共有と継続的な可視化
    • 7.2.1 より見られる可視化
    • 7.2.2 継続的なデータ可視化
  • 7.3 アニメーション(時間変化の可視化)
  • 7.4 Webによる可視化の特徴の組み合わせ
  • 7.5 まとめ

第3部 実践
第8章 CoffeeScriptの紹介

  • 8.1 コメント/ブロックコメント/文字列内挿入/ブロックテキスト
  • 8.2 関数
  • 8.3 配列生成,部分配列
  • 8.4 演算子
  • 8.5 ループ
  • 8.6 クラス
  • 8.7 まとめ

第9章 D3.js入門

  • 9.1 D3.jsとは?
  • 9.2 SVGとは
    • 9.2.1 具体例
    • 9.2.2 SVGで利用できる要素
    • 9.2.3 Path要素
    • 9.2.4 g要素
    • 9.2.5 注意点
  • 9.3 D3.jsの基本的な使い方
  • 9.4 基本となるAPI
    • d3.select
    • d3.selectAll
    • selection.attr
    • selection.style
    • selection.text
    • selection.append
    • selection.data / selection.datum
    • selection.enter / selection.exit
    • selector.on
  • 9.5 まとめ

第4部 事例
第10章 ケーススタディ

  • 10.1 本章の概要
    • 10.1.1 実行環境について
  • ケース1 サーバ情報の可視化
  • ケース2 サーバ情報のグラフへのリアルタイムの反映と範囲選択のインタラクション
  • ケース3 効果的な顧客属性・入会経路の可視化
  • ケース4 どこで顧客が脱落するか,離脱率の可視化
  • ケース5 ヒートマップを用いた売上推移可視化
  • ケース6 ニコニコ動画投稿/コメントの可視化
  • ケース7 アクセスフローの可視化
  • ケース8 様々なインタラクションを試してみよう。「税金はどこに行った?」を模写
  • ケース9 単語の解析と可視化
  • ケース10 両箱ひげ図
  • ケース11 状態遷移図
  • ケース12 決定木

付録

  • 付録1 可視化のツール/サービス/ライブラリ
  • 付録2 D3.js API ハンドブック
  • 付録3 参考文献ほか

サポート

ダウンロード

本書で使用するサンプルソースは下記よりダウンロードできます。詳しくは同梱されているindex.htmlをご参照ください。

(2014年2月13日更新)

ダウンロード
サンプルソース

正誤表

本書の以下の部分に誤りがありました。ここに訂正するとともに,ご迷惑をおかけしたことを深くお詫び申し上げます。

(2014年11月7日更新)

P.iv(目次の前のページ)

下記を追加させていただきます。

本書執筆にあたり、丁寧なレビューをくださった本郷 寛様、春山 征吾様、山根 承子様、井戸 一二子様、市原 千里様、古川 陽介様、中野 広基様に感謝の意を表します。また、データ可視化のニーズが高まる時期にタイミングよく執筆の機会を下さった技術評論社 細谷謙吾様に感謝いたします。

P.21 「2.1.4 ファンネルグラフ」

この可視化によって最初の母数がどの段階で大きく数を減らしたのか、ほとんど数を減らすことなく次に進んだ段階がどこなのか、〜
この可視化によって最初の分母がどの段階で大きく数を減らしたのか、ほとんど数を減らすことなく次に進んだ段階がどこなのか、〜

P.75

また、よく件数を見てみると、10 ~ 20代と50代でほとんど差はありませんし、この件数はあくまで発生件数であって、各年代の母数の差を考慮したものではありません。それに、このデータが〜
また、よく件数を見てみると、10 ~ 20代と50代でほとんど差はありませんし、この件数はあくまで発生件数であって、各年代の総数の差を考慮したものではありません。それに、このデータが〜

P.79

ここから定数として5を各データから引いた場合、データは[A:5, B:10, C15]となり、同じくAを基準とした比は[A:1, B:2, C,3]となります。
ここから定数として5を各データから引いた場合、データは[A:5, B:10, C:15]となり、同じくAを基準とした比は[A:1, B:2, C:3]となります。

P.87 「5. 比較可能な状態になっているか?」

母数や単位、尺度が異なる場合、単純に数値の大小を並べて比較することはできません。日本全国で〜
~中略
これは天候ごとの母数について明示されていないため、先の主張はできません。晴天の日は〜
分母や単位、尺度が異なる場合、単純に数値の大小を並べて比較することはできません。日本全国で〜
~中略
これは天候ごとの分母について明示されていないため、先の主張はできません。晴天の日は〜

P.123 リスト9.4 main.js

下記に差し替えさせていただきます。

(function() {
  var circlesInSVG, circleSelectionWithData,
      newCircleSelectionWithData, circlesInNewCircleSelectionWithData,
      colors, data, div, height, r, svg, width;
  width = 600;
  height = 600;
  r = 30;
  colors = ["green", "red", "orange", "blue", "yellow", "cyan",
            "grey", "magenta", "purple", "brown", "black"];
  // 可視化の元となるデータの生成
  data = d3.range(0, 10).map(function(d) {
    return {
      cx: 0 | Math.random() * width,
      cy: 0 | Math.random() * height,
      r: 0 | (Math.random() * r + r)
    };
  });
  // DIV#visualization Elementを取得...(1)
  div = d3.select('div#visualization');
  // SVG Elementの追加...(2)
  svg = div.append('svg');
  // SVG Elementの属性のセット...(3)
  svg.attr('width', width).attr('height', height);
  // svg要素の中のすべてのcircle Elementの取得(空の配列)...(4)
  circlesInSVG = svg.selectAll('circle');
  // データと関連付けられたcircle selection...(5)
  circleSelectionWithData = circlesInSVG.data(data);
  // データ...(6)
  newCircleSelectionWithData = circleSelectionWithData.enter();
  // selectionにcircle Elementを追加...(7)
  circlesInNewCircleSelectionWithData =
    newCircleSelectionWithData.append('circle');
  // circle Elementの属性を指定... (8)
  circlesInNewCircleSelectionWithData
    .attr('r', 20) // 固定の値を属性値にセット... (8a)
    .attr('cx', function(d) { // 対応付けられたデータの値を元に属性値をセット... (8b)
      return d.cx;
    })
    .attr('cy', function(d) {
      return d.cy;
    })
    .attr('fill', function(d, idx) { // インデックスを元にして属性値をセット... (8c)
      return colors[idx % colors.length];
    })
    .style('opacity', 0.6); // スタイルをセット... (8d)
}).call(this);

正しいリストを記したPDFファイルを用意しました。

P.126

この結果はリスト9.8となり、確かにDOMに対してデータが結び付けられていることがわかります。
この実行結果をブラウザ(下記はChrome)のWebInspectorで見ると、リスト9.8のように表示され、確かにDOMに対してデータが結び付けられていることがわかります。

P.126 リスト9.8 selection.dataの実行例

下記に差し替えさせていただきます。

[Array[4], enter: function, exit: function, select: function, selectAll: function, attr: function…]
  0: Array[4]
    0: div
      __data__: Object
        value: 0
        __proto__: Object
      accessKey: ""
      align: ""
      attributes: NamedNodeMap
      ...

P.131

data = [
:
  { "sales": 43, "name": "label 4", "type": 2},
]

data = [
:
  { "sales": 43, "name": "label 4", "type": 2}
]


「2}」の後ろの「,」を取ります。

P.143 本文1行目に下記を追加

dstatの2014年10月26日時点でのversion 0.7.2では`--output`とすると、セミコロンではなく、カンマで区切られたデータで出力されます。そのため執筆時に必要であったセミコロンのパースを行う必要はなくなっています。

P.146

# 表示したいサーバ情報変数
info = "net/total.recv"
drawChart(data, info, "#visualization", {
  width: 1000 # 描画の幅
  height: 100 # 描画の高さ
  margin: [30, 50] # 描画エリアのマージン(数値などの軸を描画するために確保する)
  title: info # タイトル
  })
drawChart("body", data, "net/total.recv", {
  width: width
  height: 60
  margin: margin
  title: info
  })

P.147

for info in infos
  svgs.push drawChart(data, info, "#visualization", {
    width: 1000
    height: 100
    margin: 50
    title: info
  })
for info in infos
  svgs.push drawChart("body", data, info, {
    width: 1000
    height: 60
    margin: 50
    title: info
    })

P.164

{ time: 'Thu Nov 07 2013 15:36:45 GMT+0900 (JST)', stateId: 0, userId: 1}
{ time: 'Thu Nov 07 2013 15:37:20 GMT+0900 (JST)', stateId: 4, userId: 31}
{ time: 'Thu Nov 07 2013 15:37:49 GMT+0900 (JST)', stateId: 3, userId: 8}
...
{ time: 'Thu Nov 07 2013 15:36:45 GMT+0900 (JST)', stageId: 0, userId: 1}
{ time: 'Thu Nov 07 2013 15:37:20 GMT+0900 (JST)', stageId: 4, userId: 31}
{ time: 'Thu Nov 07 2013 15:37:49 GMT+0900 (JST)', stageId: 3, userId: 8}

P.221 selection.attr(name [, value ]) / selection.classed(name [, value ]) /selection.style(name[, value]) / selection.property(name[, value])のサンプル

d3.selectAll('table.tr')
d3.selectAll('table tr')

P.224 selection.node()のサンプル

d3.selectAll('div').empty(); // => 
text
d3.selectAll('div').node(); // => 
text

P.225 サンプル直前の文章

また、transition.transion()を実行することで、〜
また、transition.transition()を実行することで、〜

P.246 サンプル 7〜10行目

value: 0|Math.random() * 50 + 50
startAngle: i / 5 * Math.PI
startAngle: (i + 1) / 5 * Math.PI
}
value: 0|Math.random() * 50 + 50,
startAngle: i / 5 * Math.PI,
endAngle: (i + 1) / 5 * Math.PI
};

P.256 d3.time.format(specifier ) / d3.time.format.utc(specifier )のサンプル

console.log(d3.time.format.iso(new Date)); // => "Sun Jan 5 14:37:20 2014"
console.log(d3.time.format.iso(new Date)); // => "2014-01-05T14:37:20.315Z"

P.268 d3.laout.pieのサンプル

// pieレイアウトを作成
pie = d3.layout.pie().value(function(d){ return d.a;})
  .startAngle(Math.PI / 2).endAngle(-Math.PI / 2);
// 円弧を描画
node = svg.selectAll('g').data(pie(data)).enter().append('g')
  .attr('transform', 'translate(radius, radius)');
node.append('path').attr({
  d: d3.svg.arc().outerRadius(radius),
  fill: function(d, idx){ return color(idx); }
})
var radius = 100;
// pieレイアウトを作成
pie = d3.layout.pie().value(function(d){ return d.a;})
  .startAngle(Math.PI / 2).endAngle(-Math.PI / 2);
// 円弧を描画
node = svg.selectAll('g').data(pie(data)).enter().append('g')
  .attr('transform', 'translate(' + radius+ ', ' + radius + ')');
node.append('path').attr({
  d: d3.svg.arc().outerRadius(radius),
  fill: function(d, idx){ return color(idx); }
})

P.269 d3.layout.bundleのサンプル

  d: line,
  fill: 'none',
  stroke: 'red',
  a: function(d){ console.log(d); }
});
正:
  d: line,
  fill: 'none',
  stroke: 'red'
});

商品一覧