Graphs et théorie des réseaux
en langage python
L'essentiel de cette page
Le module networkx (mais aussi igraph) de python permet de réaliser des graphs.
Cette page explique comment réaliser facilement un réseau et mettre en forme la couleur, la taille des disques et leurs labels.
1- Réaliser un premier graph, un premier réseau
1.1- Matrice d'adjacence
Tout parle d'une matrice d'adjacence : une matrice qui va établir la relation entre des objets.
Voici 4 exemples de matrices d'adjacence :
import numpy as np
A = np.array([[1, 1], [1, 1]]) # 2 objets, relation 1-1
A = np.array([[1, 1], [1, 2]]) # 2 objets, relation réciproque plus forte dans un sens
A = np.array([1,1,0,1,1,1,0,1,1]) ; A=A.reshape(3,3) # 3 objets
A = np.array([1,1,0,1,1,1,1,0,0,1,1,1,1,0,1,1]) ; A=A.reshape(4,4) # 4 objets
print(A)
Voici l'exemple à 4 objets :
[[1 1 0 1]
[1 1 1 0]
[0 1 1 1]
[1 0 1 1]]
On voit ici 4 objets que l'on peut appeler A, B, C et D où A interagit avec B, B avec C, C avec D et D avec A.
1.2- Représentation graphique sous networkx
import networkx as nx
import matplotlib.pyplot as plt
G = nx.from_numpy_array(A)
nx.draw(G)
plt.show()
1.3- Représentation graphique sous igraph
Voici un petit exemple d'igraph que je ne développerai pas plus ici (pour l'instant) car il est difficile à installer (compétition avec un autre igraph, packages graphiques nécessaires comme cairo, non utilisation de matplotlib).
import igraph
A = np.array([1,1,0,1,1,1,1,0,0,1,1,1,1,0,1,1]) ; A=A.reshape(4,4) # 4 objets
A = list(A)
g = igraph.Graph.Adjacency(A,mode=igraph.ADJ_UNDIRECTED)
obj = igraph.plot(g,vertex_label_size=15,vertex_size=35,vertex_color='#ffe4c4')
obj.show()
Quelques commandes utiles quand igraph pose des problèmes...
Archives pour igraphpip install pygobjectpip install cairocffipip install PyGTK pygtkpip install pangocairocffi python -m pip install --user pycairohttps://www.lfd.uci.edu/~gohlke/pythonlibs/#pycairo
CD C:\Users\apcma\Google Drive\IUT\LP\02_Dataviz_pythonpip install pycairo-1.18.1-cp37-cp37m-win_amd64.whl pip install C:\pycairo-1.18.1-cp37-cp37m-win_amd64.whl installer visual code C++14
2- Mise en forme des graphs
2.1- Préparer les données qui serviront d'exemple ici
import networkx as nx
import matplotlib.pyplot as plt
# 10 objets (vertices)
A = np.array([[1,1,0,1,0,0,0,0,0,0],
[1,1,1,0,0,0,0,0,0,0],
[0,0,1,1,1,0,0,0,0,0],
[0,1,0,1,2,0,0,0,0,0],
[0,0,1,1,1,0,0,0,0,0],
[0,1,0,1,2,0,0,0,0,0],
[0,0,1,1,1,0,0,0,0,0],
[0,0,1,1,1,0,0,0,0,0],
[0,1,0,1,2,1,0,0,0,0],
[0,1,0,2,1,0,1,0,0,0]]) ; # On notera une relation forte entre D et E.
G = nx.from_numpy_array(A)
2.2- Mettre des labels aux nodes (networkx)
Il faut éditer un dictionnaire pour l'exemple de la partie 2.1.
dic= {0:"Adonis", 1:"Achille", 2:"Ménélas",3 :"Dartagnan",4 :"Paris",5 :"Hélenne",6 :"Zeus",7 :"Hector",8 :"Agamemnon",9 :"Juliette"}
G = nx.relabel_nodes(G, dic) # Nommer les labels
nx.draw(G,with_labels=True,font_size=8)
plt.show()
plt.figure(figsize=(10,6))
nx.draw(G,with_labels=True,font_size=8,
alpha=0.8,node_color="#A86CF3")
plt.show()
Remarque :
On peut aussi ajouter les labels indépendamment (utile pour la partie 3) :
nx.draw_networkx_labels(G,position)
2.3- Mettre en forme les sommets / nœuds / points / vortex / vertices
importance = dict(nx.degree(G))
importance = [v*v*v+40 for v in importance.values()]
nx.draw(G,with_labels=True,font_size=8,
node_color="#F9CD45",
node_size = importance)
plt.show()
2.4- Changer l'épaisseur des traits / liens / lignes en fonction de l'interconnexion
plt.figure(figsize=(10,6))
edges,weights = zip(*nx.get_edge_attributes(G,'weight').items())
position = nx.spring_layout(G)
nx.draw(G, position ,
node_color='#E97EF7',
edgelist=edges,
with_labels=True,
edge_color=weights,
width=weights*3,
edge_cmap=plt.cm.Blues, node_size = importance)
plt.show()
Un exemple où l'on fait varier les couleurs des traits sur le même graph : exemple d'un corrélogramme
# Créer une matrice d'adjacence de type matrice de corrélation
import seaborn as sns
iris = sns.load_dataset('iris')
mycor = iris.corr() # Matrice de corrélation non filtrée par les p-values
import numpy as np
mycor2 = np.array(mycor) # Conversion de la matrice pandas en matrice array
labels = list(mycor.columns.values) # Conversion au format list des noms de variables
key_list = list( range(len(labels)))
dic = dict(zip(key_list, labels))
# Définir les couleurs en fonction des valeurs de corrélation (>0 : rouge, <0 : bleu)
import networkx as nx
G = nx.from_numpy_array(mycor2)
edges,weights = zip(*nx.get_edge_attributes(G,'weight').items())
# Coloration conditionnelle
weights = list(weights)
for i in range(len(weights)) :
if weights[i] < 0 :
weights[i] = "red"
else :
weights[i] = "blue"
weights = tuple(weights)
# Tracer le réseau
# Nommer les labels
G = nx.relabel_nodes(G, dic)
import matplotlib.pyplot as plt
plt.figure(figsize=(6,6))
nx.draw(G,with_labels=True,font_size=8, alpha=0.8, node_color="#FFFFD3", edge_color=weights)
plt.show()
Si je souhaite colorer différemment mes arêtes non pas en fonction de la valeur de connexion mais en fonction du type de variables interconnectées :
Exemple : relier en orange les variables seulement si elles appartiennent toutes les 2 à la catégorie A
categorieA = ["sepal_length","sepal_width","petal_length"]
# Coloration conditionnelle
weights = list(weights)
import numpy as np
for i in range(len(edges)) :
#if edge[0].isin(categorieA) :
edge = edges[i]
if (np.isin(edge[0], categorieA)) and (np.isin(edge[1], categorieA)) :
weights[i] = 'orange'
else :
weights[i] = 'pink'
weights = tuple(weights)
# puis ré-exéctuer le code d'affichage ci-dessus
Dans cet igraph, les connexions entre petal_width et une autre variable figurent en rose. Par cette approche, je peux colorer disinctement les connexions (type variable de type A avec A, A avec B ou B avec B)
3- Détection et coloration des communautés
La détection de communauté est disponible sous python mais peut être rendu plus performante si on fait appel à certaines fonctions de R.
Voici un exemple qui se fait automatiquement, mais qui ne doit pas être pris en tant qu'aboutissement car la détection des communautés nécessite un paramétrage subtile et une connaissance de la théorie des graphs.
Cet exemple demande le module communauté, installer :
pip install community python-louvain
En reprenant l'exemple donné au début de la partie 02 :
from community import community_louvain
# Identification des communautés
partition = community_louvain.best_partition(G)
G.add_nodes = partition
position = nx.spring_layout(G) # Identifier la structure du graph
plt.figure(figsize=(7, 7))
plt.axis('off') # Pas d'axes
# Les cercles
nx.draw_networkx_nodes(G, position,
width=100,edge_color="black",
cmap=plt.cm.RdYlBu,
node_color=list(partition.values()))
# Les traits
nx.draw_networkx_edges(G, position, alpha=0.3)
# Les labels (optionnel)
nx.draw_networkx_labels(G,position)
plt.show(G)
4- Changer le type de graphe
4.1- Diagramme Chord (Chord diagram)
plt.figure(figsize=(18,18))
nx.draw_circular(G,
node_color='g', # Couleur des sommets
#(node/vertices/ronds) , vert
edge_color='#909090', # Couleur des traits
node_size=900) # Taille des sommets
plt.axis('equal')
plt.show()
Fonctions à explorer (en projet)
nx.get_node_attributes(G,'name') # pour récupérer les attribues d'un graph
nx.to_dict_of_dicts(G, nodelist=dic) # fonction de gestion des dicts à explorer
G.add_nodes_from(["Bob Morane","Achille"]) # Ajouter des nodes