HTML5テクニカルノート
D3.js入門 03: 立て棒グラフに軸の記載を加える
- ID: FN1701006
- Technique: HTML5 / JavaScript
- Library: D3.js 4.4.0
「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>要素が加わっている
04 数値軸と項目軸を加える
グラフに垂直の数値軸と水平の項目軸を加えましょう。軸をつくるのは、それぞれd3.axisLeft()
とd3.axisBottom()
メソッドです。つぎのように、election.call()
メソッドで選択に対して呼び出し、引数にはscale
関数を渡します。そして、加えた<g>
要素にはクラス(axisとaxis--xおよびaxis--y)を与えてください。また、CSSにひとつ定めを書き足します。
<style>要素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)); });
.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へ
- D3.jsを使う
- D3.js入門 01: 棒グラフを描く
- D3.js入門 02: 外部ファイルのデータからSVGで棒グラフを描く
- D3.js入門 04: グラフにアニメーションを加える
- D3.js入門 05: グラフの棒にラベルを加える
作成者: 野中文雄
作成日: 2017年1月14日
Copyright © 2001-2017 Fumio Nonaka. All rights reserved.