¿Cómo dibujar gráficos dirigidos usando networkx en Python?

101

Tengo algunos nodos que provienen de un script que quiero mapear en un gráfico. A continuación, quiero usar la flecha para ir de A a D y probablemente también tener el borde coloreado (rojo o algo así).

Esto es básicamente, como un camino de A a D cuando todos los demás nodos están presentes. puedes imaginar cada nodo como ciudades y viajar de A a D requiere direcciones (con puntas de flecha).

Este código a continuación crea el gráfico

import networkx as nx
import numpy as np
import matplotlib.pyplot as plt

G = nx.Graph()
G.add_edges_from(
    [('A', 'B'), ('A', 'C'), ('D', 'B'), ('E', 'C'), ('E', 'F'),
     ('B', 'H'), ('B', 'G'), ('B', 'F'), ('C', 'G')])

val_map = {'A': 1.0,
           'D': 0.5714285714285714,
           'H': 0.0}

values = [val_map.get(node, 0.25) for node in G.nodes()]

nx.draw(G, cmap = plt.get_cmap('jet'), node_color = values)
plt.show()

pero quiero algo como se muestra en la imagen.ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

Las puntas de flecha de la primera imagen y los bordes en color rojo en la segunda imagen.

tormenta de ideas
fuente

Respuestas:

86

Ejemplo completo con flechas solo para los bordes rojos:

import networkx as nx
import matplotlib.pyplot as plt

G = nx.DiGraph()
G.add_edges_from(
    [('A', 'B'), ('A', 'C'), ('D', 'B'), ('E', 'C'), ('E', 'F'),
     ('B', 'H'), ('B', 'G'), ('B', 'F'), ('C', 'G')])

val_map = {'A': 1.0,
           'D': 0.5714285714285714,
           'H': 0.0}

values = [val_map.get(node, 0.25) for node in G.nodes()]

# Specify the edges you want here
red_edges = [('A', 'C'), ('E', 'C')]
edge_colours = ['black' if not edge in red_edges else 'red'
                for edge in G.edges()]
black_edges = [edge for edge in G.edges() if edge not in red_edges]

# Need to create a layout when doing
# separate calls to draw nodes and edges
pos = nx.spring_layout(G)
nx.draw_networkx_nodes(G, pos, cmap=plt.get_cmap('jet'), 
                       node_color = values, node_size = 500)
nx.draw_networkx_labels(G, pos)
nx.draw_networkx_edges(G, pos, edgelist=red_edges, edge_color='r', arrows=True)
nx.draw_networkx_edges(G, pos, edgelist=black_edges, arrows=False)
plt.show()

Bordes rojos

Marius
fuente
1
es una locura lo diferentes que son nuestras dos imágenes actualizadas. +1 por descubrir los colores de los bordes.
mdml
¿Por qué su borde (C, E) no es rojo, aunque debe ser rojo de acuerdo con su código anterior?
tormenta de
¿No es posible tener estas puntas de flecha solo en los bordes de interés? por ejemplo (A, C) y (C, E)
tormenta de
@ user1988876: Ah, lo siento, (C, E)no es rojo porque elegí los bordes para red_edgescuando todavía estaba trabajando con su gráfico no dirigido, simplemente seleccionando al azar de los bordes devueltos por G.edges(). Debería serlo red_edges = [('A', 'C'), ('E', 'C')].
Marius
@ user1988876: Es posible tener flechas en solo algunos de los bordes con llamadas separadas a draw_networkx_edges(). Limpié el código y solucioné los problemas de DiGraph.
Marius
47

Solo pongo esto para completar. He aprendido mucho de marius y mdml. Aquí están los pesos de los bordes. Perdón por las flechas. Parece que no soy el único que dice que no se puede evitar. No pude renderizar esto con el cuaderno ipython.Tuve que ir directamente desde Python, que era el problema para obtener mis pesos de borde antes.

import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
import pylab

G = nx.DiGraph()

G.add_edges_from([('A', 'B'),('C','D'),('G','D')], weight=1)
G.add_edges_from([('D','A'),('D','E'),('B','D'),('D','E')], weight=2)
G.add_edges_from([('B','C'),('E','F')], weight=3)
G.add_edges_from([('C','F')], weight=4)


val_map = {'A': 1.0,
                   'D': 0.5714285714285714,
                              'H': 0.0}

values = [val_map.get(node, 0.45) for node in G.nodes()]
edge_labels=dict([((u,v,),d['weight'])
                 for u,v,d in G.edges(data=True)])
red_edges = [('C','D'),('D','A')]
edge_colors = ['black' if not edge in red_edges else 'red' for edge in G.edges()]

