【问题标题】:d3.js how to generate tree hierarchy from csv or tabled3.js 如何从 csv 或 table 生成树层次结构
【发布时间】:2018-04-26 14:55:42
【问题描述】:

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

world,country,state

World,US,CA

World,US,NJ

World,INDIA,OR

World,INDIA,AP

我需要转换成如下所示的树形层次结构:

{

"name": "World",
"children": [
  { "name": "US",
      "children": [
       { "name": "CA" },
       { "name": "NJ" }
     ]
  },
  { "name": "INDIA",
      "children": [
      { "name": "OR" },
      { "name": "TN" }
     ]
  }

] };

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

【问题讨论】:

    标签: javascript d3.js tree hierarchical-data


    【解决方案1】:

    根据您的其他 question,我假设您希望在 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"}
    ]
    

    我们可以使用 d3 嵌套来为 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" }
          ]
        }
      ]
    }
    

    这是用:

    var nestedData = d3.nest()
     .key(function(d) { return d.world; })
     .key(function(d) { return d.country; })
     .entries(data);
    

    这会产生一个数组,数组中的每一项都是一个根。要使用 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; })
    

    现在我们有了一个可以馈送到任何 d3 分层布局的数据集:

    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');
    path {
      fill:none;
      stroke: steelblue;
      stroke-width: 1px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

    Here's an example 带有一个实际的 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" }
    ]
    

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

    var data = [
     {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" }
    ];
    
    // manipulate data:
    
    var root = d3.stratify()
      .id(function(d) { return d.name; })
      .parentId(function(d) { return d.parent; })
      (data);
      
    // 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.name; })
    	 .attr('y',-10)
    	 .attr('x',-10)
    	 .attr('text-anchor','middle');
    path {
      fill: none;
      stroke: steelblue;
      stroke-width: 1px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

    【讨论】:

    • 感谢您详尽而清晰的回答!有没有办法查看具有子结构的层次结构数据或将其导出到 json 文件?使用检查,我可以看到这样的数组数据:▾Object { key: "World" values: ▾Array(2) [ 0: ▾Object { key: "US" values: ▾Array(2) [ 0: ▾Object {世界:“世界”国家:“美国”国家:“加利福尼亚”} 1:▸Object {世界:“世界”,国家:“美国”,国家:“新泽西”}
    • 您可以在浏览器中使用 console.log() 语句查看层次结构,但是复制到 JSON 可能是一个挑战,因为在层次结构中有很多对对象的循环引用。老实说,不确定是否有办法做到这一点(如果有,它是否仍然可以在 d3 分层布局中工作)
    • 请原谅我的新手问题。我能够将层次结构传递给树形图,但仍然无法将其用于树形图。有什么不妥吗? jsbin.com/xequpikomi/edit?html,output
    • 我只看到两件事,因为它不适合评论,请参阅here
    • 很高兴我能提供帮助
    猜你喜欢
    • 2012-08-16
    • 1970-01-01
    • 2011-12-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-07
    • 2012-06-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多