Есть ли способ гарантировать иерархический вывод из NetworkX?

86

Я пытаюсь создать блок-схему древовидной структуры. Я смог создать репрезентативные графики с помощью networkx, но мне нужен способ показать древовидную структуру при выводе графика. Я использую matplotlib.pylab для построения графика.

Мне нужно показать данные в структуре, подобной показанной здесь . Хотя у меня нет подграфов.

Как я могу гарантировать такую ​​структуру?

Примеры для неверующих:

Различные макеты NetworkX

Мне удалось показать графики с помощью 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()
Максимум
источник

Ответы:

118

Если вы используете ориентированный граф, то точечный макет 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')

Вывод Graphviz

Вывод NetworkX / Matplotlib

ОБНОВЛЕНО

Вот версия, обновленная для 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')

введите описание изображения здесь

Арик
источник
1
Ага! Так что все, что мне было нужно, это ориентированный график с «точечным» макетом. Я знал, что это что-то очень маленькое. Большое спасибо, Арик!
max
Есть ли хороший способ пометить узлы по возрастанию? Под этим я подразумеваю, что я создаю граф. g = nx.full_rary_tree(2, 10)Если я распечатаю края, которые я получаю: [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), ... ]но он будет визуализировать их в другом порядке ...
CodeKingPlusPlus
1
PyGrapviz работает с Python 3, и этот код будет работать с Python 3.
Арик,
3
также, если у вас возникнут какие-либо проблемы с установкой pygraphvizобычными способами, попробуйтеpip install --install-option="--include-path=/usr/local/include/" --install-option="--library-path=/usr/local/lib/" pygraphviz
Rotail
2
@Rotail Это сработало для меня после того, как я установил graphviz(в моем случае использовал brew install graphviz).
Шивендра
10

Вы можете использовать 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 -Nwidth=".2" -Nheight=".2" -Nmargin=0 -Gfontsize=8')
>>> A.draw('test.png')

Результат: введите описание изображения здесь

Обратите внимание, что я скопировал параметры graphviz из ссылки, которую вы разместили выше. Я не уверен, почему 4-й ребенок нарисован сверху, а не в строго вертикальном формате. Может быть, кто-то, кто знает больше о параметрах Graphviz, сможет в этом помочь.

терраса
источник
Благодарю. Это было именно то, что я увидел, когда попробовал. Мне кажется несколько странным, почему он произвел нечто подобное.
max
5
Обратите внимание, что в версии 1.11 networkx api изменился. Теперь to_agraphфункция находится в папке nx.nx_agraph.to_agraph.
m00am
1
Есть ли способ сделать так, чтобы ребенок всегда был ниже своих родителей?
Dror
0

Вы можете использовать grandalf для решения только для Python, если не хотите устанавливать graphviz.

Кроме того, этот тип визуализации называется рисованием многоуровневого графа или рисованием графа в стиле Сугияма , который может отображать многие виды графиков, в том числе не деревья.

См. Мой ответ на другой вопрос для получения подробной информации и реализации.

флаксер
источник