サイトトップ

Director Flash 書籍 業務内容 プロフィール

HTML5テクニカルノート

D3.js入門 02: 外部ファイルのデータからSVGで棒グラフを描く


D3.jsは、視覚表現にSVGが使えます。「D3.js入門 01: 棒グラフを描く」のCSSで表したグラフを、SVGで描いてみましょう。また、グラフにするデータは、外部ファイルから読み込むことにします。

01 SVGでグラフを描く

Scalable Vector Graphics (SVG)は、2次元のベクター表現をXML形式でマークアップする言語です。D3はデータをSVGで描くことができます。「D3.js入門 01: 棒グラフを描く」のコード003「横棒グラフの長さが領域に合わせられる」でつくったCSSのグラフを、SVGを使って描いてみます。D3は使わず、<body>要素にSVGを直に手書きしたのがつぎのコードです(SVのマークアップについては、「チュートリアル」参照)。後に掲げたコード001の簡単なCSSを割り当てます。すると、CSSで描いた前出「D3.js入門 01」コード003のグラフと見た目は変わりません(図001)。

<body>要素

<svg class="chart" width="420" height="120">
	<g transform="translate(0,0)">
		<rect width="40" height="19"></rect>
		<text x="37" y="9.5" dy="0.35em">4</text>
	</g>
	<g transform="translate(0,20)">
		<rect width="80" height="19"></rect>
		<text x="77" y="9.5" dy="0.35em">8</text>
	</g>
	<g transform="translate(0,40)">
		<rect width="150" height="19"></rect>
		<text x="147" y="9.5" dy="0.35em">15</text>
	</g>
	<g transform="translate(0,60)">
		<rect width="160" height="19"></rect>
		<text x="157" y="9.5" dy="0.35em">16</text>
	</g>
	<g transform="translate(0,80)">
		<rect width="230" height="19"></rect>
		<text x="227" y="9.5" dy="0.35em">23</text>
	</g>
	<g transform="translate(0,100)">
		<rect width="420" height="19"></rect>
		<text x="417" y="9.5" dy="0.35em">42</text>
	</g>
</svg>

図001■SVGで描いた棒グラフ

4 8 15 16 23 42

つぎの項で、SVG要素をD3で定めます。そのために、前掲SVGコードで用いられているおもな寸法を、表001にまとめました。なお、グラフの棒の垂直位置は、translate()関数で決めていました。

表001■SVGの要素に定めたおもな寸法

対象 属性
グラフ領域 420
高さ データ数×20
棒幅 データ値×10
棒高さ 19
テキスト水平位置 棒幅 – 3
テキスト垂直位置 棒高さ / 2

コード001■棒グラフに用いるスタイル

<style>要素

.chart rect {
	fill: steelblue;
}
.chart text {
	fill: white;
	font: 10px sans-serif;
	text-anchor: end;
}

02 D3がつくるSVG要素で棒グラフを描く

D3で動的にSVG要素を差し込みますので、<body>要素には<svg>要素(class属性"chart")をひとつだけ加えておきます。

<body>要素

<svg class="chart"></svg>

<div>要素とCSSで描いた「D3.js入門 01: 棒グラフを描く」のコード003を書き替えるかたちで進めましょう。扱うのがSVG要素に変わるものの、コードの組み立てに大きな違いはありません。幅や高さは属性の扱いになりますので、つぎのようにselection.attr()メソッドで定めます。新たなデータの選択(selectionオブジェクト)をメソッドselection.selectAll()で初期化して加え、selection.data()にデータを与えて、selection.append()でデータに応じた子要素(<g>)をつくるのは<div>要素の場合と同じです(「D3.js入門 01: 棒グラフを描く」03「D3で要素を動的に加える」)。垂直方向の位置決めは、前掲SVGコードと同じくtranslate()関数を用いています。


var width = 420;
var barHeight = 20;

var chart = 
d3.select('.chart')
	.attr('width', width)
	.attr('height', barHeight * data.length);
var bar = chart.selectAll('g')
	// .selectAll('div')
	.data(data)
	.enter().append('g')  // div')
	/* .style('width', function(d) {
		return x(d) + 'px';
	}) */
	.attr('transform', function(d, i) {
		return 'translate(0,' + i * barHeight + ')';
	});

グラフの棒は<rect>、値の文字は<text>要素として、つぎのように加えます。用いた寸法は前掲表001のとおりです。データは親の要素(<g>)から得られます。こうして書き替えたスクリプトは、以下のコード002のとおりです。前掲のSVGコードと同じグラフが描かれます(前掲図001参照)。


bar.append('rect')
	.attr('width', x)
	.attr('height', barHeight - 1);
bar.append('text')
	.attr('x', function(d) {
		return x(d) - 3;
	})
	.attr('y', barHeight / 2)
	.attr('dy', '0.35em')
	.text(function(d) {
		return d;
	});

コード002■SVGで横棒グラフを描く


var data = [4, 8, 15, 16, 23, 42];
var width = 420;
var barHeight = 20;
var x = d3.scaleLinear()
	.domain([0, d3.max(data)])
	.range([0, width]);
var chart = d3.select('.chart')
	.attr('width', width)
	.attr('height', barHeight * data.length);
var bar = chart.selectAll('g')
	.data(data)
	.enter().append('g')
	.attr('transform', function(d, i) {
		return 'translate(0,' + i * barHeight + ')';
	});
bar.append('rect')
	.attr('width', x)
	.attr('height', barHeight - 1);
bar.append('text')
	.attr('x', function(d) {
		return x(d) - 3;
	})
	.attr('y', barHeight / 2)
	.attr('dy', '0.35em')
	.text(function(d) {
		return d;
	});

03 データを外部ファイルから読み込む

データは外部ファイルにすると、視覚化の処理と分けられて、扱いやすくなります。D3で読み込めるファイル形式がいくつかある中で、ここではつくりやすいTSV(タブ区切り)を用いることにしましょう。つぎのように、項目をタブで区切り、レコードは改行で分けます。拡張子はtsvです。

data.tsv

name	value
Locke	4
Reyes	8
Ford	15
Jarrah	16
Shephard	23
Kwon	42

そうすると、データを入れた変数はつぎのようにコードから除きます。また、データの値の範囲は読み込んでみないとわかりませんので、continuous.domain()メソッドの呼び出しは後回しです。


// var data = [4, 8, 15, 16, 23, 42];
var width = 420;
var barHeight = 20;
var x = d3.scaleLinear()
	// .domain([0, d3.max(data)])
	.range([0, width]);
var chart = d3.select('.chart')
	.attr('width', width);

TSVファイルは、d3.tsv(メソッドでつぎのように読み込みます。第1引数は、ファイルのURLです。そして、第3引数にロードし終えたときの処理を関数で定めます。第2引数は、レコードごとに加えたい前処理があれば関数で与えます。前処理が要らないときは、省いて構いません。今回加えた関数(type())は、そのままではテキストになってしまう項目(value)の値を数値に変えています。名前のない関数で書くと、第3引数も加わって見にくくなるので、外に定めました。


d3.tsv('data.tsv', type, function(error, data) {
	// ロード後の処理
});
function type(d) {
	d.value = +d.value;
	return d;
}

そして、ロード後の処理を関数本体に移します。このとき、レコードはふたつのプロパティ(nameとvalue)をもつようになりましたので、数値はプロパティを添えて取り出すように書き替えなければなりせん。また、コードが見やすくなるように、引数に受け取ったレコードの数値を返す関数(getValue())も別に定めました。これで、外部TSVファイルから読み込んだデータが、SVGで棒グラフに描かれます。なお、ファイルはローカルで単純に開くと、一般にXMLHttpRequestの制約でデータが読み込めませんので、ローカルサーバーなどでお試しください。


d3.tsv('data.tsv', type, function(error, data) {
	x.domain([0, d3.max(data, getValue)]);
	chart.attr('height', barHeight * data.length);

	bar.append('rect')
		// .attr('width', x)
		.attr('width', function(d) {
			return x(d.value);
		})

	bar.append('text')
		.attr('x', function(d) {
			// return x(d) - 3;
			return x(d.value) - 3;
		})

		.text(getValue);  /* function(d) {
			return d;
		}); */
});

function getValue(d) {
	return d.value;
}

スクリプトはつぎのコード003にまとめました。また、サンプル001をjsdo.itに上げてあります(外部ファイルを読み込む場合はページに埋め込めないのでリンクしました)。

コード003■読み込んだTSVファイルからSVGでグラフを描く


var width = 420;
var barHeight = 20;
var x = d3.scaleLinear()
	.range([0, width]);
var chart = d3.select('.chart')
	.attr('width', width);
d3.tsv('data.tsv', type, function(error, data) {
	x.domain([0, d3.max(data, getValue)]);
	chart.attr('height', barHeight * data.length);
	var bar = chart.selectAll('g')
		.data(data)
		.enter().append('g')
		.attr('transform', function(d, i) {
			return 'translate(0,' + i * barHeight + ')';
		});
	bar.append('rect')
		.attr('width', function(d) {
			return x(d.value);
		})
		.attr('height', barHeight - 1);
	bar.append('text')
		.attr('x', function(d) {
			return x(d.value) - 3;
		})
		.attr('y', barHeight / 2)
		.attr('dy', '0.35em')
		.text(getValue);
});
function type(d) {
	d.value = +d.value;
	return d;
}
function getValue(d) {
	return d.value;
}

サンプル001■D3.js: SVG Bar Chart with Loading Data


>>画像をクリックでjsdo.itへ

作成者: 野中文雄
更新日: 2017年3月3日 XMLHttpRequestの制約について追記。
更新日: 2017年1月14日 「D3.js入門」シリーズのリンクを追加。
作成日: 2017年1月10日


Copyright © 2001-2017 Fumio Nonaka.  All rights reserved.