有没有办法保证 NetworkX 的分层输出?

我正在尝试制作一个 结构的流程图。我已经能够用 networkx 创建具有代表性的图形,但是我需要一种在输出绘图时显示 结构的方法。我正在使用 matplotlib.pylab 绘制图表。

我需要以类似于 给你的结构来显示数据,尽管我没有子图。

我怎么能保证这样的结构呢?

非信徒的例子:

Various NetworkX layouts

我已经能够显示与 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()
63016 次浏览

You can use pygraphviz to get close:

>>> 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 -Nwidth=".2" -Nheight=".2" -Nmargin=0 -Gfontsize=8')
>>> A.draw('test.png')

Result: enter image description here

Note I copied the graphviz options from the link you posted above. I'm not sure why the 4th child is drawn on top instead of in strictly vertical format. Maybe someone who knows more about the Graphviz options can help with that.

If you use a directed graph then the Graphviz dot layout will do something like you want with the tree. Here is some code similar to the above solutions that shows how to do that

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')

Graphviz output

NetworkX/Matplotlib output

UPDATED

Here is a version updated for networkx-2.0 (and with upcoming networkx-2.1 draws arrows too).

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')

enter image description here

You can use grandalf for a python-only solution, if you don't want to install graphviz.

Also, this type of visualization is called a layered graph drawing or Sugiyama-style graph drawing, which can display many kinds of graphs, including non-trees.

See my answer to a different question for details and implementation.

See also the hierarchical structures created by @Abdallah Sobehy, w/o the need to use any extra module/library (like 'pygraphviz'), at preserving the left and right child while printing python graphs using networkx

Maybe the graph is not so nice as the above, but it does the requested job!

You could do it manually just with only networkx. Traverse tree and for each children coordinate x change as if right parent.x+1/np.log(y_coord + 1) if left parent.x-1... and y = parent.y - 1 Or any other algorithm to get coord and eg. See image here.

import networkx as nx
import matplotlib.pyplot as plt
coord = {0: [8, 0], 2: [9, -1], 1: [8, -2], 4: [10, -2], 3: [9, -3], 5: [11, -3]}
eg = [[0, 2], [2, 1], [2, 4], [4, 3], [4, 5]]
G=nx.Graph()
G.add_edges_from(eg)
nx.draw(G, with_labels=True, node_size=1500, node_color="skyblue", pos=coord)
plt.show()