¿Hay alguna forma de garantizar la salida jerárquica de NetworkX?

84

Estoy intentando producir un diagrama de flujo de una estructura de árbol . He podido crear gráficos representativos con networkx, pero necesito una forma de mostrar la estructura del árbol cuando genero un gráfico. Estoy usando matplotlib.pylab para trazar el gráfico.

Necesito mostrar los datos en una estructura similar a la que se muestra aquí . Aunque no tengo subgráficos.

¿Cómo puedo garantizar una estructura así?

Ejemplos para los incrédulos:

Varios diseños de NetworkX

He podido mostrar los gráficos con pylab y graphviz, pero ninguno ofrece la estructura de árbol que estoy buscando. He probado todos los diseños que ofrece networkx, pero ninguno muestra una jerarquía . No estoy seguro de qué opciones / modo darle O si necesito usar pesas. Cualquier sugerencia ayudaría mucho.

@jterrace:

Aquí hay un esquema general de lo que usé para producir los gráficos anteriores. Agregué algunas etiquetas, pero aparte de eso, es lo mismo.

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()
max
fuente

Respuestas:

116

Si usa un gráfico dirigido, el diseño de puntos de Graphviz hará algo como usted quiera con el árbol. Aquí hay un código similar a las soluciones anteriores que muestra cómo hacer eso

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

Salida Graphviz

Salida NetworkX / Matplotlib

ACTUALIZADO

Aquí hay una versión actualizada para networkx-2.0 (y con el próximo networkx-2.1 también dibuja flechas).

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

ingrese la descripción de la imagen aquí

Aric
fuente
1
¡Ah, ja! Entonces, todo lo que necesitaba era un gráfico dirigido con el diseño de 'puntos'. Sabía que era algo muy pequeño. ¡Muchas gracias Aric!
máximo
¿Existe alguna buena forma de etiquetar los nodos de forma ascendente? Con eso quiero decir, creo un gráfico g = nx.full_rary_tree(2, 10)Si imprimo los bordes que obtengo: [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), ... ]pero los visualizará en un orden diferente ...
CodeKingPlusPlus
1
PyGrapviz funciona con Python 3 y este código funcionará con Python 3.
Aric
3
Además, si encuentra algún problema al instalar pygraphvizde manera regular, intentepip install --install-option="--include-path=/usr/local/include/" --install-option="--library-path=/usr/local/lib/" pygraphviz
Rotail
2
@Rotail Esto funcionó para mí después de instalar graphviz(en mi caso usar brew install graphviz).
Shivendra
10

Puedes usar pygraphviz para acercarte:

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

Resultado: ingrese la descripción de la imagen aquí

Tenga en cuenta que copié las opciones de graphviz del enlace que publicó arriba. No estoy seguro de por qué el cuarto niño se dibuja en la parte superior en lugar de en formato estrictamente vertical. Quizás alguien que sepa más sobre las opciones de Graphviz pueda ayudar con eso.

terraza
fuente
Gracias. Esto era exactamente lo que estaba viendo cuando lo probé. Me parece algo extraño por qué produjo algo como esto.
máximo
5
Tenga en cuenta que en la versión 1.11 de networkx, la API cambió. La to_agraphfunción ahora se encuentra en nx.nx_agraph.to_agraph.
m00am
1
¿Hay alguna manera de asegurarse de que los niños estén siempre por debajo de sus padres?
Dror