D3.js 强制有向图,通过使边缘相互排斥来减少边缘交叉

Posted

技术标签:

【中文标题】D3.js 强制有向图,通过使边缘相互排斥来减少边缘交叉【英文标题】:D3.js force directed graph, reduce edge crossings by making edges repel each other 【发布时间】:2012-08-13 23:33:47 【问题描述】:

所以我已经有一个页面绘制了一个力导向图,就像here 显示的那样。

而且效果很好。我正在使用来自here 的 JS,并进行了一些调整以更好地分散节点。

这些或多或少是唯一的区别:

d3.json("force.json", function(json) 
  var force = d3.layout.force()
      .gravity(0.1)
      .charge(-2000)
      .linkDistance(1)
      .linkStrength(0.1)
      .nodes(json.nodes)
      .links(json.links)
      .size([w, h])
      .start();

降低链接强度似乎会使链接更像弹簧,因此它类似于经常使用的Fruchterman & Reingold 技术。这工作得相当好,但仅适用于相当小的图形。对于较大的图表,交叉点的数量只会增加 - 正如人们所期望的那样,但它所采用的解决方案通常远非最佳。我不是在寻找获得最佳解决方案的方法,我知道这非常困难。我只是希望它有一些粗略的添加,试图将线条和节点分开。

有没有办法在链接之间以及节点之间添加斥力?我不熟悉 D3 力的工作方式,我似乎找不到任何东西说这是可能的......

【问题讨论】:

你有想过这个吗? 很遗憾没有。不过我没有深入研究 js,因为我不熟悉该语言。我确实尝试过使用实际的 Fruchterman & Reingold 技术,但结果仍然不如我手动移动节点那么好。 @pocketfullofcheese - 我实际上在使用 networkX(一个 python 模块)和 matplotlib,但是他们的网站上有一个 D3.js 示例,看起来相当不错,这就是我尝试它的原因。 可视化大图困难...我知道这不能解决问题,但也许你会发现我的 networkX 端口有帮助:felix-kling.de/JSNetworkX。它也使用 d3,让您可以轻松放大和缩小图表的某些部分,从而更容易检查。 @FelixKling 除了放大和缩小之外,这是否会为两者添加任何功能?并不是说我的图表是,更多的是它们之间的联系非常紧密——它们大约有 40 个节点 【参考方案1】:

很遗憾,您的问题的答案不存在。

D3 中没有内置机制可以排斥边缘或最大限度地减少边缘交叉。您可能会认为在边缘实施收费并不难,但我们来了。

此外,似乎没有任何机制任何地方可以减少一般的边缘交叉。我浏览了几十个可视化库和布局算法,但没有一个能够减少通用无向图上的边交叉。

有许多算法适用于平面图、2 级图或其他简化。 dagre 在理论上适用于 2 级图,尽管完全缺乏文档使其几乎无法使用。

造成这种情况的部分原因是布局图表很难。特别是,最小化边缘交叉是 NP 难的,所以我怀疑大多数布局设计师遇到了这个问题,用头撞了几次键盘,然后放弃了。

如果有人为此想出了一个好的库,请为我们其他人发布它:)

【讨论】:

这是我得出的结论。经理们不喜欢“你能让这张图看起来更大吗?”这样的回答。 “不。这确实是一个 hard 问题。”。你有一个软件可以模拟复杂机器内部的物理,但你不能以任何令人愉快的方式绘制输出。耻辱。 另外,graphviz 现在可以在epl 许可下使用。【参考方案2】:

比试图强行排斥边缘更容易的方法是摆动节点,直到系统中的交叉线数量减少。

http://en.wikipedia.org/wiki/Simulated_annealing

从连接数量最少的节点开始,然后向下摆动。

如果您尝试将边用作节点,我怀疑您只会遇到相同的空间锁定问题。解决方案是找出边缘交叉点的位置以及是否可以解决它们。您可能会发现解决许多边缘交叉是不可能的

一种更横向的可视化方法是对其进行动画处理,使其一次仅显示节点和连接的子集。或者使边缘透明,直到用户将鼠标焦点放在节点上,这点关联的边缘变得更加明显。

【讨论】:

【参考方案3】:

我按照 Force Editor 示例进行操作,发现设置 chargelinkDistance 值可以解决问题。

  ...
  .charge(-200)
  .linkDistance(50)
  ...

截图:

【讨论】:

所有改变carge所做的就是改变点相互排斥的力。 linkDistance jsut 改变了点的理想长度。这在您给出的示例中可以正常工作,但是当您像我一样有一个高度连接的图表时,它就不起作用了。我将在星期一用一些真实的示例数据来更新这个问题来说明这个问题。这是一个化学和反应数据集,因此所有点都通过特殊的反应点与其他几个点相关联。 @将在您更新问题后通知我。也许我可以帮忙。我在应用程序中使用这个库。 是的,我看了一下使用它,但发现它基本上不是适合这项工作的工具,我想要表示的图表太连接了。【参考方案4】:

我已经“解决”了这个问题:

nodes[0].x = width / 2;
nodes[0].y = 100;
nodes[0].fixed = true;
force.on("tick", function(e) 

    var kx = .4 * e.alpha, ky = 1.4 * e.alpha;
    links.forEach(function(d, i) 
      d.target.x += (d.source.x - d.target.x) * kx;
      d.target.y += (d.source.y + 80 - d.target.y) * ky;
    );
    [...]
 

http://mbostock.github.io/d3/talk/20110921/parent-foci.html

这不是我们想要的,但比以前更好。 重要的是,您定义一个“根”节点并修复它。

nodes[0].fixed = true;

它看起来更像一棵树,但更清晰。

【讨论】:

这并不能解决我的问题。对于您的问题,它可能会起作用,但我不确定它是否适用于我的问题,因为我的 grapgh 高度连接,而您的则是一棵树。 您的答案的问题是您的图表实际上可以在没有任何交叉边缘的情况下进行布局!更糟糕的是,在您的示例中,有几条边相互交叉。

以上是关于D3.js 强制有向图,通过使边缘相互排斥来减少边缘交叉的主要内容,如果未能解决你的问题,请参考以下文章

D3 强制有向图 ajax 更新

R语言可视化散点图(scatter plot)图中的标签和数据点互相堆叠丑死了,ggrepel包来帮忙:文本标签(label)相互排斥,远离数据点,远离绘图区域的边缘。

如何使 D3.js 中的强制布局图响应屏幕/浏览器大小

swift:如何单选菜单?使它们相互排斥?

使用 d3.js 保存和重新加载强制布局

D3.js中的弹簧力强制定向布局?