D3树形图的垂直分离

11
我正在使用D3树状图布局,类似于这个网站上的例子:http://mbostock.github.com/d3/talk/20111018/tree.html。我已经改变了它以适应我的需要,但遇到了一个问题。示例也有同样的问题,如果您打开了太多节点,它们会变得紧凑,使阅读和交互变得困难。我希望定义节点之间的最小垂直空间,并重新调整舞台大小以允许这样的间距。 我尝试修改分离算法来解决这个问题:
.separation(function (a, b) {
    return (a.parent == b.parent ? 1 : 2) / a.depth;
})

那不起作用。我还尝试计算哪个深度有最多的子节点,然后告诉舞台的高度为children * spaceBetweenNodes。这让我更接近了,但仍然不准确。

depthCounts = [];
nodes.forEach(function(d, i) { 
    d.y = d.depth * 180;

    if(!depthCounts[d.depth])
        depthCounts[d.depth] = 0;

    if(d.children)
    {
        depthCounts[d.depth] += d.children.length;
    }
});

tree_resize(largest_depth(depthCounts) * spaceBetweenNodes);

我也尝试在下面的方法中更改节点的x值,以便计算y分离,但没有成功。我本来想发布这个更改,但是我从我的代码中删除了它。

nodes.forEach(function(d, i) { 
    d.y = d.depth * 180;
});

如果您知道一种方法可以实现节点之间的最小垂直间距,请提供建议。非常感谢。我可能遗漏了一些非常简单的东西。

4个回答

7

4

在Google Groups的一位用户的帮助下,我得以解决这个问题。我找不到那篇文章了。解决方案需要您在D3.js的一个位置进行修改,虽然这并不被推荐,但这是我所能找到的唯一解决此问题的方法。

从大约5724行或此方法开始:d3_layout_treeVisitAfter

更改为:

d3_layout_treeVisitAfter(root, function(node) {
    node.x = (node.x - x0) / (x1 - x0) * size[0];
    node.y = node.depth / y1 * size[1];
    delete node._tree;
});

收件人:

d3_layout_treeVisitAfter(root, function(node) {
    // make sure size is null, we will make it null when we create the tree
    if(size === undefined || size == null) 
    { 
        node.x = (node.x - x0) * elementsize[0]; 
        node.y = node.depth * elementsize[1]; 
    } 
    else 
    { 
        node.x = (node.x - x0) / (x1 - x0) * size[0];
        node.y = node.depth / y1 * size[1]; 
    } 
    delete node._tree;
});

在5731行以下添加一个名为elementsize的新变量,并将其默认设置为[1,1]
var hierarchy = d3.layout.hierarchy().sort(null).value(null)
    , separation = d3_layout_treeSeparation
    , elementsize = [ 1, 1 ] // Right here
    , size = [ 1, 1 ];

下面有一个名为tree.size = function(x)的方法。在该定义下方添加以下内容:

tree.elementsize = function(x) {
    if (!arguments.length) return elementsize;
    elementsize = x;
    return tree;
};

最后,当您创建树时,可以像这样更改elementsize

var tree = d3.layout.tree()
             .size(null)
             .elementsize(50, 240);

2
这里是有关更多信息的Google Groups链接:https://groups.google.com/forum/?fromgroups#!topic/d3-js/7Js0dGrnyek - Biovisualize
1
在d3版本3中,现在有一个nodeSize属性,它将执行与上述修改相同的操作。参考:https://github.com/mbostock/d3/wiki/Tree-Layout#nodeSize - patorjk

3

我知道我不应该回复其他答案,但是我没有足够的声望添加评论。

无论如何,我只是想更新此信息,以供使用最新的d3.v3.js文件的人们参考。(我认为这是因为新版本的原因,因为对我来说,已接受答案中的行引用是错误的。)

您正在编辑的d3.layout.tree函数位于6236到6345行之间。d3_layout_treeVisitAfter从6318行开始。层次结构变量在6237行声明。关于tree.elementsize的部分仍然有效 - 我将其放在6343行。

最后(我认为这是一个错误):当您创建树时,请将维度放在方括号内,就像通常使用“大小”一样。所以:

var tree = d3.layout.tree()
         .size(null)
         .elementsize([50, 240]);

如果您正在使用版本3,则不需要进行修改。已经有一个nodeSize属性可以代替elementsize。 - patorjk

1
您提出的修复方案是可行的,只需要确保在将所有内容添加到画布后再进行操作。d3会在每次进入、退出、附加等操作时重新计算布局。完成所有这些操作后,您可以调整d.y来修复深度问题。
nodes.forEach(function(d) { d.y = d.depth * fixdepth});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接