D3.js v4/v5 ヒートマップ(heat map)の作り方
D3でのヒートマップの作り方を紹介します。tableの作り方と似ていますが、tableタグではなくSVGのrect要素を使って作成します。
サンプルデモ
サンプルプログラム
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>D3 Heat Map</title> <script src="https://d3js.org/d3.v5.min.js"></script> </head> <body> <script> // 1.データの準備 var width = 1200; // グラフの幅 var height = 800; // グラフの高さ var n = 30; var matrix = new Array(n); for(var i = 0; i < n; i++) { matrix[i] = new Array(n); for(var j = 0; j < n; j++) { matrix[i][j] = Math.random(); } } // 2. SVG領域の設定 var svg = d3.select("body").append("svg").attr("width", width).attr("height", height); g = svg.append("g").attr("transform", "translate(" + 0 + "," + 0 + ")"); // 3. スケールの設定 var scale = d3.scaleBand().rangeRound([0, d3.min([width, height])]).domain(d3.range(n)); var color = d3.scaleSequential( function(t) { return d3.interpolate("white", "steelblue")(t); } ) .domain([0, d3.max(matrix, function(row) { return d3.max(row) })]); // 4. ヒートマップの作成 g.selectAll(".row") .data(matrix) .enter() .append("g") .attr("class", "row") .attr("transform", function(d, i) { return "translate(0," + scale(i) + ")"; }) .selectAll(".cell") .data(function(d) { return d }) .enter() .append("rect") .attr("class", "cell") .attr("x", function(d, i) { return scale(i); }) .attr("width", scale.bandwidth()) .attr("height", scale.bandwidth()) .attr("opacity", 0.9) .attr("fill", function(d) { return color(d); }); </script> </body> </html> |
解説
1.データの準備
デモ用のデータとして2次元配列を準備して乱数を格納します。
1 2 3 4 5 6 7 8 |
var n = 30; var matrix = new Array(n); for(var i = 0; i < n; i++) { matrix[i] = new Array(n); for(var j = 0; j < n; j++) { matrix[i][j] = Math.random(); } } |
2. SVG領域の設定
SVG要素を設定します。今回は必要ありませんが、ラベルを付けることを想定して"g"要素を設定し、その中にヒートマップの要素を設定していきます。
1 2 |
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height); g = svg.append("g").attr("transform", "translate(" + 0 + "," + 0 + ")"); |
3. スケールの設定
棒グラフのラベル作成時と同じようにスケールを設定します。
1 |
var scale = d3.scaleBand().rangeRound([0, d3.min([width, height])]).domain(d3.range(n)); |
d3.scaleBand()は.domain()に入力した配列に応じて.rangeRound()で設定した範囲を当分割して返す関数をscaleに設定するメソッドです。d3.rangeは0からnまでの連続する数の配列([1,2,...,n])を作成するメソッドです。
また、カラースケールを設定します。
1 2 3 4 |
var color = d3.scaleSequential( function(t) { return d3.interpolate("white", "steelblue")(t); } ) .domain([0, d3.max(matrix, function(row) { return d3.max(row) })]); |
カラースケールの作り方についてはこちらを参照ください。d3.scaleSequential()は.domainに入力された範囲を0~1の値に変換後、引数に設定した関数に応じて値を返す関数を設定するメソッドです。d3.interpolateは2つの引数の補間値を返すメソッドです。
4. ヒートマップの作成
dataメソッドを行と列の2度呼び出すことでヒートマップを作成します。行の部分では"g"要素を設定し、"transform"属性を使ってy方向に移動させます。
1 2 3 4 5 6 |
g.selectAll(".row") .data(matrix) .enter() .append("g") .attr("class", "row") .attr("transform", function(d, i) { return "translate(0," + scale(i) + ")"; }) |
列の部分では、y方向に移動した"g"要素内に"rect"要素を設定していきます。y方向は所望の位置となっているので、"y"属性はデフォルトの0とし、"x"属性のみ設定します。
1 2 3 4 5 6 7 8 9 10 |
.selectAll(".cell") .data(function(d) { return d }) .enter() .append("rect") .attr("class", "cell") .attr("x", function(d, i) { return scale(i); }) .attr("width", scale.bandwidth()) .attr("height", scale.bandwidth()) .attr("opacity", 0.9) .attr("fill", function(d) { return color(d); }); |
scale.bandwidth()は要素の幅を呼び出すメソッドです。
まとめ
tableタグベースで作成した表の背景色を変えることでもヒートマップは作成できますが、並び替えなどのアニメーションを設定する際はSVG要素ベースで作成したほうが簡単です。セル内に文字列を表示したい場合はrect要素をdiv要素に変更するとセルから文字がはみ出すことなく表示することができます。