【问题标题】:NetworkX-style spring model layout for directed graphs in Graphviz / PyGraphvizGraphviz / PyGraphviz 中的有向图的 NetworkX 样式弹簧模型布局
【发布时间】:2013-05-13 19:42:57
【问题描述】:

NetworkX 主要用于图形分析,PyGraphviz 主要用于绘图,它们旨在协同工作。然而,至少在一个方面,NetworkX 的图形绘制(通过 MatPlotLib)优于 PyGraphviz 的图形绘制(通过 Graphviz),即 NetworkX 具有专门针对有向图的弹簧布局算法(可通过 spring_layout 函数访问),而 PyGraphviz有几种弹簧布局算法(可通过neato 程序和其他程序访问),它们将有向图布局为无向图。唯一真正处理图形方向的 Graphviz / PyGraphviz 布局程序是 dot,但 dot 创建分层布局,而不是强制导向布局。

下面是一个例子,展示了 NetworkX 和 PyGraphviz 在有向图的 spring 布局方面的区别:

import networkx as nx
import pygraphviz as pgv
import matplotlib.pyplot as ppt

edgelist = [(1,2),(1,9),(3,2),(3,9),(4,5),(4,6),(4,9),(5,9),(7,8),(7,9)]

nxd = nx.DiGraph()
nxu = nx.Graph()
gvd = pgv.AGraph(directed=True)
gvu = pgv.AGraph()

nxd.add_edges_from(edgelist)
nxu.add_edges_from(edgelist)
gvd.add_edges_from(edgelist)
gvu.add_edges_from(edgelist)

pos1 = nx.spring_layout(nxd)
nx.draw_networkx(nxd,pos1)
ppt.savefig('1_networkx_directed.png')
ppt.clf()

pos2 = nx.spring_layout(nxu)
nx.draw_networkx(nxu,pos2)
ppt.savefig('2_networkx_undirected.png')
ppt.clf()

gvd.layout(prog='neato')
gvd.draw('3_pygraphviz_directed.png')

gvu.layout(prog='neato')
gvu.draw('4_pygraphviz_undirected.png')

1_networkx_directed.png:(http://farm9.staticflickr.com/8516/8521343506_0c5d62e013.jpg)

2_networkx_undirected.png:(http://farm9.staticflickr.com/8246/8521343490_06ba1ec8e7.jpg)

3_pygraphviz_directed.png:(http://farm9.staticflickr.com/8365/8520231171_ef7784d983.jpg)

4_pygraphviz_undirected.png:(http://farm9.staticflickr.com/8093/8520231231_80c7eab443.jpg)

画出来的第三个和第四个图形基本相同,只是箭头部分(整个图形被旋转了,但除此之外没有区别)。然而,第一个和第二个图形的布局不同——不仅仅是因为 NetworkX 的布局算法引入了随机性元素。

重复运行上面的代码表明这不是偶然发生的。 NetworkX 的 spring_layout 函数显然是基于这样的假设编写的:如果从一个节点到另一个节点有弧线,则第二个节点应该比第一个节点更靠近图的中心(即,如果 edgelist 中描述的图是定向,节点 2 应该比节点 1 和 3 更接近节点 9,节点 6 应该比节点 4 更接近节点 9,节点 8 应该比节点 7 更接近节点 9;这并不总是有效正如我们从上图第一个图中的节点 4 和 5 中看到的那样完美,但与将 2 和 9 放在中心附近相比,这是一个小问题,而且从我的角度来看,“错误”非常轻微)。换句话说,NetworkX 的spring_layout 既是分层的又是强制导向的。

这是一个不错的功能,因为它使核心/外围结构在有向图中更加明显(根据您正在使用的假设,没有传入弧的节点可以被视为外围的一部分,即使它们有大量的输出弧)。 @skyebend 在下面解释了为什么大多数布局算法将有向图视为无向图,但上图显示 (a) NetworkX 以不同的方式处理它们,以及 (b) 它以有助于分析的原则方式这样做。

这可以使用 PyGraphviz / Graphviz 复制吗?

不幸的是,documentation 和 NetworkX 的 spring_layout(实际上是 fruchterman_reingold_layout)函数的注释 source code 没有提供任何关于 NetworkX 产生结果的线索。

这是使用 PyGraphviz 使用 NetworkX spring_layout 函数绘制网络的结果(请参阅下面我自己对这个问题的回答)。 5_pygraphviz_plus_networkx.png: (http://farm9.staticflickr.com/8378/8520231183_e7dfe21ab4.jpg)

【问题讨论】:

    标签: graph visualization graphviz networkx pygraphviz


    【解决方案1】:

    好的,我想我想通了,所以我要回答我自己的问题。我不认为它可以在 PyGraphviz 本身中完成。但是,可以指示 PyGraphviz 从 NetworkX 获取节点位置,但将它们固定(使用!),以便防止neato 程序实际上做任何事情,除了橡皮戳spring_layout 计算的节点位置。在上面添加以下代码行:

    for k,v in pos1.iteritems():
        gvd.get_node(k).attr['pos']='{},{}!'.format(v[0]*10,v[1]*10)
    
    gvd.layout(prog='neato')
    gvd.draw('5_pygraphviz_plus_networkx.png')
    

    结果并不完美——我必须将坐标乘以 10 以阻止节点被绘制在彼此之上,这(显然)是一个杂乱无章——但这是一种改进,即度数为 0 的节点在外侧(使用 NetworkX 布局的好处),并且有适当的箭头不会被节点本身吞噬(使用 PyGraphviz 绘图的好处)。

    我知道这并不是我严格要求的(即使用 PyGraphviz / Graphviz 本身的解决方案)。

    如果有人能提供更好的解决方案,我会很高兴!

    编辑:没有人为上述问题提供更好的解决方案,因此我将接受我自己的答案以表明它确实有效。但是,我也对 skyebend 的答案投了赞成票,因为 - 尽管它不能解决问题 - 它对理解潜在问题非常有用。

    【讨论】:

      【解决方案2】:

      Graphviz 还具有 fdpsfdp 布局模式,用于强制定向放置节点,类似于弹簧布局。我不熟悉 NetworkX,但似乎 gvu.layout(prog='fdp') 可能有用吗?如果 NetworkX 允许向 Graphviz 传递额外的参数,那么您可以调整许多可配置的布局参数,这些参数可能会让您的布局更接近您想要的。请参阅 Graphviz 文档:http://www.graphviz.org/content/attrs

      但是,fdp 布局将网络视为无向图。我知道的大多数“弹簧”布局也将网络视为无向的,因为它们必须将它们转换为距离对称的欧几里得空间(屏幕)。一个例外是“磁性”弹簧布局,它也试图对齐弧线,因此它们指向相似的方向以传达层次结构,作为一种整洁/点混合。

      算法实现在如何将有向网络中的网络距离转换为无向权重/距离以通过布局进行优化方面也可能有所不同。如果您想更好地控制有向弧的解释方式,您可能需要自己明确地执行此步骤。

      【讨论】:

      • 感谢您解释为什么大多数 Spring 布局将网络视为无向,但您提供的解决方案(即使用 fdpsfdp 而不是 neato)并不能解决我的问题(正如您所承认的那样当您写“fdp 布局将网络视为无向图”时),并且似乎没有 Graphviz 布局参数会产生我想要的效果。我将在上面包含屏幕截图,以便您了解我的意思。 (如果 NetworkX 文档解释了发生的事情,那肯定会有所帮助!)
      • 我很想知道 NetworkX spring_layout 是否类似于那些“'磁性'弹簧布局,它们也试图对齐弧线,因此它们指向相似的方向以传达层次结构” -根据我上面链接到的图像的证据,它似乎在做的不是试图使弧指向同一方向,而是试图使它们指向图形的中心。
      • 我想我不清楚你想要达到什么形象。我不知道 Python,但是从查看您链接到的 FR 布局代码来看,它似乎没有明确处理图表中的不对称性,并且试图仅在“输出”关系上进行优化,这似乎可能是给出奇怪的结果。例如,在您链接到的图像中,为什么节点 7 和 8 应该比 7 和 9 更接近?您链接的 pygraphviz 布局在我看来更加一致和清晰。
      • 这两种方法中哪一种更“清晰”取决于您想要澄清的内容。在社交网络分析中,关键概念之一是核心与外围,NetworkX 布局清楚地显示了哪些节点属于哪个节点,而各种 Graphviz 布局完全模糊了核心-外围结构。从这个角度来看,7 和 8 比 7 和 9 更接近并不是一个“奇怪的结果”,而是使 NetworkX 布局对现实世界数据如此有价值的一个例子(与我的玩具数据相反) m 在这里使用):7 和 8 在图的外围,而 9 在核心。
      • 我投票赞成你的答案,因为即使它不能解决我的具体问题,它也是一个非常有用的贡献。 (很抱歉没有早点这样做 - 我希望有人会发布一个实际的解决方案,但是 - 除非你算上我在自己对问题的回答中提供的 kludge - 没有人有。)
      猜你喜欢
      • 2022-10-18
      • 1970-01-01
      • 2018-04-26
      • 2011-07-29
      • 2017-12-23
      • 2021-05-18
      • 2023-03-20
      • 1970-01-01
      • 2013-06-25
      相关资源
      最近更新 更多