Faire des cartes d'analyse avec QGIS 1.3.0 et PostGIS 1.3 đ
Introduction¶
Dans le monde des SIG libres, le choix des outils d'analyse est assez limité:
- GRASS pour les manipulations complexes (car la prise en main de GRASS est assez complexe, il faut le reconnaĂźtre).
- QGIS pour l'affichage simple.
- PostgreSQL/PostGIS permet également de faire des traitements mais pas de les afficher simplement.
D'oĂč la question: existe-t-il un moyen simple et efficace de reprĂ©senter de l'information gĂ©ographique travaillĂ©e et non brute de dĂ©coffrage ? Ma tentative de rĂ©ponse vient Ă la suite de cet article⊠Pour faire simple, disons, que oui c'est possible avec un peu d'entraĂźnement et surtout une bonne base de travail.
Le contexte de ce travail est d'utiliser uniquement QGIS et PostGIS pour afficher des cartes d'analyses. Une carte d'analyse est une carte qui croise de l'information géographique avec des données alphanumériques. Elles sont trÚs utilisées en statistiques par exemple et en termes d'efficacité, avec un outil comme MapInfo Pro (utilisation des analyses thématiques) et des données correctes, ce genre de carte prend 15 minutes environ à créer.
Nous voulons effectuer des croisements d'informations simples. Par exemple, colorier une commune en fonction d'une valeur donnée. Cette valeur n'est pas située dans une table géographique mais dans une table simplement alphanumérique.
Les capacitĂ©s de traitement de QGIS sont vraiment trĂšs limitĂ©es. On peut utiliser certains plugins genre ftools mais leur utilisation est assez complexe et surtout pas rĂ©servĂ©e Ă ce que nous voulons faire. En plus, ça ne fonctionne pas sur PostGIS. D'oĂč l'idĂ©e d'utiliser les capacitĂ©s de traitement de PostgreSQL et de PostGIS pour faire le travail. QGIS se contentera de l'affichage.
Tout est trĂšs simpleâŠ
PrĂ©requis¶
Je suppose que vous avez QGIS (l'exemple fonctionne avec la version 1.3.0 sous Debian Squeeze, compilée à la main, car le paquet disponible sur gfoss.it est buggé) et un serveur PostgreSQL sous la main avec l'extension PostGIS. Si ce n'est pas le cas, Google est votre ami et il vous donnera des tonnes de sites qui expliquent comment on fait pour mettre en place l'infrastructure.
Pour simplifier le sujet serveur PostgreSQL, on va dire qu'il est situé sur localhost, que la base de données utilisée sera nommée "GEOBASE_LOCALE" et que l'utilisateur qgis a tous les droits dessus, y compris celui de créer des tables.
Je suppose aussi que vous disposez de l'outil ogr2ogr (pour le chargement des données).
Une modĂ©lisation light¶
Voyons maintenant ce que ça donne sur un exemple concret:
- Nous avons le dessin des départements dans une table géographique (nommée DEPARTEMENT).
- Nous avons une donnée qui nous intéresse dans la table UTILISATEUR_LINUX.
La table DEPARTEMENT est une table contenant le dessin géométrique des communes du département. Elle est composée des champs suivants:
- code_dept: Code à deux caractÚres du département.
- the_geom: le champ géographique du département.
La table UTILISATEUR_LINUX contient des informations alphanumériques sur les utilisateurs de GNU/Linux. Une ligne correspond non pas à une commune mais à un utilisateur.
Pour chaque ligne, on a les champs suivants:
- ID_USER: identifiant de l'utilisateur.
- DEPARTEMENT: code sur deux chiffres du département de l'utilisateur.
- NB_MACHINES: Nombre de machines sous GNU/Linux de cet utilisateur.
Le lien entre la table géographique et la table alphanumérique est le code INSEE (champ INSEE dans les deux tables).
Pour la table UTILISATEUR_LINUX, on aurait pu choisir un modĂšle plus simple (genre une ligne par commune) mais le modĂšle de cette table va nous permettre de faire quelques agrĂ©gations⊠Ăa ne fait jamais de mal de voir ce qu'on peut faire comme calculs avec un peu de SQL.
Au final, nous allons créer une table géographique nommée LINUX qui contiendra les objets géographiques et les données alphanumériques qui nous intéressent à savoir:
- Nombre d'utilisateurs par département.
- Nombre de machines par département.
- Densité utilisateur: nombre d'utilisateurs par millier de km2 par département.
- Densité machines: nombre de machines par millier de km2 par département.
RĂ©cupĂ©rer les donnĂ©es¶
Pour les données géographiques, j'ai utilisé la couche GEOFLA des départements produite par l'IGN. Ces données sont non libres (pas d'exploitation commerciale) mais gratuites au format Shapefile (lien pour les télécharger) . Je vous conseille de télécharger dans la projection RGF93 car la suite des manipulations utilise cette projection.
Les données sont au format shapefile. Il faut donc les convertir et les charger dans le serveur PostGIS, ce que nous allons faire avec shp2pgsql comme suit:
$ shp2pgsql -s 2154 -d DEPARTEMENT DEPARTEMENT | psql -h localhost -U qgis -W GEOBASE_LOCALE
L'option -s 2154 permet de spécifier la projection (2154 correspond à RGF93) et -d permet d'effacer la table si elle existe déjà .
Pour les données de la table UTILISATEUR_LINUX, j'ai créé une table remplie avec des valeurs aléatoires dont vous pouvez disposer ici. Il s'agit d'un script SQL contenant des valeurs aléatoires. Pour injecter les données, il suffit de faire:
$ psql -h localhost -U qgis -W GEOBASE_LOCALE -f UTILISATEUR_LINUX.sql
Quelques prĂ©cautions techniques¶
Avant de crĂ©er une table gĂ©ographique, il ne faut pas oublier que QGIS impose certaines rĂšgles lors de la crĂ©ation de tables. D'abord, pour que QGIS liste la table LINUX, il est indispensable que les colonnes gĂ©ographiques soient renseignĂ©es dans la table "geometry_columns". C'est le comportement normal de PostGIS aussi, mais pas de PostgreSQL. L'ajout de cette information dans la table peut ĂȘtre effectuĂ© de deux maniĂšres. La technique utilisĂ©e est l'emploi de la requĂȘte suivante:
De plus, QGIS exige que la table dispose d'un champ d'identification qui doit ĂȘtre de type int et disposer d'une contrainte de clef unique. Enfin, QGIS travaille avec des valeurs plutĂŽt en rĂ©el (float8) qu'en entier (integer). Cette contrainte impose que les rĂ©sultats de requĂȘte soient convertis avant de pouvoir travailler avec.
CrĂ©er une couche avec des valeurs de rĂ©fĂ©rence et une donnĂ©e gĂ©ographique¶
L'objectif est de créer une couche en utilisant une jointure pour lier un objet géographique à une ou plusieurs valeurs. Ensuite, on utilisera QGIS pour affecter la couleur et gérer les classes.
Cette requĂȘte permet de crĂ©er la table gĂ©ographique LINUX en croisant les donnĂ©es gĂ©ographiques de la table DEPARTEMENT et les donnĂ©es alphanumĂ©riques de la table UTILISATEUR_LINUX en effectuant une agrĂ©gation d'informations (Nombre d'utilisateurs, nombre de machines, densitĂ© d'utilisateurs et densitĂ© de machines). Cette couche rĂ©pond aux exigences de QGIS.
Visualiser le rĂ©sultat¶
Le travail est centré sur les onglets de propriétés de la couche dans QGIS:
- Ouvrir QGIS.
- Se connecter au serveur PostGIS.
- Ouvrir la table LINUX.
- Normalement, une vue par défaut s'affiche tout est en couleur unie.
- Faire un clic droit sur la couche et choisir le menu "Propriétés".
- Choisir l'onglet "Convention des signes".
C'est dans cet onglet que l'on peut régler la représentation de la couche. QGIS nous propose 4 modes de représentation:
- Par symbole unique: chaque objet ponctuel se voit attribuer un symbole suivant des éléments. Dans notre cas, la couche étant surfacique, le menu ne propose rien.
- Par symbole gradué: chaque objet géographique se voit attribuer un style suivant son appartenance à une classe. C'est ce que nous voulons pour travailler ici sur les densités.
- Par couleur continue: chaque objet géographique se voit attribuer une couleur suivant une classe prédéfinie. Dans notre cas, la représentation ne donne pas grand-chose.
- Par valeur unique: chaque valeur unique de l'objet gĂ©ographique se voit attribuer un style. Ăa ressemble aux classes, en plus simple, si on a des valeurs discrĂštes.
Dans notre cas, seules les densités sont représentables avec les objets surfaciques des départements. Nous allons donc utiliser le symbole gradué. La représentation qui utilise ce mode est trÚs intéressante dans QGIS car elle permet de créer des classes de maniÚre assez simple:
- Choisir "Symbole gradué" dans la liste déroulante intitulée "Type de Légende".
- Choisir le champ qu'on désire représenter (ici: densité_machines).
- On peut sélectionner deux modes: par intervalles réguliers, c'est-à - dire que les classes sont espacées de maniÚre réguliÚre entre elles (de 10 en 10 par exemple). On peut également choisir par quantiles c'est-à -dire que les classes sont construites de maniÚre à représenter un nombre égal d'objets. Vu l'expression de notre densité de machines qui correspond au nombre de machines réparties en milliers de km2, la distribution est trÚs inégale: les densités les plus importantes sont forcément dans les plus petits départements. Il nous faut donc, dans ce cas, choisir le mode par quantiles.
- Choisir le nombre de classes: 5 par exemple.
- Générer les classes en cliquant sur le bouton "Classer"
- Cliquer sur OK pour affecter la représentation à la carte.
Voici ce qu'on obtient:
CrĂ©er une carte avec des points de couleur¶
Le principe est le mĂȘme que prĂ©cĂ©demment. Toutefois, au lieu de prendre l'objet gĂ©ographique, on va utiliser son centroĂŻde pour y positionner un symbole. Nous allons donc avoir besoin de la fonction PostGIS: ST_Centroid().
Cette requĂȘte permet de crĂ©er quasiment la mĂȘme table qu'auparavant mais gĂ©nĂšre des points et non des surfaces. Pour faire une carte digne de ce nom, il convient d'utiliser Ă©galement les surfaces, histoire d'amĂ©liorer le support visuel. On a donc intĂ©rĂȘt Ă ouvrir les couches LINUX_POINT et LINUX (ordre des calques Ă©galement). La couche LINUX sert uniquement de fond de carte, on va donc l'ouvrir et choisir une couleur neutre.
Travaillons maintenant sur la couche LINUX_POINT:
- Nous désirons afficher un symbole dont la taille sera proportionnelle au nombre de machines.
- Aller sur l'onglet convention des signes.
- Choisir le type de légende: symbole unique.
- Choisir le symbole (le crĂąne de hacker).
- Choisir le champ d'échelle de la surface: nb_machines.
- On peut employer le multiplicateur en bougeant les valeurs du champ "Taille".
Voici le résultat final:
Utiliser des vues¶
Notre mode opératoire permet de publier assez rapidement des cartes.
Toutefois, si les données de la table UTILISATEUR_LINUX changent, il
faut supprimer les couches (par la requĂȘte SELECT
dropgeometrytable('COUCHE')
) et relancer les requĂȘtes de croisement.
Cela peut se révéler assez fastidieux si la table change réguliÚrement.
Heureusement, PostgreSQL peut nous aider grĂące Ă son concept de vue: une
vue est une requĂȘte SELECT qui se lance Ă chaque fois qu'on interroge la
vue. Donc si la requĂȘte est longue, le rĂ©sultat met du temps Ă
s'afficher.
Pour utiliser des vues, il suffit d'employer le terme CREATE VIEW
au
lieu de CREATE TABLE
dans les requĂȘtes de croisement d'information.
L'intĂ©rĂȘt des vues c'est que l'on ne stocke rien en dur et que les
données sont toujours à jour par rapport à la table de référence. Le
plus important est bien d'affecter la colonne géométrie dans la table de
référence.
Si on utilise ensuite QGIS, on ne verra aucune diffĂ©rence: la table est prĂ©sente et rien n'indique que c'est une vue. En revanche, le premier affichage est plus long: c'est Ă ce moment que la requĂȘte est lancĂ©e. Dans notre cas, c'est assez rapide tout de mĂȘme.
Une idĂ©e: "Travailler avec des tables temporaires" ?¶
PostgreSQL supporte le concept de tables temporaires. Toutefois, ces derniĂšres se suppriment automatiquement Ă la fin du pool de requĂȘte. Je n'ai pas trouvĂ© comment les utiliser concrĂštement. Les vues me semblent mieux adaptĂ©es Ă notre objectif.