ユーザー体験を向上させる、データビジュアライゼーションライブラリD3.js

ブログメインビジュアル こんにちは、フロントエンドエンジニアの峯です。
業界問わず、至る所でテクノロジーが活用され、たくさんのデータを蓄積している環境は多いのではないでしょうか。 データを見ることで現状を知ることができます。そして課題を見つけて有効なアプローチを取ることができます。

データは溜まっているが、まだ活用ができていないのであれば、提供する価値を最大化させるために、データを活用することは有効な手段です。

今回この記事では、データを可視化して価値を提供しているサービス事例とともに、データ可視化(以下、データビジュアライゼーション)に必要となる技術を紹介したいと思います。



目次


身近なデータビジュアライゼーション

少し前までは、事業者向けの管理ツールとしてのみ活用されているイメージだったデータビジュアライゼーションですが、 最近では、普段私たちが触れているサービスでも、見ることが多くなってきているように感じます。

単にテーブルに数値を表示するだけでは、どのような状態なのか理解するのに時間がかかります。 データビジュアライゼーションを行い、データを分かりやすく表現することで、ひと目で良い状態なのか、悪い状態なのかが分かるようになります。

データビジュアライゼーション技術は、決して新しい技術ではないですが、DX文脈でこれから更にエンジニアとして必要性を求められる機会も増えて来ると思いますし、エンジニア意外の職種でも表現手法を知っていることで、提供できる価値は上がるのではないかと思います。

ではまず、いくつか事例を紹介します。

【事例1】 新型コロナウイルス感染症対策サイト

1つ目は、OSSとして開発され、各自治体で運営されているコロナウイルス感染症対策サイトです。 棒グラフや折れ線グラフによって、推移が可視化された事例です。コロナ禍で毎日このようなグラフを目にする機会が増えたのではないでしょうか。

Image from Gyazo

参照:東京都新型コロナウイルス感染症対策サイト

棒グラフと折れ線グラフで可視化され、増減の推移が表現されています。一つの表に2つのグラフをかけ合わせて、日別の推移、週間推移がまとめて確認できます。



【事例2】 家計簿アプリ マネーフォワード

2つ目は、家計簿アプリのマネーフォワードです。 円グラフで、全体の支出に対して占めるカテゴリの割合をひと目で確認できます。円グラフ以外にも棒グラフや折れ線グラフなども目的に合わせて利用されています。

Image from Gyazo

参照:マネーフォワード



【事例3】 GoogleAnalytics

3つ目に、サイト解析サービスでおなじみのGoogleAnalyticsがあります。 棒グラフや、円グラフといった基本的な表現以外に、コホート分析や階層構造チャート、地図を利用したものなど様々な可視化手法が用いられています。

Image from Gyazo

参照:アナリティクス ヘルプ

以上のように、データビジュアライゼーションは、単純な集計データを表現するだけにとどまらず、機械学習による分析結果を表示するなど、複雑な情報を見やすく、わかりやすく表現することができます。


また、インタラクションをつけることで、より使いやすさを向上させることもできるでしょう。 利用するグラフは、ユーザーに何を見せたいかによって使い分けましょう。



JavaScriptライブラリ D3.js

データビジュアライゼーションを実現するライブラリにも複数ありますが、今回はD3.jsを紹介します。
D3.jsは、HTML、SVG、CSSを活用してデータ表現を行うJavaScriptライブラリです。このライブラリは自由度が高く、創造性の高い表現が可能です。

棒グラフや円グラフなど、基本的な表現のみを行うだけであれば、グラフ描画用のライブラリを利用することをオススメします。 グラフ作成APIが用意されているわけではなく、データ整形用のAPIとDOM操作を駆使して独自のビジュアルを作成する所が特徴です。見せ方や動作などカスタマイズ性が求められる場合にD3.jsはメリットを発揮します。


ライブラリの導入

CDNまたは、npmで導入することができます。

描画用のデータを用意します。 今回は棒グラフを作成していこうと思います。データはJSON形式で用意しました。 (CSVデータをJSONに整形して利用することもできます!)


data.json

[
	{
		"id": 1,
		"value": 100
	},
	{
		"id": 2,
		"value": 70
	},
	{
		"id": 3,
		"value": 150
	},
	{
		"id": 4,
		"value": 50
	},
	{
		"id": 5,
		"value": 200
	},
	{
		"id": 6,
		"value": 130
	}
]



