【问题标题】:Optimize d3 force directed layout, via charge/gravity properties, based on number of nodes根据节点数量通过电荷/重力属性优化 d3 力导向布局
【发布时间】:2013-09-10 18:05:39
【问题描述】:

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

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

【问题讨论】:

  • 有人吗?请帮忙。 :)
  • 强制布局对于这项任务来说并不是很理想。除了电荷/重力属性之外,您还可以尝试linkDistance,甚至可以添加“幻像”链接,即那些未绘制但会影响节点定位方式的链接。
  • 我已经在使用链接距离了,尽管我发现它对图表的布局没有太大的影响。为此目的,电荷/重力似乎更重要。为什么说力布局不适合网络拓扑?老实说,我认为它比任何其他图算法更适合网络。还有其他建议吗?
  • 它不是特别适合,因为只要满足力约束,它就不会努力使布局“漂亮”。我对 Javascript 没有任何其他建议。

标签: javascript graph d3.js force-layout


【解决方案1】:

在这种基于力的算法案例中,我会说几乎不可能设置所有案例适合的设置。这种布局几乎不依赖于图形密度和内部图形语义。
可能的节点数范围是多少?密度呢?是随机生成的具有预定义密度系数的图,还是它背后有一些语义,并且有可能基于这个语义看起来不错。
你说节点彼此远离。什么更高的重力给你?
此外,关于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 like this。或者使用 Mike Bostock 的建议手动在每个报价上分布节点。

【讨论】:

  • 没有最大节点数。此网络拓扑已内置到产品中,因此它取决于客户图中将有多少节点。我们的一些客户拥有庞大的网络,可能会产生 > 5000 个节点的图形。我正在寻找的只是生成一个节点不重叠并且很好分布的图形。我不希望所有节点都被挤压在一起......而且我不希望它们相距太远。我曾希望力布局算法能够自己完成这项工作,或者让我更简单地对其进行调整……但似乎并不是那么明确。 :(
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-23
    • 2015-08-12
    相关资源
    最近更新 更多