3

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

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;

有人可以帮我解决这个问题吗?将不胜感激,因为我觉得有点卡在这个自动取款机上。

4

2 回答 2

3

这其实是我自己想出来的……

所以我用于电荷/重力/等的值并不是那么大的问题。该问题与调用刻度函数以调整图形的次数有关。对于我较大的图表,节点总是布置得很好。我遇到的主要问题是较小的图表。我发现当图形中只有大约 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 次)。

这可能不适用于所有人,但它为我解决了问题。

于 2013-09-19T18:40:18.963 回答
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。我只能建议你做实验。选择一小组测试图并为每个图找到最佳初始设置,然后插入给定的数字。此外,如果您处理非常大的图表(我的意思是对于“漂亮”的可视化来说非常大),也许您会发现分组(折叠)其中的某些部分很有帮助 - 它减少了节点的数量(并且可能减少了图表的复杂性)。
另外请记住,您不需要设置恒力布局设置(电荷、重力、链接距离等都是保持功能)。您可以将节点的半径设置为比可见半径大一点,这样它们就不会相互重叠。或者设置充电的非常数函数,例如像这样的smth。或者使用 Mike Bostock 的建议在每个分时手动传播节点。

于 2013-09-16T10:23:05.557 回答