根据节点数量,通过电荷/重力属性优化d3力定向布局

时间:2013-09-06 15:20:30

标签: javascript graph d3.js force-layout

我一直在使用内置于D3的强制定向算法进行网络拓扑可视化。一切都运行良好,但有一个重要细节的麻烦......我似乎无法使图形以理想的方式布局,以用于具有不同数量节点的图形。理想情况下,我的意思是节点与每个节点(没有重叠)和节点集群很好地隔开,只要它有意义。我一直试图通过调整力布局的“充电”和“重力”属性来做到这一点,但无论我尝试什么,它似乎总是适用于一种情况(即大量节点),但不是对于另一种情况(即,少量节点)。例如,如果我的布局适用于大型图形,那么当我使用相同的电荷/重力公式查看小图时,生病有一些节点远离其他节点的站点。以下是我根据另一个SO问题post使用的公式示例:

var k = Math.sqrt(json.nodes.length / (dim.w * dim.h));
var charge = -10 / k;
var gravity = 100 * k;

这适用于具有14个节点的图形,但如果我尝试使用5个节点的图形,则其中一些节点完全不在屏幕上。请注意,计算“k”时使用的宽度/高度在这两种情况之间不会发生变化。现在也许我不应该根据图的可见区域的宽度/高度来获得这些属性。说实话,这不是一个要求。我不需要图形来渲染并适合图形的视口。我只需要图表就可以合理地展示自己,所以如果其中一些可能在可见区域之外,特别是在大图中,则可以。我已经尝试了以下方面取得了一些成功,但我仍然发现节点与小图的其余部分相距太远:

var charge = -1 * Math.pow(json.nodes.length, 3);
var gravity = 1 / json.nodes.length;

有人可以帮我解决这个问题吗?非常感谢,因为我觉得有点困在这个大气压。

2 个答案:

答案 0 :(得分:2)

在这个基于力的算法案例中,我会说几乎不可能设置所有案例拟合设置。这种布局几乎不依赖于图形密度和内部图形语义 可能的节点数范围是多少?密度怎么样?它是随机生成的图形,具有预定义的密度系数,或者它背后有一些语义,并且有可能基于这种语义看起来很好 你说节点之间的距离很远。什么更高的重力给你? 关于linkDistance的建议也可能对您有所帮助。例如。我也在使用d3.forceLayout来绘制网络图(但它们大多是节点<50的小手工图)。我刚从Mike Bostock的力布局示例中复制了统计数据。他们在这里:

// graph force layout defaults
var linkDistance = 50,
    charge = -200;
// chart properties
var height = 720,
    width = 720;
    radius = 10;

我不认为它会对你有所帮助,但也许它会刺激其他人讨论。

UPD。我只能建议你做实验。选择一小组测试图并找到每个测试图的最佳初始化设置,然后插入给定的数字。此外,如果你处理非常大的图形(非常大的“好”可视化我的意思)也许你会发现分组(colapsing)它的一些部分是有帮助的 - 它减少了节点的数量(可能还有图形的复杂性)。 /> 另外请记住,您不需要设置恒定力布局设置(电荷,重力,linkDistance等都是维护功能)。并且您可以将节点半径设置为略大于可见半径,这样它们就不会相互重叠。或者设置非常数的充电功能,例如smth like this。或者使用Mike Bostock建议手动在每个刻度上传播节点。

答案 1 :(得分:2)

我实际上是在自己想出来的......

所以我用于充电/重力/等的值并不是问题所在。问题与调用tick函数调整图表的次数有关。对于我的大图,节点总是布局得相当好。我遇到的主要问题是图表较小。我发现,当图形中只有大约5-10个节点时,节点经常被放置在视口之外。

在我的代码中,我手动调用tick函数,如下所示:

force.start();

for (var i = tickLimit; i > 0; --i)
    force.tick();

force.stop();

以前,tickLimit设置如下:

var tickLimit = Math.pow(json.nodes.length, 2);

在弄乱了电荷/重力值之后,我终于意识到这对于小图来说还不够。如果我有一个包含4个节点的图形,那么这意味着只会进行16次tick()调用。这对于图形完全自我调整(即稳定)是不够的。因此,我只需要添加一个检查以确保图表记录最小次数(例如至少300)和最大值(例如不超过10000)。

这可能对每个人都不起作用,但它解决了我的问题。