D3.js v4/v5 コンター図の作成 (d3.contours 使い方)
D3でコンター図(contours plot)の作り方を紹介します。
サンプルデモ
サンプルプログラム
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 57 58 59 60 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>D3 Contours Plot</title> <script src="https://d3js.org/d3.v5.min.js"></script> <!-- <script src="https://d3js.org/d3.v4.min.js"></script> --> <!-- <script src="https://d3js.org/d3-hsv.v0.1.min.js"></script> --> <!-- <script src="https://d3js.org/d3-contour.v1.min.js"></script> --> </head> <body> <script> // 1. データの準備 var width = 800; // グラフの幅 var height = 600; // グラフの高さ function himmelblaus(x, y) { return(x * x + y - 11) * (x * x + y - 11) + (x + y * y - 7) * (x + y * y - 7); } var n = 240; var m = 125; var k = 0; var values = new Array(n * m); for(var j = 0; j < m; ++j) { for(var i = 0; i < n; ++i) { var x = i / (n - 1) * 10 - 5; var y = j / (m - 1) * 10 - 5; values[k] = himmelblaus(x, y); ++k; } } // 2. SVG領域の設定 var svg = d3.select("body").append("svg").attr("width", width).attr("height", height); // 3. しきい値の設定 var thresholds = d3.range(0, 20).map(function(p) { return 7*p; }); // 4. データ変換 var contours = d3.contours() .size([n, m]) .thresholds(thresholds); // 5. カラースケールの設定 var color = d3.scaleSequential(function(t){return d3.hsl(t*230, 1, 0.5) + ""}).domain([140,0]); // 6. コンター用SVG要素の設定 svg.selectAll("path") .data(contours(values)) .enter() .append("path") .attr("d", d3.geoPath(d3.geoIdentity().scale(width / n))) .attr("fill", function(d) { return color(d.value); }) .attr("stroke","white") .attr("stroke-width","0.5"); </script> </body> </html> |
解説
d3.contourはv5から追加された機能ですが、v4でもHTMLファイルのヘッダー部分で下記を記載してモジュールを呼び出せば使うことができます。
1 2 |
<script src="https://d3js.org/d3-hsv.v0.1.min.js"></script> <script src="https://d3js.org/d3-contour.v1.min.js"></script> |
1. データの準備
コンター用のデータを準備します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function himmelblaus(x, y) { return(x * x + y - 11) * (x * x + y - 11) + (x + y * y - 7) * (x + y * y - 7); } var n = 240; var m = 125; var k = 0; var values = new Array(n * m); for(var j = 0; j < m; ++j) { for(var i = 0; i < n; ++i) { var x = i / (n - 1) * 10 - 5; var y = j / (m - 1) * 10 - 5; values[k] = himmelblaus(x, y); ++k; } } |
この部分は、コンター用のサンプルデータvalues[]の作成です。こちらのHimmelblau's functionを参考にさせて頂きました。コンター用のデータ(values)はn(x方向の配列要素数) × m(y方向の配列要素数)の要素数をもつ一次元配列として設定する必要があります。
2. SVG領域の設定
SVGタグを設定します。
1 |
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height); |
3. しきい値の設定
しきい値を設定する一次元の配列(thresholds)を定義します。
1 |
var thresholds = d3.range(0, 20).map(function(p) { return 7*p; }); |
ここでは、D3のメソッドを使って配列を作成しました。d3.range(a,b)はaからbまでの連続値の配列を作成します([0,1,2,..])。.mapメソッドは各配列の値を設定した関数に応じて変更するものです。今回は[0,7,14,...]の配列を作成し、これをコンター図のしきい値とします。
4. データ変換
コンター図用に用意したデータを変換するための関数をメソッドのd3.contoursを使って設定します。
1 2 3 |
var contours = d3.contours() .size([n, m]) .thresholds(thresholds); |
.sizeでは、データの要素数n(x方向の配列要素数) × m(y方向の配列要素数)のサイズを、.thresholdsではしきい値設定用の配列を指定します。
5. カラースケールの設定
コンター図の色分け用のカラースケールをD3のメソッドを使って設定します。
1 |
var color = d3.scaleSequential(function(t){return d3.hsl(t*230, 1, 0.5) + ""}).domain([140,0]); |
d3.scaleSequential(function(t){}).domain([,])は、domainで設定した範囲を0.0~1.0に線形変換して内部の関数に渡し、内部の関数の返り値を出力する関数をcolorに設定します。d3.hslは、HSL色空間のRGB値を算出してくれるものです。d3.hslの一つ目の変数が角度に相当するものですが、0~230度に設定するとサンプルのような色使いになります。カラースケールの作り方についてはこちらを参照ください。
6. コンター用SVG要素の設定
SVG要素を設定します。
1 2 3 4 5 6 7 8 |
svg.selectAll("path") .data(contours(values)) .enter() .append("path") .attr("d", d3.geoPath(d3.geoIdentity().scale(width/n))) .attr("fill", function(d) { return color(d.value); }) .attr("stroke","white") .attr("stroke-width","0.5"); |
dataに設定したデータ変換関数によって変換したデータを設定し、"path"要素でコンター図を描きます。"d"属性にはコンター図用に変換するd3.geoPath()を用います。引数として設定したd3.geoIdentity().scale(width/n)は、スケールを変換するもので、デフォルトではm×n pxで描かれますので所望の大きさに変換します。
まとめ
D3のv5にはカラーテーマが複数用意されていますので、あわせて使えば様々なシチュエーションに対応できます。