QGIS et l’analyse de graphe

Dans un précédent billet, il a été signalé qu’il existe peu d’outils intégrés au sein des SIG permettant d’analyser les réseaux. Néanmoins, les SIG libres peuvent être combinés à d’autres logiciels, programmes ou bibliothèques accroissant ainsi leur potentialité initiale. De plus, Grass (SIG libre qui, il est vrai, n’est pas des plus commodes à appréhender) permet d’effectuer différentes mesures sur des réseaux spatiaux.
Ce billet va présenter d’une part, comment réaliser un programme sur QGIS permettant d’analyser des réseaux spatiaux en ayant recours à des bibliothèques existantes d’analyse de réseaux (en l’occurrence, des bibliothèques développées en Python). D’autre part, ce billet va présenter un plugin réalisé à cet effet.

Utiliser une bibliothèque Python avec QGIS

Le SIG libre QGIS propose une console Python permettant d’interagir avec l’ensemble des outils de QGIS et par conséquent de développer de petits programmes automatisant plusieurs tâches. Dans les faits, il est plus souvent intéressant d’utiliser les nombreuses bibliothèques Python existantes afin d’étendre les capacités de QGIS. Par exemple, il existe de nombreuses bibliothèques permettant de réaliser de l’analyse de graphe (igraph, NetworkX…). Dans ce billet, nous allons utiliser NetworkX, bibliothèque développée originalement par Aric Hagberg, Dan Schult, et Pieter Swart (http://networkx.github.com/).

Pour utiliser une bibliothèque Python dans QGIS, il faut la télécharger (voici le lien pour la télécharger [1]), puis la dézipper et enfin la placer dans le répertoire des bibliothèques Python de QGIS. Ainsi, pour la version 1.8 (Lisboa) de QGIS, le répertoire se situe dans : « C:\Program Files\Quantum GIS Lisboa\apps\Python27\Lib\site-packages » (attention cette version de QGIS n’a pas été choisie par hasard, en effet elle implémente Python 2.7 qui est nécessaire pour la dernière version de NetworkX). Toutes les bibliothèques Python déjà présentes dans QGIS se trouvent dans ce répertoire (MapPlotLib, PyQt4…). La bonne complémentarité entre QGIS et Python est ici illustrée, car il n’y a plus rien à faire. Tout est installé et il est alors possible de réaliser de l’analyse de graphe avec QGIS, alors même qu’initialement ce n’était pas le cas.

Pour vérifier, il suffit d’ouvrir QGIS, d’aller dans « Extension -> Console Python », puis de taper les lignes de code suivantes :

>>> import networkx as nx  # Import de la bibliothèque NetworkX
>>> G=nx.Graph()  # Création d’un graphe G
>>> G.add_edges_from([(1,2),(1,3)])  # Création des arcs du graph G
>>> nx.clustering(G)  # Calcul les clustering coefficient des noeuds
{1: 0.0, 2: 0.0, 3: 0.0}
>>> nx.degree(G)  # Calcul les degrés des noeuds
{1: 2, 2: 1, 3: 1}

Analyser des graphes spatiaux dans QGIS avec Python

Cette étape est un peu plus complexe que la précédente. En effet, sans même avoir une grande connaissance de Python et de QGIS, il est possible d’utiliser la bibliothèque NetworkX dans QGIS en étudiant les tutoriels (voici le lien vers les tutoriels [2]). Faire interagir Python et QGIS ajoute un niveau de difficulté supplémentaire. Ainsi, partons du fait que deux couches ont été chargées dans QGIS. La première couche est composée de nœuds caractérisés par leur identifiant (vous pouvez télécharger un exemple ici). La deuxième couche est composée d’arcs caractérisés par leur identifiant, les deux identifiants des nœuds situés aux extrémités de l’arc et leur longueur (vous pouvez télécharger un exemple ici).

L’enjeu est alors de créer le graphe « NetworkX » à partir de ces deux couches. Pour cela, il faut récupérer les attributs des couches à l’aide de Python :

>>> canvas=qgis.utils.iface.mapCanvas() # Interaction avec la carte et les couches
>>> allLayers = canvas.layers() # Récupère les deux couches chargées dans QGIS
>>> couche_noeud = allLayers[0] # Récupère la couche supérieure
>>> couche_arc = allLayers[1]  # Récupère la couche inférieure
>>> provider = couche_arc.dataProvider() # Interaction avec la couche arc
>>> field=provider.fields() # Récupère les champs de la couche arc
>>> startind=provider.fieldNameIndex(‘depart’) # Index du champ « départ »
>>> endind=provider.fieldNameIndex(‘arrivee’)   # Index du champ « arrivée »
>>> distind=provider.fieldNameIndex(‘distance_K’) # Index du champ « distance_K »
>>> feat = QgsFeature()   # Permet de manipuler les entités des couches
>>> allAttrs = provider.attributeIndexes()   # Récupère les index des entités
>>> provider.select(allAttrs)   # Sélectionne toutes les entités 
>>> table=[]  # Création d’une table qui va récupérer les informations
>>> while provider.nextFeature(feat):  # Boucle parcourant l’ensemble des entités
…     attrs = feat.attributeMap()   # Récupère tous les attributs des entités
…     attrsstart=attrs.values()[startind].toInt()[0]  # Attribut nœud de départ
…     attrsend=attrs.values()[endind].toInt()[0]  # Attribut nœud d’arrivée
…     attrsdist=attrs.values()[distind].toInt()[0] # Attribut distance
…     table=table+[(attrsstart,attrsend,attrsdist)] # Ajoute les attributs récupérés à la table

Une fois les attributs des couches permettant de créer le graphe récupérés et après les avoir collectés dans un tableau, il est possible d’analyser ce graphe à l’aide la bibliothèque NetworkX :

>>> import networkx as nx  # Import de la bibliothèque NetworkX
>>> G=nx.Graph() # Création d’un graphe G
>>> G.add_weighted_edges_from(table) # Ajout des entités de la table au graphe G
>>> b=nx.betweenness_centrality(G,weight=’weight’) # Calcul de la centralité des noeuds du graphe G

Enfin, il est possible de récupérer les résultats obtenus pour les implémenter dans la couche nœuds :

>>> provider2 = couche_noeud.dataProvider() # interaction avec les données
>>> nbcol=int(provider2.fieldCount()) # Récupère le nombre de champs de la couche
>>> from PyQt4.QtCore import *   # Import de la bibliothèque PyQt4
>>> from PyQt4.QtGui import *   # Import de la bibliothèque PyQt4
>>> provider2.addAttributes([QgsField(« centralite », QVariant.Double)])
>>> taille=len(b)  # Récupère le nombre de nœuds
>>> couche_noeud.startEditing()  # Permet l’édition de la couche nœuds
>>> for k in range(taille):  # Boucle qui parcoure l’ensemble des nœuds
…      couche_noeud.changeAttributeValue(k,nbcol,b[k+1]) # Attribution des valeurs
>>> couche_noeud.commitChanges() # Enregistrement des changements

Toutes ces lignes de commande peuvent être récupérées et réorganisées pour créer un petit programme permettant de calculer les centralités des nœuds d’un graphe spatial (lien vers un fichier zip contenant un exemple ici) :

>>> execfile(« C:/Users/XXXXX/Desktop/centralite.py »)       # Appelle le programme à exécuter

Utiliser un plugin QGIS pour analyser des graphes spatiaux

Pour développer un plugin en Python dans QGIS, des connaissances supplémentaires en programmation sont nécessaires. Elles ne seront pas développées dans ce billet. Elles peuvent être trouvées sur ce site internet. Je vais plutôt introduire un petit plugin que j’ai développé. Il n’est pas très exhaustif, mais a pour objectif de montrer ce que l’on peut obtenir en combinant QGIS et une bibliothèque Python d’analyse de graphe.

Le dossier zip à télécharger se trouve ici. Une fois le dossier téléchargé et dézippé, il faut le placer dans le répertoire des plugins Python de QGIS. Pour la version Lisboa, le répertoire est le suivant : « C:\Program Files\Quantum GIS Lisboa\apps\qgis\python\plugins ». Le plugin est alors installé. Ensuite, il suffit de lancer QGIS pour que le plugin apparaisse dans « Extension -> Analyse de graphe ». S’il n’apparait pas, il faut aller dans « Extension -> Gestionnaire d’extensions » et cocher l’extension « Analyse de graphe version 0.1 ». Après avoir lancé le plugin, une boite de dialogue s’ouvre. Elle permet de sélectionner les nœuds et les arcs du graphe à étudier.

Après avoir validé cette première boite de dialogue, une deuxième boite de dialogue apparait. Elle permet de sélectionner les champs des extrémités des arcs, de préciser si le graphe est orienté ou non, de préciser si le graphe est pondéré ou non (et si oui, quel est le champ de cette pondération : distance, flux, importance…). Enfin, différents indicateurs sont proposés (ceux-ci peuvent être normalisés ou non).

Le tour est joué. Ainsi, un champ a été créé dans la couche des nœuds afin de stocker les résultats de la requête. Il est alors possible de réaliser une carte thématique finale.


Serge Lhomme

Maitre de conférences à l'université Paris Est Créteil - Docteur en géographie de l'université Paris VII spécialité "dynamique des milieux et risques"

More Posts - Website

10 réflexions au sujet de « QGIS et l’analyse de graphe »

  1. Ping : QGIS et l’analyse de graphe | All Around GIS

  2. Salut à tous, bon je travaille sur un sujet de fin d’étude dans lequel je suis appelé à réaliser un plugin en QGIS. j’ai développé le script python (qui se base sur la théorie des graphes). Votre plugin fait à peu près la même chose, sauf qu’il se focalise sur la distance la plus proche entre les nœuds, par contre mon algorithme doit avoir en sortie les distances les plus proches par rapport à la piste, route et les douars (que vous pouvez appeler aussi village) qui présentent des services de bases (ces douars sont représentés par leur id dans un fichier.json)

    les résultats doivent êtres affectées à une base de données postgres.

    Je suis débutant en plugin avec python + j’ai pas beaucoup de temps, si vous pouvez m’orienter je serais très reconnaissant. merci d’avance

    Anass : anass.ouhammou@gmail.com

    • Bonjour,

      je viens de lire le billet que vous signalez et (de relire) celui de Serge et, s’ils présentent des points communs, il me semble que ce dernier apporte des compléments utiles pour l’analyse de réseaux avec QGis.

      Merci en tout cas pour l’information.

      • bien sûr, mais le papier sur le Portail ne s’attelait qu’à une seule chose, la possibilité de transformer, avec Python, n’importe quel fichier shapefile en graphe avec le module Networkx, et non les traitements futurs qui n’étaient que suggérés et rendre justice à celui qui a permis que ce soit possible, Ben Reilly.

  3. How to install or compilat networkx on Quantum GIS Lisboa, I allways get this error:
    Traceback (most recent call last):
    File «  », line 1, in
    File « C:/PROGRA~1/Quantum GIS Lisboa/apps/qgis/./python\qgis\utils.py », line 309, in _import
    mod = _builtin_import(name, globals, locals, fromlist, level)
    ImportError: No module named networkx
    What i have to do ?

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *