D3.js 面グラフ(area chart)の作成方法

D3で基本チャートの面グラフを作成する方法を紹介する。

サンプルプログラム

コードを確認

サンプルコード

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>D3 Area Chart</title>
  <script src="https://d3js.org/d3.v7.min.js"></script>
</head>

<body>
  <script>
    // 1. データ準備
    var dataset = [
      [1, 15],
      [5, 25],
      [25, 30],
      [85, 40],
      [100, 42],
      [220, 40],
      [250, 50],
      [330, 95],
      [410, 30],
      [475, 44],
      [480, 50]
    ];

    var width = 400; // グラフ幅
    var height = 300; // グラフ高さ
    var margin = { "top": 30, "bottom": 60, "right": 30, "left": 60 };

    // 2. SVG領域設定
    var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);

    // 3. 軸スケール(目盛り)設定
    var xScale = d3.scaleLinear()
      .domain([0, d3.max(dataset, function (d) { return d[0]; })])
      .range([margin.left, width - margin.right]);

    var yScale = d3.scaleLinear()
      .domain([0, d3.max(dataset, function (d) { return d[1]; })])
      .range([height - margin.bottom, margin.top]);

    // 4. 軸表示
    var axisx = d3.axisBottom(xScale).ticks(5);
    var axisy = d3.axisLeft(yScale).ticks(5);

    svg.append("g")
      .attr("transform", "translate(" + 0 + "," + (height - margin.bottom) + ")")
      .call(axisx)
      .append("text")
      .attr("fill", "black")
      .attr("x", (width - margin.left - margin.right) / 2 + margin.left)
      .attr("y", 35)
      .attr("text-anchor", "middle")
      .attr("font-size", "10pt")
      .attr("font-weight", "bold")
      .text("X Label");

    svg.append("g")
      .attr("transform", "translate(" + margin.left + "," + 0 + ")")
      .call(axisy)
      .append("text")
      .attr("fill", "black")
      .attr("text-anchor", "middle")
      .attr("x", -(height - margin.top - margin.bottom) / 2 - margin.top)
      .attr("y", -35)
      .attr("transform", "rotate(-90)")
      .attr("font-weight", "bold")
      .attr("font-size", "10pt")
      .text("Y Label");

    // 5. 領域(area)表示
    svg.append("path")
      .datum(dataset)
      .attr("fill", "rgba(70, 130, 180, 0.3)")
      .attr("d", d3.area()
        .x(function (d) { return xScale(d[0]); })
        .y1(function (d) { return yScale(d[1]); })
        .y0(yScale(0))
      );

    svg.append("path")
      .datum(dataset)
      .attr("fill", "none")
      .attr("stroke", "steelblue")
      .attr("stroke-width", 1.5)
      .attr("d", d3.line()
        .x(function (d) { return xScale(d[0]); })
        .y(function (d) { return yScale(d[1]); })
      );
  </script>
</body>

</html>

サンプルコード説明

散布図を対象にグラフを作成する方法のチュートリアルと、折れ線グラフを作成する方法を紹介している。面グラフは折れ線チャートから少し変更するだけで作成できる。

1. データ準備

余白を設定するためにオブジェクトを用意する。

var margin = { "top": 30, "bottom": 60, "right": 30, "left": 60 };

軸を表示するため、下端と左側のマージンを大きく設定する。

2. SVG領域設定

SVGの表示領域を設定する。

3. 軸スケール設定

軸スケールを設定する。

d3.scaleLinear()

上のコードで、domainで設定した範囲をrangeで設定した範囲へ変換する関数を設定する。線グラフの座標を画面のピクセル値へ変換する関数を作成する。

4. 軸表示

D3の関数d3.axisBottom()d3.axisLeft()を使用して軸要素を設定する。引数を軸スケールの設定で作成した関数にし、callで呼び出すことでSVG要素が自動的に追加される。

var axisx = d3.axisBottom(xScale).ticks(5);
var axisy = d3.axisLeft(yScale).ticks(5);

svg.append("g")
  .attr("transform", "translate(" + 0 + "," + (height - margin.bottom) + ")")
  .call(axisx)

svg.append("g")
  .attr("transform", "translate(" + margin.left + "," + 0 + ")")
  .call(axisy)

.ticks()は軸目盛りの数を制御するメソッドである。整数で設定する。

軸を呼び出し、text要素で軸ラベルを追加する。

  .append("text")
  .attr("fill", "black")
  .attr("x", (width - margin.left - margin.right) / 2 + margin.left)
  .attr("y", 35)
  .attr("text-anchor", "middle")
  .attr("font-size", "10pt")
  .attr("font-weight", "bold")
  .text("X Label");

  .append("text")
  .attr("fill", "black")
  .attr("x", -(height - margin.top - margin.bottom) / 2 - margin.top)
  .attr("y", -35)
  .attr("transform", "rotate(-90)")
  .attr("text-anchor", "middle")
  .attr("font-weight", "bold")
  .attr("font-size", "10pt")
  .text("Y Label");

"text-anchor"はテキストの位置合わせ用の属性で、"middle"で中央揃えを設定している。それぞれ軸に重ならないように35pxずつ移動している。

5. 面領域表示

面グラフを"path"要素で表示する。ここが線グラフと異なる部分である。

svg.append("path")
  .datum(dataset)
  .attr("fill", "rgba(70, 130, 180, 0.3)")
  .attr("d", d3.area()
    .x(function(d) { return xScale(d[0]); })
    .y1(function(d) { return yScale(d[1]); })
    .y0(yScale(0))
  );

svg.append("path")
  .datum(dataset)
  .attr("fill", "none")
  .attr("stroke", "steelblue")
  .attr("stroke-width", 1.5)
  .attr("d", d3.line()
    .x(function(d) { return xScale(d[0]); })
    .y(function(d) { return yScale(d[1]); })
  );

データバインディングは次のようにdatumを使用している。

.datum(dataset)

1つずつデータをバインドするdataとは異なり、"path"にデータセット全体を追加する。また、色の指定時に"rgba(70, 130, 180, 0.3)"を使用している。RGB値を0から255で、alpha値(透明度)を0から1で設定する。"opacity"属性でも透明度を設定できるが、"fill"属性と"stroke"属性の透明度を別々に変更したい場合はrgbaを使用する。ここでは"stroke"属性を設定していないため、どちらでもよい。

面領域を描くとき、path"d"属性を次のD3メソッドで設定する。

d3.area()
  .x(function(d) { return xScale(d[0]); })
  .y1(function(d) { return yScale(d[1]); })
  .y0(yScale(0))

.x()x座標を指定する関数を、y0に下側(今回はy=0)のy座標を、y1に上側のy座標を設定する。

2つ目の"path"は折れ線チャートと同じように境界線を設定する。不要な場合は除外する。

d3.line()
  .x(function(d) { return xScale(d[0]); })
  .y(function(d) { return yScale(d[1]); })

上のコードは境界用"path""d"属性を作成する関数である。

まとめ

棒グラフ散布図も同じアルゴリズムで作成できる。参照するとよい。