D3:Data-Driven Documents(データ駆動型ドキュメント)
D3.js は SVG(ベクター画面)を対象にした JavaScript のライブラリで、棒グラフや折線グラフの作成を主な分野にしています。
Chart.jsがCANVASでの描画をするのに対して、D3.jsは SVG での描画をします。
D3.js のCDN: <script src="https://d3js.org/d3.v7.min.js"></script>
単純な例として、SVG要素に青丸を表示するコードを示します。
ここに、次の記述があります。
<svg id="svg0" width="300" height="200" style="border: solid 1px black"></svg>
function test0() {
// 既存 SVG要素を svg とする
var svg = d3.select("#svg0")
// 図形の作成
var zukei = svg
.append("circle") // D3.js が提供している circle を図形とする
.attr("cx", 100) // circle の属性を指定
.attr("cy", 50)
.attr("r", 30)
.attr("fill", "blue");
}
HTML内に対象とする SVG要素がなく、D3.js で生成します。
次のプログラムが記述されている場所(実行された場所に SVG要素が生成されます。
// SVG要素の創成
var svg = d3.select("body")
.append("svg")
.attr("width", 200)
.attr("height", 100)
.style("border", "solid 1px black");
// 図形の作成
var zukei = svg
.append("circle")
.attr("cx", 100)
.attr("cy", 50)
.attr("r", 30)
.attr("fill", "blue");
このシリーズでは、HTML における SVG要素の場所を固定するという理由だけで「既にSVG要素が定義されている場合」だけにします。
D3.js では、まずX軸とY軸を作成した後で、本体のグラフを作成します。
この軸の作成が、コーディングの大部分を占めます。
D3.js での入力データ形式には、通常配列と連想配列があります。通常配列のほうが簡素ですが、D3.js の説明では連想配列を例にしていることが多いのです。おそらく、他のシステムとの連携を重視しているのでしょう。
データの特徴として、X軸の値が数値の場合と質的データの場合があります。数値の場合は昇順になっている必要がありますが、不等間隔でも構いません。
ここでは、入力データはX軸データ x と2系列のY軸データ y1, y2 から成っていますが、一部を除き x と y1 のグラフにしています。x と y2 のグラフにしたいときは、プログラム中の y1 を t2, d[1] を d[2] とします。
|
svg1 通常配列・X軸=数値(昇順) |
svg2 連想配列・X軸=数値(昇順) |
svg3 通常配列・X軸=質的 |
svg4 連想配列・X軸=質的 |
X軸作成// ================= データの指定 var X軸ラベル = "県"; var ラベルサイズ = "10pt"; var ラベルの色 ="black"; var X目盛数 = 5; var 最小値X = 10; // X軸の目盛りに影響するのでキリのよい値にする // ================= SVG画面の設定 var svg = d3.select("#svg1") var width = 250; var height = 200; var マージン上 = 40; var マージン下 = 40; var マージン左 = 60; var マージン右 = 20; // ========== X軸 var X軸スケール = d3.scaleLinear() .domain([0, d3.max(入力データ, function(d) { return d[0]; }) ]) // 入力データが連想配列のときは d.xにする .range([マージン左, width - マージン右]); var X軸 = d3.axisBottom(X軸スケール) .ticks(X目盛数) .tickSize(マージン上+マージン下 - height); svg.append("g") .attr("transform", "translate(" + 0 + ", " + (height - マージン下) + ")") .call(X軸) .append("text") .attr("fill", ラベルの色) .attr("x", (width-マージン左-マージン右)/2+マージン左) .attr("y", マージン下/2) .attr("text-anchor", "middle") .attr("font-size", ラベルサイズ) .attr("font-weight", "middle") .text(X軸ラベル); |
X軸作成
// ================= データの指定
var X軸ラベル = "県";
var ラベルサイズ = "10pt";
var ラベルの色 ="black";
var X目盛数 = 5;
// ================= SVG画面の設定
var svg = d3.select("#svg3")
var width = 250; var height = 200;
var マージン上 = 40; var マージン下 = 40;
var マージン左 = 60; var マージン右 = 20;
// ========== X軸
var X目盛間隔 = (width - マージン左 -マージン右) / (X目盛数 + 0.5);
var X軸スケール = d3.scaleBand()
.domain(入力データ.map(function(d) { d[0]; }))
// 入力データが連想配列のときは d.xにする
.range([マージン左 + (X目盛間隔/2), width - マージン右]);
var X軸 = d3.axisBottom(X軸スケール)
.ticks(X目盛数)
.tickSize(マージン上+マージン下 - height);
svg.append("g")
.attr("transform", "translate(" + (-X目盛間隔/2) + "," + (height - マージン下) + ")")
.call(X軸)
.append("text")
.attr("fill", ラベルの色)
.attr("x", (width - マージン左 - マージン右) / 2 + マージン左)
.attr("y", マージン下/2)
.attr("text-anchor", "middle")
.attr("font-size", ラベルサイズ)
.attr("font-weight", "middle")
.text(X軸ラベル);
|
||
通常配列と連想配列で下の赤の部分が異なるだけで、それ以外はすべて共通です。
// データの指定で次の変数を定義
var 最小値Y = 0; // Y軸スケールに関係するので、実際の値ではなく、キリのよい値にする。
var Y軸ラベル = "人数";
var Y目盛数 = 5; // 補助線数と考えてもよい。D3.js が自動的に変更することもある。
// ========== Y軸
var Y軸スケール = d3.scaleLinear()
.domain([最小値Y, d3.max(入力データ, function(d) { return d.[1]; })])
// 入力データが連想配列のときは d.y1にする
// 複数グラフのときは、入力データで値が最大の系列を用いる
.range([height - マージン下, マージン上]);
var Y軸 = d3.axisLeft(Y軸スケール)
.ticks(Y目盛数)
.tickSize(マージン左+マージン右 -width);
svg.append("g")
.attr("transform", "translate(" + マージン左 + "," + 0 + ")")
.call(Y軸)
.append("text")
.attr("fill", ラベルの色)
.attr("text-anchor", "middle")
.attr("x", -(height - マージン上 - マージン下) / 2 - マージン上)
.attr("y", -マージン左/2)
.attr("transform", "rotate(-90)") // 縦書きにする
.attr("font-size", ラベルサイズ)
.text(Y軸ラベル);
本体のグラフを作成するのは、むしろ簡単です。
ここでは、折線グラフですが、棒グラフではかなり異なる記述になります。
入力データが通常配列と連想配列の違いは、下の赤字の部分だけです。
svg.append("path") // 折線グラフ
.datum(入力データ)
.attr("fill", "none")
.attr("stroke", 線の色)
.attr("stroke-width", 線の太さ)
.attr("d", d3.line()
.x(function(d) { return X軸スケール(d[0]); })
.y(function(d) { return Y軸スケール(d[1]); }));
// 連想配列のときは d.x. d.y1 とする
複数のグラフにするときは、上を d[1], d[2] として2つ記述すればよい。for ~ はうまくいかない。
すべてに共通ですが、右端の svg4 だけに組み込みました。
ここではグラフの上・中央に表示していますが、グラフの下部に表示することもできます。
マージン上のサイズを調整する必要があります。
var タイトル = "県別男女人数";
var タイトルの色 = "red";
var タイトルサイズ = "14pt";
svg.append("text")
.attr("transform", "translate(" + (width+マージン左-マージン右)/2 + "," + (マージン上)/2 + ")")
// X座標:(width+マージン左-マージン右)/2 グラフの中央
// Y座標:(マージン上)/2
.attr("text-anchor", "middle") // 上の位置に文字列の中央を合わせる
.attr("fill", タイトルの色)
.attr("font-size", タイトルサイズ)
.text(タイトル);
すべてに共通ですが、右端の svg4 だけに組み込みました。
var 系列名 = ["男性", "女性"];
var 線の色 = [4, 2]; // むしろ「系列の色」としたほうが適切かも
var 凡例サイズ = "10pt";
// 系列1
var y0 = height - 10; // 画面の最低部に横に並べる
// グラフの直上なら マージン上 - 10
var x0 = マージン左; // 系列文字列の先頭をここに合わせる
svg.append('text')
.attr("x", x0)
.attr("y", y0)
.attr("font-size", 凡例サイズ)
.attr("fill", 線の色[0])
.text(系列名[0]);
// 系列2 系列の数だけ繰り返す。 for ~ はうまくいかない
x0 = x0 + 100; // 右に100 移動 100 = 系列文字列の長さ + α
svg.append('text')
.attr("x", x0)
.attr("y", y0)
.attr("font-size", 凡例サイズ)
.attr("fill", 線の色[1])
.text(系列名[1]);