comment dessiner des graphiques dirigés en utilisant networkx en python?

101

J'ai des nœuds provenant d'un script que je souhaite mapper sur un graphique. Dans ce qui suit, je veux utiliser Arrow pour aller de A à D et avoir probablement le bord coloré aussi (rouge ou quelque chose du genre).

C'est fondamentalement, comme un chemin de A à D lorsque tous les autres nœuds sont présents. vous pouvez imaginer chaque nœud comme des villes et voyager de A à D nécessite des directions (avec des flèches).

Ce code ci-dessous construit le graphique

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

mais je veux quelque chose comme montré dans l'image.entrez la description de l'image ici entrez la description de l'image ici

Les flèches de la première image et les bords de couleur rouge sur la deuxième image.

idée de génie
la source

Réponses:

86

Exemple complet avec des flèches pour uniquement les bords rouges:

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

Bords rouges

Marius
la source
1
c'est fou à quel point nos deux images mises à jour sont différentes. +1 pour déterminer les couleurs des bords!
mdml
pourquoi votre bord (C, E) n'est-il pas rouge, alors qu'il doit être rouge selon votre code ci-dessus?
brain storm
n'est-il pas possible d'avoir ces flèches uniquement sur les arêtes d'intérêt? par exemple (A, C) et (C, E)
brain storm
@ user1988876: Ah, désolé, ce (C, E)n'est pas rouge parce que j'ai choisi les arêtes pour le red_edgesmoment où je travaillais encore avec votre graphique non orienté, en sélectionnant simplement au hasard les arêtes renvoyées par G.edges(). Ça devrait être red_edges = [('A', 'C'), ('E', 'C')].
Marius
@ user1988876: Il est possible d'avoir des flèches sur certains bords seulement avec des appels séparés à draw_networkx_edges(). J'ai nettoyé le code et corrigé les problèmes DiGraph.
Marius
47

Je ne l'ai mis que par souci d'exhaustivité. J'ai beaucoup appris de marius et de mdml. Voici les poids des bords. Désolé pour les flèches. On dirait que je ne suis pas le seul à dire que cela ne peut pas être aidé. Je ne pouvais pas rendre cela avec le cahier ipython, je devais passer directement de python, ce qui était le problème pour obtenir mes poids de bord plus tôt.

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

entrez la description de l'image ici

Back2Basics
la source
9
J'ai exécuté ceci et n'ai pas obtenu les étiquettes de nœud. Vous devez ajouter ces: node_labels = {node:node for node in G.nodes()}; nx.draw_networkx_labels(G, pos, labels=node_labels).
MadeOfAir
Et si vous avez déjà un graphe non orienté et que vous souhaitez en reproduire une copie dirigée? Existe-t-il un moyen de définir la G.add_edges_from()ligne sans avoir à saisir manuellement le point de départ et d'arrivée? Peut-être ajouter des arêtes à partir d'un dict?
FaCoffee
La première ligne de code de cette section (autre que les lignes d'importation) définit le type de graphe et le type d'arêtes qu'il accepte. Vous pouvez passer d'un digraphe (plus d'informations) à un graphique (moins d'informations) mais vous ne pouvez pas passer d'un graphique (moins d'informations) à un digraphe (plus d'informations) sans les informations ou un moyen de construire ces informations manquantes. Je suggérerais de poser votre question avec un exemple dans une autre question de débordement de pile.
Back2Basics
1
Est-il possible d'obtenir de vraies flèches sur les bords? Je n'aime pas la fin juste plus épaisse.
Wikunia
1
Dessiner des pointes de flèches dans matplotlib est délicat et n'est actuellement pas pris en charge dans NetworkX. Les demandes de tirage sont acceptées.
Back2Basics
33

Au lieu de nx.draw normal, vous pouvez utiliser:

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

Par exemple:

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

Vous pouvez ajouter des options en initialisant cette ** variable comme ceci:

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

Certaines fonctions prennent également en charge le directed=True parameter Dans ce cas, cet état est celui par défaut:

G = nx.DiGraph(directed=True)

La référence networkx se trouve ici .

Graphique avec image de flèches

Raz
la source
21

Vous devez utiliser un graphe orienté au lieu d'un graphe, c'est-à-dire

G = nx.DiGraph()

Ensuite, créez une liste des couleurs de bord que vous souhaitez utiliser et transmettez-les nx.draw(comme indiqué par @Marius).

En mettant tout cela ensemble, j'obtiens l'image ci-dessous. Ce n'est toujours pas tout à fait l'autre image que vous montrez (je ne sais pas d'où viennent vos poids de bord), mais beaucoup plus proche! Si vous voulez plus de contrôle sur l'apparence de votre graphique de sortie (par exemple, obtenir des pointes de flèches qui ressemblent à des flèches), je vérifierais NetworkX avec Graphviz .

entrez la description de l'image ici

mdml
la source
Ah, bravo, je ne pouvais pas comprendre pourquoi les flèches ne fonctionnaient pas car je pouvais voir des arguments pour eux dans la documentation.
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()

C'est simplement comment dessiner un graphe dirigé en utilisant python 3.x en utilisant networkx. juste une représentation simple et peut être modifiée et colorée, etc. Voir le graphique généré ici .

Remarque: ce n'est qu'une simple représentation. Des bords pondérés pourraient être ajoutés comme

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

et donc tracé à nouveau.

Panda Padmalochan
la source
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
la source