pos=nx.spring_layout(G)
nx.draw_networkx_edge_labels(G,pos,edge_labels=edge_labels)
nx.draw(G,pos, node_color = values, node_size=1500,edge_color=edge_colors,edge_cmap=plt.cm.Reds)
pylab.show()

ingrese la descripción de la imagen aquí

Back2Basics
fuente
9
Ejecuté esto y no obtuve las etiquetas de nodo. Es necesario añadir los siguientes: node_labels = {node:node for node in G.nodes()}; nx.draw_networkx_labels(G, pos, labels=node_labels).
MadeOfAir
¿Y si ya tiene un gráfico no dirigido y desea reproducir una copia dirigida del mismo? ¿Hay alguna forma de configurar la G.add_edges_from()línea sin tener que ingresar manualmente el punto inicial y final? ¿Quizás agregar bordes de a dict?
FaCoffee
La primera línea de código en esta sección (aparte de las líneas de importación) establece qué tipo de gráfico es y qué tipo de bordes acepta. Puedes pasar de un dígrafo (más información) a un gráfico (menos información) pero no puedes pasar de un gráfico (menos información) a un dígrafo (más información) sin la información o una forma de construir esa información que falta. Sugeriría poner su pregunta con un ejemplo en otra pregunta de desbordamiento de pila.
Back2Basics
1
¿Es posible obtener flechas reales en los bordes? No me gusta el final más grueso.
Wikunia
1
Dibujar puntas de flecha en matplotlib es complicado y actualmente no es compatible con NetworkX. Se aceptan solicitudes de extracción.
Back2Basics
33

En lugar de nx.draw normal, es posible que desee utilizar:

nx.draw_networkx(G[, pos, arrows, with_labels])

Por ejemplo:

nx.draw_networkx(G, arrows=True, **options)

Puede agregar opciones inicializando esa ** variable de esta manera:

options = {
    'node_color': 'blue',
    'node_size': 100,
    'width': 3,
    'arrowstyle': '-|>',
    'arrowsize': 12,
}

Además, algunas funciones admiten el directed=True parameter En este caso, este estado es el predeterminado:

G = nx.DiGraph(directed=True)

La referencia de networkx se encuentra aquí .

Gráfico con imagen de flechas

Raz
fuente
21

Necesita usar un gráfico dirigido en lugar de un gráfico, es decir

G = nx.DiGraph()

Luego, cree una lista de los colores de borde que desea usar y nx.drawpáselos a (como lo muestra @Marius).

Poniendo todo esto junto, obtengo la imagen de abajo. Todavía no es la otra imagen que muestra (no sé de dónde vienen los pesos de los bordes), ¡pero mucho más cerca! Si desea tener más control de cómo se ve su gráfico de salida (por ejemplo, obtener puntas de flecha que parecen flechas), vería NetworkX con Graphviz .

ingrese la descripción de la imagen aquí

mdml
fuente
Ah, salud, no pude entender por qué las flechas no funcionaban, ya que pude ver argumentos para ellas en la documentación.
Marius
9
import networkx as nx
import matplotlib.pyplot as plt

g = nx.DiGraph()
g.add_nodes_from([1,2,3,4,5])
g.add_edge(1,2)
g.add_edge(4,2)
g.add_edge(3,5)
g.add_edge(2,3)
g.add_edge(5,4)

nx.draw(g,with_labels=True)
plt.draw()
plt.show()

Esto es simplemente cómo dibujar un gráfico dirigido usando python 3.x usando networkx. Representación simple y se puede modificar y colorear, etc. Vea el gráfico generado aquí .

Nota: es solo una representación simple. Los bordes ponderados se pueden agregar como

g.add_edges_from([(1,2),(2,5)], weight=2)

y por lo tanto trazada de nuevo.

Panda de Padmalochan
fuente
1
import networkx as nx
import matplotlib.pyplot as plt

G = nx.DiGraph()
G.add_node("A")
G.add_node("B")
G.add_node("C")
G.add_node("D")
G.add_node("E")
G.add_node("F")
G.add_node("G")
G.add_edge("A","B")
G.add_edge("B","C")
G.add_edge("C","E")
G.add_edge("C","F")
G.add_edge("D","E")
G.add_edge("F","G")

print(G.nodes())
print(G.edges())

pos = nx.spring_layout(G)

nx.draw_networkx_nodes(G, pos)
nx.draw_networkx_labels(G, pos)
nx.draw_networkx_edges(G, pos, edge_color='r', arrows = True)

plt.show()
Sachin Rawat
fuente