グラフの作成

グラフの作成を行います。
今回は、HTMLファイルにSVGタグが既に用意されている状態でスクリプトを書いていきます。

index.html

<!DOCTYPE html>
<html lang="ja" dir="ltr">
  <head>
    <meta charset="UTF-8" />
    <title>d3.js sample</title>
  </head>
  <body>
    <!-- svgタグの中にグラフを作成していきます -->
    <svg xmlns="http://www.w3.org/2000/svg"></svg>
    <script src="src/index.js"></script>
  </body>
</html>




まずは、グラフを描画するSVGエリアを確保します。

d3.selectAPIでSVGタグを選択して、幅・高さを設定します。見た目を整えるためにマージン定数を用意して余白を確保しました。
同時にSVGタグ内にSVGグループタグ(<g>)を追加しています。余白を持たせるためにtransformプロパティで位置を調整しています。

index.js

const MARGIN = { top: 20, right: 20, bottom: 50, left: 50 };
const WIDTH = 300 - MARGIN.left - MARGIN.right;
const HEIGHT = 500 - MARGIN.top - MARGIN.bottom;

const chart = d3
  .select("svg")
  .attr("width", WIDTH + MARGIN.left + MARGIN.right)
  .attr("height", HEIGHT + MARGIN.top + MARGIN.bottom)
  .append("g")
  .attr("transform", "translate(" + MARGIN.left + "," + MARGIN.top + ")");




次に、座標取得用のメソッドを作成します。

getY()は、高さ(HEIGHT)を最大値とした範囲に、0~200(Y軸ラベルとして利用)の定量的な領域を持たせています。 データを受け取ると、範囲を基準としたY座標位置を返します。(=棒グラフの高さとなる)

getX()は、幅(WIDTH)を最大値としたエリアに、padding()の設定値を棒グラフ間の間隔として余白を取り、データの描画開始位置を返します。

index.js

const getY = d3.scaleLinear().domain([0, 200]).range([HEIGHT, 0]);

const getX = d3
  .scaleBand()
  .rangeRound([0, WIDTH])
  .padding(0.2)
  .domain(
    DATA.map(function (d) {
      return d.id;
    })
);




棒グラフの作成を行います。
SVGタグの中に、SVGグループタグを追加して更にその中に、棒グラフ用の長方形エリアを作っていきます。
JSONデータを受け取り、先程のgetX()getY()に対象のデータ項目を引数として渡して、描画位置を取得します。


index.js

// 棒グラフ描画エリアのsvgグループ
const bar = chart
  .selectAll("g")
  .data(DATA)
  .enter()
  .append("g")
  .attr("transform", function (d, i) {
    return "translate(" + getX(d.id) + ",0)";
});

// 棒グラフの描画位置、データのvalueに応じた高さを設定
bar
  .append("rect")
  .attr("fill", "skyblue")
  .attr("y", function (d) {
    return getY(d.value);
  })
  .attr("height", function (d) {
    return HEIGHT - getY(d.value);
  })
  .attr("width", getX.bandwidth())




最後に、座標ラベルを追加して完成です。

index.js

// Y座標の作成 0~200でY軸ラベルを適当に作成してくれている
chart.append("g").call(d3.axisLeft(getY));

// X座標の作成 idをそのままX軸ラベルとして利用
chart
  .append("g")
  .attr("transform", "translate(0," + HEIGHT + ")")
  .call(d3.axisBottom(getX));



棒グラフが完成しました!
全ソースをご覧になりたい方は以下からご覧ください。デモとしても確認いただけます。


さいごに

スクリプトの内容をご覧いただいたように、D3.jsで棒グラフを作成しようとすると、すべての要素を自作する必要があるため、先程も述べましたが、作成したいグラフ用のライブラリを活用した方が遥かに手軽に作成することができます。

しかし、見た目のデザイン面やインタラクションの部分など要件が複雑になると、グラフ用のライブラリでは実現できないことがあります。

オリジナリティを求められる場合は、D3.jsは有効的です。豊富なD3.jsのAPIを使いこなすことで圧倒的に表現の幅が広がると思います。

この記事を書いた人 mine 2019年1月 中途入社のゴルフにはまっているフロントエンドエンジニア
COBOL開発経験がありますが平成生まれです。
TOP