d3.js 如何从 csv 或 table 生成树层次结构

san*_*oku 5 javascript tree hierarchical-data d3.js

我有一个包含以下数据的 csv:

world,country,state

World,US,CA

World,US,NJ

World,INDIA,OR

World,INDIA,AP
Run Code Online (Sandbox Code Playgroud)

我需要转换为树层次结构,如下所示:

{

"name": "World",
"children": [
  { "name": "US",
      "children": [
       { "name": "CA" },
       { "name": "NJ" }
     ]
  },
  { "name": "INDIA",
      "children": [
      { "name": "OR" },
      { "name": "TN" }
     ]
  }
Run Code Online (Sandbox Code Playgroud)

] };

使用 d3.nest 我只能得到一个 json 数组,而不是一棵名为“children”的树。我还需要做些什么吗?阅读 API 并没有真正的帮助,而且我在搜索的任何地方都找不到进行转换的代码片段。

And*_*eid 9

根据您的其他问题,我假设您想在 d3 分层布局中使用此分层数据

一旦被 d3.csv/tsv/dsv 等读取,你就会得到一个包含如下对象的数组:

[
  { "world": "World","country": "US","state": "CA" },
  { "world": "World","country": "US","state": "NJ" },
  { "world": "World","country": "INDIA","state": "OR" },
  { "world": "World","country": "INDIA","state": "AP"}
]
Run Code Online (Sandbox Code Playgroud)

我们可以使用 d3 nest 为我们提供大部分用于 d3 层次结构(树、树状图等)布局的可用树的方法:

{ 
  "key": "World", "values": [
    {
      "key": "US", "values": [
        { "world": "World", "country": "US", "state": "CA" },
        { "world": "World", "country": "US", "state": "NJ" }
      ]
    },
    {
      "key": "INDIA", "values": [
        { "world": "World", "country": "INDIA", "state": "OR" }, 
        { "world": "World", "country": "INDIA", "state": "AP" }
      ]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

这是由:

var nestedData = d3.nest()
 .key(function(d) { return d.world; })
 .key(function(d) { return d.country; })
 .entries(data);
Run Code Online (Sandbox Code Playgroud)

这将生成一个数组,数组中的每个项目都是一个根。要使用 d3.nest() 获取上面的 json,我们需要获取数组中的第一个元素,在本例中为nestedData[0];. 另请注意,我们通常不需要嵌套最低级别,在这种情况下是状态

现在我们可以将这些数据提供给d3.hierarchy以获得用于可视化的层次结构。如果您查看文档,我们有与示例相同的数据结构,除了我们的孩子包含在名为“values”而不是“children”的属性中。不用担心,d3.hierarchy 允许我们设置包含子项的属性的名称:

d3.hierarchy(data[, children])

...

为每个数据调用指定的子访问器函数,从根数据开始,并且必须返回表示子数据的数组,如果当前数据没有子数据,则返回 null。如果未指定 children,则默认为:

function children(d) { return d.children; }

因此,要获取从 d3.nest 创建的上述数据,让我们将其提供给 d3.hierarchy:

var root = d3.hierarchy(nestedData[0],function(d) { return d.values; })
Run Code Online (Sandbox Code Playgroud)

现在我们有一个可以输入任何 d3 分层布局的数据集:

[
  { "world": "World","country": "US","state": "CA" },
  { "world": "World","country": "US","state": "NJ" },
  { "world": "World","country": "INDIA","state": "OR" },
  { "world": "World","country": "INDIA","state": "AP"}
]
Run Code Online (Sandbox Code Playgroud)
{ 
  "key": "World", "values": [
    {
      "key": "US", "values": [
        { "world": "World", "country": "US", "state": "CA" },
        { "world": "World", "country": "US", "state": "NJ" }
      ]
    },
    {
      "key": "INDIA", "values": [
        { "world": "World", "country": "INDIA", "state": "OR" }, 
        { "world": "World", "country": "INDIA", "state": "AP" }
      ]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)
var nestedData = d3.nest()
 .key(function(d) { return d.world; })
 .key(function(d) { return d.country; })
 .entries(data);
Run Code Online (Sandbox Code Playgroud)

这是一个带有实际 csv 和更多行和级别的示例


如果 csv 数据结构不同,包含父子对,那么一旦用 d3.csv/tsv/dsv 解析它就会看起来像这样:

[
 {parent: "", name: "World"},
 {parent: "World", name:"US"},
 {parent: "World", name:"India"},
 {parent: "India", name:"OR" },
 {parent: "India", name:"AP" },
 {parent: "US", name:"CA" },
 {parent: "US", name:"WA" }
]
Run Code Online (Sandbox Code Playgroud)

有了这个,我们可以使用d3.stratify的,而不是组合d3.nestd3.hierarchy

var root = d3.hierarchy(nestedData[0],function(d) { return d.values; })
Run Code Online (Sandbox Code Playgroud)
var data = [
 { "world": "World","country": "US","state": "CA" }, 
 { "world": "World","country": "US","state": "NJ" },
 { "world": "World","country": "INDIA","state": "OR" },
 { "world": "World","country": "INDIA","state": "AP"}
];

 
var nestedData = d3.nest()
  .key(function(d) { return d.world; })
  .key(function(d) { return d.country; })
  .entries(data);
	
var root = d3.hierarchy(nestedData[0], function(d) { return d.values; })

// Now draw the tree:

var width = 500;
var height = 400;

margin = {left: 10, top: 10, right: 10, bottom: 10}

var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height);
	  
var g = svg.append("g").attr('transform','translate('+ margin.left +','+ margin.right +')');

	  
var tree = d3.tree()
    .size([height-margin.top-margin.bottom,width-margin.left-margin.right]);

 var link = g.selectAll(".link")
    .data(tree(root).links())
    .enter().append("path")
      .attr("class", "link")
      .attr("d", d3.linkHorizontal()
          .x(function(d) { return d.y; })
          .y(function(d) { return d.x; }));

  var node = g.selectAll(".node")
    .data(root.descendants())
    .enter().append("g")
      .attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
      .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })

  node.append("circle")
      .attr("r", 2.5);
	  
  node.append("text")
     .text(function(d) { return d.data.key; })
	 .attr('y',-10)
	 .attr('x',-10)
	 .attr('text-anchor','middle');
Run Code Online (Sandbox Code Playgroud)
path {
  fill:none;
  stroke: steelblue;
  stroke-width: 1px;
}
Run Code Online (Sandbox Code Playgroud)