サイトトップ

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

HTML5テクニカルノート

D3.js入門 03: 立て棒グラフに軸の記載を加える


D3.js入門 02: 外部ファイルのデータからSVGで棒グラフを描く」の棒は横向きでした。このグラフは縦棒に改め、左側と下側に数値軸および項目軸を加えます。

01 横棒グラフを縦に変える

横を縦に変えるには、計算する座標のxをyに改めればよいでしょう。けれど、それだけでは足りません。ハンカチの横縞を縦縞に変えるより、もう少し手間がかかります。まず、座標の原点です。x座標は左角が0です。したがって、棒は正の向きに伸ばせば済みます。ところが、y座標は上角が0です。下に伸びる棒グラフは普通使われません。そのため、棒の上端を計算して、そこから起点までの棒を描くことになるのです。つぎに、横棒は下に向けてなりゆきで並べるだけでした。数が増えても、スクロールするのは不自然ではありません。けれど、縦棒はグラフ領域の幅を決めておかないと見づらいでしょう。つまり、棒の幅はデータ数で割り算して求めるのがよさそうです。

それでは、前出「D3.js入門 02: 外部ファイルのデータからSVGで棒グラフを描く」のコード003を、書き替えてゆきましょう。つぎのように、グラフ領域の幅(width)と高さ(height)は予め定めておきます。データの大きさに応じたスケール(y)は、垂直軸にもとづいて計算しなければなりません。なお、対象領域を与えるメソッドとして、continuous.range()に替えてcontinuous.rangeRound()を用いました。数値の丸めができるのですが、今回はとくに差はありません。


var width = 425;  // 420;
var height = 425;
// var barHeight = 20;
/* var x = d3.scaleLinear()
	.range([0, width]); */
var y = d3.scaleLinear()
	.rangeRound([height, 0]);
var chart = d3.select('.chart')
	.attr('width', width)
	.attr('height', height);

棒の幅(barWidth)は、前述のとおりグラフの幅(width)をデータ数(data.length)で割って求めました。そして、縦棒は水平方向に、棒の幅分ずつ位置をずらして並べます。


d3.tsv('data.tsv', type, function(error, data) {
	// x.domain([0, d3.max(data, getValue)]);
	y.domain([0, d3.max(data, getValue)]);
	var barWidth = width / data.length;
	// chart.attr('height', barHeight * data.length);
	var bar = chart.selectAll('g')

		.attr('transform', function(d, i) {
			// return 'translate(0,' + i * barHeight + ')';
			return 'translate(' + i * barWidth + ', 0)';
		});

});

棒(<rect>要素)の上端座標(yプロパティ)は、これも前述のとおり、データの値から計算します。そのうえで、棒の下端までの長さ(heightプロパティ)だけ伸ばして描くということです。数値を示すテキスト(<text>要素)も、棒に応じて位置決めしました。


d3.tsv('data.tsv', type, function(error, data) {

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

function getY(d) {
	return y(d.value);
}

CSSはつぎのように1か所だけ書き替えます。これで、横棒グラフは縦に切り替わるでしょう。ここまで手直ししたスクリプトを、以下のコード001にまとめました。また、サンプル001をjsdo.itに掲げておきます(図にリンクが加えてあります)。

<style>要素

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

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


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

コード001■縦に切り替わった棒グラフ


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

02 項目軸のデータを反映させる

グラフの領域とデータに合わせた棒の長さは、d3.scaleLinear()メソッドで求められました。グラフの横軸は項目で、数値ではありません。けれども、d3.scaleBand()メソッドを使えば、たとえば項目数に応じた棒の幅や項目ごとの位置が求められます。メソッドの使い方は以下のとおりです。

continuous.domain()メソッドには、Array.map()メソッドで得た項目名(nameプロパティ)の配列を渡します。すると、band.bandwidth()メソッドで、棒の幅が得られるのです。また、band.padding()メソッドで棒同士の間に余白を加えました。項目の位置は、translate()関数で決めています。どう変わったかが確かめられるように、jsdo.itにサンプル002を掲げておきましょう。


var x = d3.scaleBand()
	.rangeRound([0, width]).padding(0.1);

d3.tsv('data.tsv', type, function(error, data) {
	x.domain(data.map(getName));

	var bar = chart.selectAll('g')

		.attr('transform', function(d, i) {
			return 'translate(' + x(getName(d)) + ', 0)';
		});
	bar.append('rect')

		.attr('width', x.bandwidth())

	bar.append('text')
		.attr('x', x.bandwidth() / 2)

});

function getName(d) {
	return d.name;
}

サンプル002■D3.js: Vertical SVG Bar Chart with Encoding Ordinal Data


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

03 マージンを加える

垂直の数値軸と水平の項目軸を入れる支度として、グラフ領域の四方にマージンを加えます。グラフを描く<svg>要素(class属性"chart")の幅と高さは、属性としてつぎのように定めておきましょう。


<svg class="chart" width="425" height="425"></svg>

マージンはオブジェクト(margin)にプロパティとして、つぎのように与えておきます。また、グラフに含める部品が増えますので、<svg>要素に子の<g>要素(elements)をひとつ足し、左上のマージンを加えました。そして、グラフの棒の<rect>要素はその中に含めます。垂直軸にメモリをつけるつもりですので、値のテキスト(<text>要素)は除きましょう。<style>要素も、テキストの定めは要らなくなります。ブラウザの開発ツールで確かめると、<g>要素がひとつ増えているはずです(図001)。


var chart = d3.select('.chart');
var margin = {top: 20, right: 30, bottom: 30, left: 40};
var width =  +chart.attr('width') - margin.left - margin.right;  // 465;
var height = +chart.attr('height') - margin.top - margin.bottom;  // 465;

var elements = chart.append('g')
	.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
d3.tsv('data.tsv', type, function(error, data) {

	// var bar = chart.selectAll('g')
	elements.selectAll('.bar')
		.data(data)
		/* .enter().append('g')
		.attr('transform', function(d, i) {
			return 'translate(' + x(getName(d)) + ', 0)';
		});
	bar.append('rect') */
		.enter().append('rect')
		.attr('class', 'bar')
		.attr('x', function(d) {
			return getX(d);
		})

	/* bar.append('text')

		.text(getValue); */
});

<style>要素

/* .chart text {
	fill: white;
	font: 10px sans-serif;
	text-anchor: middle;
} */

図001■開発ツールでHTMLドキュメントを調べると<g>要素が加わっている

図001

04 数値軸と項目軸を加える

グラフに垂直の数値軸と水平の項目軸を加えましょう。軸をつくるのは、それぞれd3.axisLeft()d3.axisBottom()メソッドです。つぎのように、election.call()メソッドで選択に対して呼び出し、引数にはscale関数を渡します。そして、加えた<g>要素にはクラス(axisとaxis--xおよびaxis--y)を与えてください。また、CSSにひとつ定めを書き足します。


d3.tsv('data.tsv', type, function(error, data) {

	elements.append('g')
		.attr('class', 'axis axis--x')
		.attr('transform', 'translate(0,' + height + ')')
		.call(d3.axisBottom(x));
	elements.append('g')
		.attr('class', 'axis axis--y')
		.call(d3.axisLeft(y));

});

<style>要素

.axis--x path {
	display: none;
}

数値軸と項目軸を加えた棒グラフのスクリプトは、つぎのコード002にまとめたとおりです。併せて、このコードは以下のサンプル003としてjsdo.itに掲げました。

コード002■棒グラフに数値軸と項目軸を加えた


var chart = d3.select('.chart');
var margin = {top: 20, right: 30, bottom: 30, left: 40};
var width =  +chart.attr('width') - margin.left - margin.right;
var height = +chart.attr('height') - margin.top - margin.bottom;
var x = d3.scaleBand()
	.rangeRound([0, width]).padding(0.1);
var y = d3.scaleLinear()
	.rangeRound([height, 0]);
var elements = chart.append('g')
	.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
d3.tsv('data.tsv', type, function(error, data) {
	x.domain(data.map(getName));
	y.domain([0, d3.max(data, getValue)]);
	elements.append('g')
		.attr('class', 'axis axis--x')
		.attr('transform', 'translate(0,' + height + ')')
		.call(d3.axisBottom(x));
	elements.append('g')
		.attr('class', 'axis axis--y')
		.call(d3.axisLeft(y));
	elements.selectAll('.bar')
		.data(data)
		.enter().append('rect')
		.attr('class', 'bar')
		.attr('x', function(d) {
			return getX(d);
		})
		.attr('y', function(d) {
			return getY(d);
		})
		.attr('width', x.bandwidth())
		.attr('height', function(d) {
			return height - getY(d);
		});
});
function type(d) {
	d.value = +d.value;
	return d;
}
function getName(d) {
	return d.name;
}
function getValue(d) {
	return d.value;
}
function getX(d) {
	return x(d.name);
}
function getY(d) {
	return y(d.value);
}

サンプル003■D3.js: Vertical SVG Bar Chart with XY Axes


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

作成者: 野中文雄
作成日: 2017年1月14日


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