D3.js テーブルの描画 - Object.keys(), map()

D3.jsでテーブルを作成する方法を紹介する。

配列の場合

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>D3 Table</title>
  <script src="https://d3js.org/d3.v7.min.js"></script>
</head> 
<body>
  <script>
  var dataset = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
    [10, 11, 12],
  ];
 
  d3.select("body")
    .append("table")
    .attr("border", "1") // 枠線を表示
    .append("tbody")
    .selectAll("tr")
    .data(dataset)
    .enter()
    .append("tr")
    .selectAll("td")
    .data(function(row) { return row; })
    .enter()
    .append("td")
    .text(function(d) { return d; });
  </script>
</body>
</html>

オブジェクトの場合

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>D3 Table</title>
  <script src="https://d3js.org/d3.v6.min.js"></script>
</head>
<body>
  <script>
  var dataset = [
    { "name": "A", "para1": 0, "para2": 5 },
    { "name": "B", "para1": 1, "para2": 6 },
    { "name": "C", "para1": 2, "para2": 7 },
    { "name": "D", "para1": 3, "para2": 8 },
    { "name": "E", "para1": 4, "para2": 9 }
  ]
 
  var columns = Object.keys(dataset[0]);
 
  var table = d3.select("body")
    .append("table")
    .attr("border", "1") // 枠線を表示;
 
  table.append("thead")
    .append("tr")
    .selectAll("th")
    .data(columns)
    .enter()
    .append("th")
    .text(function(d) { return d; });
 
  table.append("tbody")
    .selectAll("tr")
    .data(dataset)
    .enter()
    .append("tr")
    .selectAll("td")
    .data(function(row) {
      return columns.map(function(column) {
        return {column: column, value: row[column]};
      })
    })
    .enter()
    .append("td")
    .text(function(d) { return d.value; });
  </script>
</body>
</html>

Object.keys(dataset[0])は、オブジェクトのキーを配列として取得する関数である。

var columns = Object.keys(dataset[0]);

テーブルヘッダーを作成するために、datasetの最初の行の文字列を抽出する。

Object.keys({ "name": "A", "para1": 0, "para2": 5 })

戻り値:

["name", "para1", "para2"]

また、40行目のd3.entries()は、オブジェクトのキーと値を配列として取り出す関数である。

オブジェクトをdata関数にdatasetとして指定すると、

.data(dataset)

datasetデータは次のように1行ずつrowというオブジェクトとして関数の引数に渡される。

.data(function(row) {
  return columns.map(function(column) {
    return {column: column, value: row[column]};
  })
})

結果として、row単位で受け取り、{column: カラム名, value: 値}のような形を作る。

[
  {"column" : "name",  "value" : "A"},
  {"column" : "para1", "value" : 0},
  {"column" : "para2", "value" : 5}
]