come disegnare grafici diretti usando networkx in python?


101

Ho alcuni nodi provenienti da uno script che voglio mappare su un grafico. Di seguito, voglio usare Arrow per andare da A a D e probabilmente ho anche il bordo colorato in (rosso o qualcosa del genere).

Questo è fondamentalmente, come un percorso da A a D quando tutti gli altri nodi sono presenti. puoi immaginare ogni nodo come città e viaggiare da A a D richiede direzioni (con punte di freccia).

Questo codice seguente costruisce il grafico

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

ma voglio qualcosa come mostrato nell'immagine.inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

Punte di freccia della prima immagine e bordi di colore rosso sulla seconda immagine.

Risposte:


86

Esempio completamente arricchito con frecce solo per i bordi rossi:

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

Bordi rossi


1
è pazzesco quanto siano diverse le nostre due immagini aggiornate. +1 per aver capito i colori dei bordi!
mdml

perché il tuo bordo (C, E) non è rosso, anche se deve essere rosso secondo il tuo codice sopra?
tempesta cerebrale

non è possibile avere queste punte di freccia solo sui bordi di interesse? ad esempio (A, C) e (C, E)
tempesta cerebrale

@ user1988876: Ah, scusa, (C, E)non è rosso perché ho scelto i bordi per red_edgesquando stavo ancora lavorando con il tuo grafico non orientato, scegliendo a caso dai bordi restituiti da G.edges(). Dovrebbe essere red_edges = [('A', 'C'), ('E', 'C')].
Marius

@ user1988876: è possibile avere frecce solo su alcuni bordi con chiamate separate a draw_networkx_edges(). Ho ripulito il codice e risolto i problemi di DiGraph.
Marius

47

L'ho inserito solo per completezza. Ho imparato molto da marius e mdml. Ecco i pesi dei bordi. Mi dispiace per le frecce. Sembra che non sia l'unico a dire che non può essere evitato. Non ho potuto renderizzare questo con ipython notebook, ho dovuto passare direttamente da python, che era il problema con l'inserimento prima dei pesi dei bordi.

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

inserisci qui la descrizione dell'immagine


9
L'ho eseguito e non ho ricevuto le etichette dei nodi. È necessario aggiungere questi: node_labels = {node:node for node in G.nodes()}; nx.draw_networkx_labels(G, pos, labels=node_labels).
MadeOfAir

E se si dispone già di un grafico non orientato e si desidera riprodurne una copia diretta? Esiste un modo per impostare la G.add_edges_from()linea senza dover inserire manualmente il punto iniziale e finale? Forse aggiungendo bordi da un dict?
FaCoffee

La prima riga di codice in questa sezione (diversa dalle righe di importazione) imposta il tipo di grafico e il tipo di bordi che accetta. Puoi passare da un digrafo (più informazioni) a un grafico (meno informazioni) ma non puoi passare da un grafico (meno informazioni) a un digrafo (più informazioni) senza le informazioni o un modo per costruire quelle informazioni mancanti. Suggerirei di porre la tua domanda con un esempio in un'altra domanda di overflow dello stack.
Back2Basics

1
È possibile ottenere vere frecce sui bordi? Non mi piace solo la parte più spessa.
Wikunia

1
Disegnare le punte di freccia in matplotlib è complicato e attualmente non è supportato in NetworkX. Si accettano richieste pull.
Back2Basics

33

Invece del normale nx.draw potresti voler usare:

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

Per esempio:

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

Puoi aggiungere opzioni inizializzando quella ** variabile in questo modo:

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

Inoltre alcune funzioni supportano il directed=True parameter In questo caso questo stato è quello predefinito:

G = nx.DiGraph(directed=True)

Il riferimento a networkx si trova qui .

Grafico con l'immagine delle frecce


21

È necessario utilizzare un grafico diretto invece di un grafico, ad es

G = nx.DiGraph()

Quindi, crea un elenco dei colori dei bordi che desideri utilizzare e nx.drawpassali a (come mostrato da @Marius).

Mettendo tutto insieme, ottengo l'immagine qui sotto. Ancora non proprio l'altra foto che mostri (non so da dove provengano i tuoi pesi di spigolo), ma molto più vicino! Se desideri un maggiore controllo sull'aspetto del grafico di output (ad esempio, ottieni punte di freccia che sembrano frecce), controlla NetworkX con Graphviz .

inserisci qui la descrizione dell'immagine


Ah applausi, non sono riuscito a capire perché le frecce non funzionassero perché potevo vedere gli argomenti per loro nella documentazione.
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()

Questo è solo semplice come disegnare un grafico diretto usando python 3.x usando networkx. solo semplice rappresentazione e può essere modificato e colorato ecc. Vedere il grafico generato qui .

Nota: è solo una semplice rappresentazione. È possibile aggiungere bordi ponderati come

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

e quindi tracciato di nuovo.


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()
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.