在d3.js中从csv创建树层次结构

时间:2012-08-20 18:14:53

标签: javascript csv charts d3.js

我已经阅读过类似主题的一些问题,但没有一个答案似乎适用于我的用例(或者我真的很困惑)。

我有一个来自数据库的csv文件转储,我想使用这里找到的树形图示例显示数据的层次结构http://mbostock.github.com/d3/ex/cluster.html

我的csv文件如下所示:

groupGenre,basicGenre,value
Maps,Atlases (Geographic),10
Catalogs,Auction catalogs,28
No larger group,Academic dissertations,451
No larger group,Account books,1
No larger group,Acrostics,56
No larger group,Addresses,62
No larger group,Advertisements,790
No larger group,Allegories,35
No larger group,Almanacs,3401
No larger group,Alphabets,100
No larger group,Anagrams,4
No larger group,Anthologies,133
No larger group,Anti-slavery literature,1

其中value是该类型中出版的图书数量。

以下是我改编的代码,现在根据以下建议进行修改 它也可以在http://dev.stg.brown.edu/projects/Egan/Vis/tree/tree.html

找到
var width = 960,
    height = 2000;

var tree = d3.layout.tree()
    .size([height, width - 160]);

var diagonal = d3.svg.diagonal()
    .projection(function(d) { return [d.y, d.x]; });

var vis = d3.select("#chart").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(40, 0)");

d3.csv("../data/genreNested.csv", function(csv) {

  var nodes = tree.nodes(makeTree(csv));

  var link = vis.selectAll("path.link")
      .data(tree.links(nodes))
    .enter().append("path")
      .attr("class", "link")
      .attr("d", diagonal);

  var node = vis.selectAll("g.node")
      .data(nodes)
    .enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })

  node.append("circle")
      .attr("r", 4.5);

  node.append("text")
      .attr("dx", function(d) { return d.values ? -8 : 8; })
      .attr("dy", 3)
      .attr("text-anchor", function(d) { return d.values ? "end" : "start"; })
      .text(function(d) { return d.key; });
});

//NEW Function to Build Tree from CSV data
function makeTree(nodes) {
    var nodeByGenre = {};

    //index nodes by genre in case they are out of order
    nodes.forEach(function(d) {
        nodeByGenre[d.basicGenre] = d;
    });

    //Lazily compute children.
    nodes.forEach(function(d) {
        var groupGenre = nodeByGenre[d.groupGenre];
        if (groupGenre.children) groupGenre.children.push(d);
        else groupGenre.children = [d]
    });

    return {"name": "genres", "children": nodes[0]}
}

1 个答案:

答案 0 :(得分:2)

第一个问题似乎是您将函数传递给entries而不是按照the docs传递的数组。请尝试将参数csv传递给entries方法。

function makeTree(csv) {
   var data = d3.nest()
        .key(function(d) {return d.genre; })
        .key(function(d) {return d.groupGenre; })
        .entries(csv);

   return data;
}

第二个问题是,您的makeTree函数未返回tree.nodes所期望的树结构,请参阅文档here。您希望使用makeTree方法创建如下对象。

 var root = 
 {
 "basicGenre": "Maps",
 "value" : 5,
 "children": [
  {
   "basicGenre": "Atlases (Geographic)",
   "value" : 10
   "children": [
    {
     "basicGenre": "Atlases 1",
     "children": []
    },
    {
     "basicGenre": "Atlases 2",
     "children": []
    }
   ]
  }
 ]
}

基本上,您需要根据groupGenrebasicGenre创建一个类似于heiarchary的树,所有这些都位于一些包含所有根节点的下方。

您可能还需要查看this SO question,因为它会处理创建传递给tree.nodes的正确对象。

这是一个使用您更新的代码 JSFiddle