基于节点数量,通过电荷/重力属性优化d3力导向布局

3
我一直在使用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;

有没有人能够帮我解决这个问题?非常感激,因为我目前感到有些困惑。


有人吗?请帮忙。 :) - DaViS
力导向布局并不是这项任务的理想选择。除了电荷/重力属性外,您可以尝试使用linkDistance属性,甚至添加“幻影”链接,即那些不被绘制但会影响节点位置的链接。 - Lars Kotthoff
我已经在使用链接距离算法,尽管我发现它对图形的布局影响不是很大。电荷/重力似乎对此更有意义。你为什么说力导向布局不适合网络拓扑?老实说,我认为这比任何其他图形算法都更适合网络。还有其他建议吗? - DaViS
它并不特别适合,因为只要满足强制约束条件,它就不会花费任何努力使布局“好看”。我对JavaScript没有其他建议。 - Lars Kotthoff
2个回答

3

我实际上是自己解决了这个问题...

所以,我使用的电荷/重力等值并不是问题的关键。问题与调整图形的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);

在尝试一番调整充电/重力等数值之后,我终于意识到这对于小图形不够足够。如果我有一个只有四个节点的图形,那么只会进行16次tick()调用。这对于图形完全自我调整(即稳定)来说是不够的。因此,我只需要添加一个检查以确保图形最少触发一定数量的tick()(例如至少300次),并且设置一个最大值(例如不超过10000次)。
这种方法不一定适用于所有人,但它解决了我的问题。

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;

我不指望这会对你有所帮助,但或许可以刺激其他人进行讨论。
更新:我能建议你尝试实验。选择一小组测试图形,并为每个图形找到最佳的初始设置,然后插值给定的数字。另外,如果你处理非常大的图形(对于“好”的可视化来说非常大),也许将其某些部分分组(折叠)会有所帮助 - 它减少了节点数(也许减少了图形的复杂性)。此外,请记住,你不需要设置恒定的力布局设置(电荷、重力、链接距离等都是维护函数)。你还可以将节点半径设置得比可见半径稍大一点,这样它们就不会相互重叠。或者设置非常量电荷函数,例如像这样的 函数。或者使用 Mike Bostock 的建议,在每次 tick 上手动展开节点。

1
节点数量没有上限。这种网络拓扑结构已经集成到产品中,因此图形中有多少个节点取决于客户。我们的一些客户拥有庞大的网络,可能会产生超过5000个节点的图形。我只是想生成一个节点不重叠且分布均匀的图形。我不希望所有节点挤在一起...也不希望它们相距太远。我原本希望力导向算法可以自动完成或者让我更简单地调整它...但似乎并不是那么简单。 :( - DaViS

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