NetworkX 主要用于图形分析,PyGraphviz 主要用于绘图,它们被设计为协同工作。然而,至少在一个方面,NetworkX 的图形绘制(通过 MatPlotLib)优于 PyGraphviz 的图形绘制(通过 Graphviz),即 NetworkX 具有 spring 布局算法(可通过spring_layout
函数)专门用于有向图,而 PyGraphviz 有几种弹簧布局算法(可通过neato
程序和其他)将有向图布置得就像无向图一样。唯一真正处理图形方向的 Graphviz / PyGraphviz 布局程序是dot
, but dot
创建分层布局,而不是强制导向布局。
下面的示例显示了 NetworkX 和 PyGraphviz 在有向图的弹簧布局方面的差异:
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 http://farm9.staticflickr.com/8516/8521343506_0c5d62e013.jpg)
2_networkx_undirected.png:(http://farm9.staticflickr.com/8246/8521343490_06ba1ec8e7.jpg http://farm9.staticflickr.com/8246/8521343490_06ba1ec8e7.jpg)
3_pygraphviz_directed.png:(http://farm9.staticflickr.com/8365/8520231171_ef7784d983.jpg http://farm9.staticflickr.com/8365/8520231171_ef7784d983.jpg)
4_pygraphviz_undirected.png:(http://farm9.staticflickr.com/8093/8520231231_80c7eab443.jpg http://farm9.staticflickr.com/8093/8520231231_80c7eab443.jpg)
绘制的第三个和第四个图形基本相同,但箭头不同(整个图形已旋转,但除此之外没有任何区别)。然而,第一张图和第二张图的布局不同 - 这不仅仅是因为 NetworkX 的布局算法引入了随机性元素。
反复运行上面的代码表明这不是偶然发生的。网络X的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 复制吗?
不幸的是文档 http://networkx.github.com/documentation/latest/reference/generated/networkx.drawing.layout.spring_layout.html和评论的源代码 http://networkx.github.com/documentation/latest/_modules/networkx/drawing/layout.html对于 NetworkX 来说spring_layout
(实际上fruchterman_reingold_layout
) 函数没有提供任何线索来解释为什么 NetworkX 会产生这样的结果。
这是使用PyGraphviz使用NetworkX绘制网络的结果spring_layout
函数(请参阅下面我自己对此问题的回答)。
5_pygraphviz_plus_networkx.png:
(http://farm9.staticflickr.com/8378/8520231183_e7dfe21ab4.jpg http://farm9.staticflickr.com/8378/8520231183_e7dfe21ab4.jpg)