有没有办法保证 NetworkX 的分层输出?
Posted
技术标签:
【中文标题】有没有办法保证 NetworkX 的分层输出?【英文标题】:Is there a way to guarantee hierarchical output from NetworkX? 【发布时间】:2012-07-13 20:14:50 【问题描述】:我正在尝试制作树结构的流程图。我已经能够使用 networkx 创建具有代表性的图表,但是我需要一种方法来在输出绘图时显示 tree 结构。我正在使用 matplotlib.pylab 来绘制图表。
我需要以类似于here 的结构显示数据。虽然我没有子图。
我怎样才能保证这样的结构?
不信者的例子:
我已经能够使用 pylab 和 graphviz 显示图表,但它们都没有提供我正在寻找的树结构。我已经尝试了 networkx 提供的所有布局,但没有一个显示出层次结构。我只是不确定如果我需要使用权重,应该给它或什么选项/模式。任何建议都会有所帮助。
@jterrace:
这是我用来制作上述图的粗略轮廓。我添加了一些标签,但除此之外都是一样的。
import networkx as nx
import matplotlib.pyplot as plt
G = nx.Graph()
G.add_node("ROOT")
for i in xrange(5):
G.add_node("Child_%i" % i)
G.add_node("Grandchild_%i" % i)
G.add_node("Greatgrandchild_%i" % i)
G.add_edge("ROOT", "Child_%i" % i)
G.add_edge("Child_%i" % i, "Grandchild_%i" % i)
G.add_edge("Grandchild_%i" % i, "Greatgrandchild_%i" % i)
plt.title("draw_networkx")
nx.draw_networkx(G)
plt.show()
【问题讨论】:
【参考方案1】:如果您使用有向图,那么 Graphviz 点布局将对树执行您想要的操作。这是一些类似于上述解决方案的代码,显示了如何做到这一点
import networkx as nx
from networkx.drawing.nx_agraph import graphviz_layout
import matplotlib.pyplot as plt
G = nx.DiGraph()
G.add_node("ROOT")
for i in range(5):
G.add_node("Child_%i" % i)
G.add_node("Grandchild_%i" % i)
G.add_node("Greatgrandchild_%i" % i)
G.add_edge("ROOT", "Child_%i" % i)
G.add_edge("Child_%i" % i, "Grandchild_%i" % i)
G.add_edge("Grandchild_%i" % i, "Greatgrandchild_%i" % i)
# write dot file to use with graphviz
# run "dot -Tpng test.dot >test.png"
nx.nx_agraph.write_dot(G,'test.dot')
# same layout using matplotlib with no labels
plt.title('draw_networkx')
pos=graphviz_layout(G, prog='dot')
nx.draw(G, pos, with_labels=False, arrows=False)
plt.savefig('nx_test.png')
更新
这是为 networkx-2.0 更新的版本(以及即将推出的 networkx-2.1 也会绘制箭头)。
import networkx as nx
from networkx.drawing.nx_agraph import write_dot, graphviz_layout
import matplotlib.pyplot as plt
G = nx.DiGraph()
G.add_node("ROOT")
for i in range(5):
G.add_node("Child_%i" % i)
G.add_node("Grandchild_%i" % i)
G.add_node("Greatgrandchild_%i" % i)
G.add_edge("ROOT", "Child_%i" % i)
G.add_edge("Child_%i" % i, "Grandchild_%i" % i)
G.add_edge("Grandchild_%i" % i, "Greatgrandchild_%i" % i)
# write dot file to use with graphviz
# run "dot -Tpng test.dot >test.png"
write_dot(G,'test.dot')
# same layout using matplotlib with no labels
plt.title('draw_networkx')
pos =graphviz_layout(G, prog='dot')
nx.draw(G, pos, with_labels=False, arrows=True)
plt.savefig('nx_test.png')
【讨论】:
啊哈!所以我需要的只是一个带有“点”布局的有向图。我知道这是非常小的东西。非常感谢阿里克! 有什么好的方法可以升序标记节点吗?我的意思是,我创建一个图形g = nx.full_rary_tree(2, 10)
如果我打印我得到的边:[(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), ... ]
但它会以不同的顺序将它们可视化......
PyGrapviz 适用于 Python 3,此代码适用于 Python 3。
另外,如果您在常规方式安装pygraphviz
时遇到任何问题,请尝试pip install --install-option="--include-path=/usr/local/include/" --install-option="--library-path=/usr/local/lib/" pygraphviz
@Rotail 在我安装了graphviz
(在我的情况下使用brew install graphviz
)之后,这对我有用。【参考方案2】:
你可以使用pygraphviz来接近:
>>> import pygraphviz
>>> import networkx
>>> import networkx as nx
>>> G = nx.Graph()
>>> G.add_node("ROOT")
>>> for i in xrange(5):
... G.add_node("Child_%i" % i)
... G.add_node("Grandchild_%i" % i)
... G.add_node("Greatgrandchild_%i" % i)
... G.add_edge("ROOT", "Child_%i" % i)
... G.add_edge("Child_%i" % i, "Grandchild_%i" % i)
... G.add_edge("Grandchild_%i" % i, "Greatgrandchild_%i" % i)
>>> A = nx.to_agraph(G)
>>> A.layout('dot', args='-Nfontsize=10 -N -N -Nmargin=0 -Gfontsize=8')
>>> A.draw('test.png')
结果:
请注意,我从您在上面发布的链接中复制了 graphviz 选项。我不确定为什么第四个孩子被画在顶部而不是严格的垂直格式。也许对 Graphviz 选项有更多了解的人可以提供帮助。
【讨论】:
谢谢。这正是我尝试时所看到的。我觉得它为什么会产生这样的东西有点奇怪。 请注意,在 networkx 的 1.11 版本中,api 发生了变化。to_agraph
函数现在位于 nx.nx_agraph.to_agraph
。
有没有办法确保孩子总是低于父母?【参考方案3】:
如果您不想安装 graphviz,您可以使用 grandalf 仅用于 python 的解决方案。
此外,这种可视化类型称为layered graph drawing 或Sugiyama-style graph drawing,可以显示多种图形,包括非树。
有关详细信息和实施,请参阅my answer to a different question。
【讨论】:
【参考方案4】:另请参阅@Abdallah Sobehy 创建的层次结构,无需使用任何额外的模块/库(如“pygraphviz”),位于 preserving the left and right child while printing python graphs using networkx
也许这个图表没有上面的那么好,但它完成了所要求的工作!
【讨论】:
以上是关于有没有办法保证 NetworkX 的分层输出?的主要内容,如果未能解决你的问题,请参考以下文章