Faire des cartes d'analyse avec QGIS 1.3.0 et PostGIS 1.3

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 un 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 terme 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...

logo PostGIS logo QGIS

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épartement 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... Ca 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 ([http://professionnels.ign.fr/ficheProduitCMS.do?idDoc=5323861 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. Ca ressemble aux classes en plus simple, si on a des valeurs discrètes.

densités réglages

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ères 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 nombres 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:

Densité Linux

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".

nombre de réglages

Voici le résultat final:

Nombre de machines Linux

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 fasitidieux 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.

Exemple pour la table LINUX_POINT:

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.

Références:

Posted mar. 03 nov. 2009 10:22:00 Tags:

Ceci est le premier post sous PyBlosxom

       This is my first post with PyBlosxom.

Comme ils disent...

Si tu vois ça, ça veut dire que j'ai réussi à faire une redirection cgi-bin sous Apache2, chose que je n'ai jamais faîte avant ! En plus de ça, si ça s'affiche direct, c'est que j'ai réussi à régler tous les problèmes d'encodage !!

Voilà, ce premier post est sous PyBlosxom... et en HTML à la main s'il vous plaît. Pourquoi changer ? En fait, à la base le test de pyblosxom est une expérimentation. Avec le temps, j'ai trouvé Serendipity assez lourd à gérer même avec son mode Wiki: écrire des vrais articles avec des photos et du code commenté est assez pénible. Comme pleins de gens semblaient utiliser pyblosxom ou blosxom, j'ai cru bon de faire un essai. Le concept me plaît bien: un script en Python, un seul fichier de conf, des articles sous forme de fichiers textes et c'est parti. Donc, me voilà avec mon Vim et mon fichier texte...

Avant de continuer, voici quels sont mes critères pour accepter PyBlosxom comme moteur de blog officiel:

  • Avoir une bonne gueule (genre celle du blog sous serendipity).
  • Trouver de quoi rédiger des billets en mode wiki.
  • Trouver de quoi coloriser du code, notamment le SQL pour les requêtes PostGIS.
  • Bien gérer l'encodage, particulièrement en UTF-8: je ne veux pas réencoder tous les fichiers servis par Apache !
  • Avoir de quoi publier à distance.
  • Avoir une gestion simple des images.
  • Permettre de gérer des arborescences de fichiers (pour les codes sources, les exemples de scripts, etc...).
  • Permettre d'ajouter du HTML direct dans les articles (bien pour les cartes dynamiques OpenStreetMap).
  • Permettre la reprise de tous les articles de Serendipity, à charge pour moi de conserver les bonnes URI permanentes (parce que n'oublions pas que les URL cool ne changent pas).

Mes premières investigations:

Encodage et RSS

Pour gérer l'encodage, j'utilise une balise meta qui indique le charset. Il faut placer cette balise dans le thème (flavour pour PyBlosxom) html et dans la partie head. J(y ai également inséré les éléments pour les flux RSS (balises link dans l'entête). Il ne me reste qu'à réaliser une icône favicon.

En plus de ça, j'ai bien travaillé sur la partie en-tête. En effet, de temps en temps, c'est bon de revenir aux fondammentaux: les recommandations du W3C. Voici quelques balises que j'ai ajoutées:

  • meta http-equiv="Content-Type" content="text/html; charset=utf-8"
  • meta name="description" content="$(blog_description)"
  • meta name="author" content="$(blog_author)"

Gestion de la rédaction en mode Wiki

Après avoir lu la documentation de pyblosxom, je vois qu'il existe plusieurs plugins permettant de faire ça. Dans la liste, je vois un truc que je ne connaissais pas: le plugin rst. Après plus amples investigations, rst signifie "reStructuredText". L'intérêt principal, c'est que sa syntaxe est très proche du Wiki. Dans le principe et après avoir consulté la QuickRefList, je vois que je maîtrise l'essentiel et que certaines fonctionnalités vont plus loin que ce que Serendipity pouvait faire.

Ce plugin agit au niveau du traitement des fichiers textes qu'il faut d'ailleurs renommer avec une extension .rst pour que la transformation se fasse. Du coup, je m'en vais l'installer. Il dépend du paquet python-docutils... Donc, après ce premier billet en HTML manuel, le reste devrait suivre en rst et en couleur...

Coloration syntaxique

En ce qui concerne la coloration syntaxique, il existe un module Python qui fait ça bien: il se nomme pygments. Il gère pas mal de langages différents dont le SQL qui m'intéresse. Son mode d'installation est très simple: aptitude install python-pygments

Références:

Posted lun. 16 nov. 2009 20:34:37 Tags:

Le deuxième article est en ReStructuredText (rst) et en couleur...

Normalement, si tout va bien, je peux faire joujou avec le format ReStructuredText qui est très proche de la syntaxe Wiki.

Gestion de la couleur syntaxique:

Pour gérer la couleur syntaxique, il faut disposer des éléments suivant:

  • python-pygments (pour lenny, il vaut mieux prendre la version backports).
  • le module rst de pyblosxom.
  • copier le fichier /usr/share/doc/python-pygments/examples/rst-directive.py dans le répertoire des plugins.
  • éditer ce fichier rst-directive.py en modifiant la variable INLINESTYLES de False à True.

Toutes ces petites informations ont été récupérées sur le blog de GreyGreen.

A partir de maintenant, je peux utiliser la coloration syntaxique de manière simple. Un petit exemple en Python pour commencer:

Un exemple de SQL (une requête pour PostGIS):

Fin du test...

Edition externe:

Il me faut également un moyen de gérer l'édition à distance. Pour celà, vu la simplicité de pyblosxom, il suffit de trouver un moyen de poser un ou plusieurs fichiers distants. Je pense me tourner vers WebDav sur du HTTPS. La technique est éprouvée , elle permet de passer la majorité des proxy et des firewalls. SSL devrait permettre de chiffrer le traffic. Vu la taille des fichiers que je risque de déposer (du texte sous vim, des images assez réduites), le traffic doit être suffisant.

Donc, ce que je retiens comme solution, c'est la mise en place d'un partage Webdav en écriture sur toute la partie du blog. Ca permettra de gérer également les thèmes (flavours) de pyblosxom surlesquels, j'ai encore du travail... Toutefois, il faut encore régler un autre problème: celui des images !

Gestion des images:

Maintenant que la rédaction et la forme du texte est bien gérée, il faut pouvoir mettre des images de manière simple. A vue de nez, le plus simple c'est pour les images externes:

Logo de PostGIS On peut également utiliser les figures ce qui donne la chose suivante (avec la même image):

image

Notez ici la présence d'une légende pour l'image.

Maintenant, le problème se pose pour les images internes. En effet, il faut déjà trouver un moyen de poser les images au bon endroit. Ensuite, il faut indiquer où elles se trouvent. Or, pyblosxom ne traite pas l'emplacement des images. Le script CGI de pyblosxom se contente de gérer les images avec des URL. Par exemple, si j'essaye de mettre une image locale, voici le résultat:

image En gros, le script ne met pas d'image. Pourtant, l'image est bien présente dans le bon répertoire... Donc, comment gérer les images avec pyblosxom ?

Après avoir étudié quelques sites qui tournent avec blosxom ou pyblosxom, je suis arrivé à déterminer différents modes de gestion:

  • Mettre toutes les images dans un autre endroit du serveur Web (en gros: http://serveur.org/images/) et mettre des liens vers ces images.
  • Utiliser un plugin qui permet à pyblosxom de "servir" des fichiers d'images.
  • Mettre les images dans une autre arborescence servie par le serveur Web. Cette arborescence suit celle du Blog.

La solution du plugin pour pyblosxom n'est pas intéressante: si ce n'est pas prévu dès le départ, c'est que ce n'est pas utile. Ensuite, il n'y a aucun intérêt à ce que le script CGI lise l'intégralité des images pour les resservir comme il faut.

Mettre tout dans le même répertoire c'est pénible pour le tri. En fait, si on observe la majorité des blogs sous Pyblosxom, il n'y a guère d'images... ça se comprend ! Donc, la solution est de stocker les images dans une autre arborescence que je vais nommer images/blog/catégorie/sub-catégorie/article_sans.html/nom_image ! Si tout va bien, et pour me conformer aux URL cools, je vais devoir trouver un moyen de générer les images selon leur type de manière à enlever les extensions. Mais ça, ce sera pour plus tard.

En plus de ces aspects purement fichiers, je n'ai pas trop envie de gérer les tailles d'images. En règle générale, dans les blog, l'image est gérée en deux passes: dans le corps de l'article, les images sont de tailles réduites. Quand on clique dessus, une nouvelle page avec l'image en taille originale s'affiche. C'est ce que j'aimerais bien faire sans me prendre la tête, c'est à dire, sans devoir le faire à la main car je pense que c'est une opération automatisable.

Après avoir tenté de coder un plugin pour faire ça, je me suis rendu compte qu'il n'était pas possible de le faire comme je le voulais: la séquence d'automatisation est impossible à gérer avec pyblosxom. Donc, je vais utiliser juste la directive .. image:: avec l'option target et utiliser un script pour convertir mes images (les réduire). Le reste sera géré manuellement. Code du one-liner pour la conversion des images (à lancer dans le répertoire qui contient les images)

Inclusion de HTML:

Parfois, il est bon de pouvoir inclure du HTML directement dans le texte. C'est particulièrement vrai pour inclure des cartes OpenStreetMap dynamiques par exemple. Tout cela est parfaitement possible grâce à la directive .. raw:: html.

Voici un petit exemple de carte OpenStreetMap (ici une simple iframe mais je suppose qu'on peut utiliser l'API OpenLayers):


Voir une carte plus grande

Posted mer. 18 nov. 2009 10:22:00 Tags:

Faire un paquet Debian QGIS avec support PostGIS:

QGis est une application de SIG libre qui fonctionne avec QT. En terme de fonctionnalités, on peut dire qu'il s'approche de ce que MapInfo peut faire (surtout lorsqu'il existe PostGIS derrière pour faire des requêtes). La dernière version de l'application est la 1.3.0. Pour Debian Squeeze, il existe un paquet sur debian.gfoss.it mais j'ai remarqué qu'il plante avec les couches sous PostGIS.

Plutôt que de me prendre la tête, voici un petit topo sur la fabrication des paquets liés à QGIS sur une Debian Squeeze.

Origine du source: http://download.osgeo.org/qgis/src/qgis_1.3.0.tar.gz

Il faut décompresser le fichier qgis_1.3.0.tar.gz dans un répertoire et s'y mettre dedans: ~ tar xvf qgis_1.3.0.tar.gz && cd qgis_1.3.0

Créer l'arborescence du paquet: ~ dh_make -c gpl2 -createorig

Installer les dépendances:

aptitude install libgdal1-dev grass-dev libgsl0-dev flex bison cmake python-qt4-dev sharutils sip4 libqt4-core libqt4-dev libqt4-gui libqt4-qt3support pyqt4-dev-tools libpq-dev libgdal1-1.6.0-grass

Création du paquet:

dpkg-buildpackage -rfakeroot

A la fin, impossible de signer les paquets (mais pas grave !).

Installation des paquets:

cd .. && dpkg -i libqgis1.3.0_1.3.0_i386.deb python-qgis_1.3.0_i386.deb qgis_1.3.0_i386.deb qgis-plugin-grass_1.3.0_i386.deb python-qgis-common_1.3.0_all.deb qgis-common_1.3.0_all.deb qgis-plugin-grass-common_1.3.0_all.deb

Posted mer. 25 nov. 2009 20:38:23 Tags:

Un peu de prospective avec et sur OpenStreetMap

Introduction

Je l'ai déjà affirmé maintes fois, OpenStreetMap, c'est bien... Maintenant, c'est encore mieux de savoir ce qu'on peut faire avec. Pour l'instant, la partie visible de l'iceberg,celle qui est mise en avant par l'outil, consiste en un outil de réalisation de carte sur internet à la "Google Maps". Cette fonctionnalité est certes très intéressante mais en fait, on peut aller beaucoup plus loin !

C'est parce que les données sont libres, qu'on peut en faire ce que l'on veut. Puisqu'OSM contient plus que des informations sur les routes et chemins, on peut en extraire davantage d'informations et les recouper pour former une argumentation, pour vérifier ce que le terrain révèle plutôt que du pifométrique. Quelques exemples de questions qui peuvent trouver réponses avec OSM:

  • Est-ce-que ma ville est bien équipée en transports en communs ?
  • Combien y-a-t il de kilomètres de pistes cyclables dans mon département ?
  • Quel est le niveau d'exhaustivité d'OSM sur un thème particulier ?

Cet article a pour objet d'illustrer le potentiel d'OSM sur la prospective au niveau d'un territoire. La limite d'étude, car il faut bien en fixer une, sera l'emprise de la région des Pays-de-la-Loire. D'abord parce que c'est une région que je connais, ce qui me permettra d'éviter les erreurs d'appréciation (genre si une commune disparaît du lot de données, je devrais bien pouvoir l'identifier). Ensuite parce qu'il y suffisamment de données au niveau régional pour permettre une anayse comparative entre départements par exemple.

Avant de nous lancer, il ne faut pas oublier qu'OSM est loin d'être exhaustif en terme de données. Explorer les données va nous permettre également de nous en rendre compte mais surtout de voir "là où le bat blesse" et où il faudrait apporter de l'effort.

Etape 0: Pré-requis

Pour les besoins de l'expérience, vous avez besoin d'un SGBD spatial et d'un visualisateur de couches géographiques. Dans mon cas, j'utilise PostGIS comme SGBD spatial et QGIS pour visualiser les données. Si vous ne diposez pas de ces outils, allez sur Google et renseignez-vous sur la manière de les installer. Je pars du principe que ces outils sont bien installés et configurés. L'objet de cet article n'est pas de passer en revue ce point important certes mais qui prendrait des plombes à expliquer.

Etape 1: Récupérer les données

Avant de commencer, il convient de récupérer les données. En effet, si OSM permet de downloader en temps réel les informations dont vous avez besoin, nous n'allons pas utiliser ce moyen direct mais bien télécharger des données snapshots récentes. Si on procède ainsi, c'est avant tout pour des raisons d'efficacité: des serveurs proposent des snapshots de données, prêts à être intégrés dans une base de données spatiale. Ensuite, il y a les problèmes de trafic réseau: notre limite d'étude (Région Pays-de-la-Loire) représente déjà 25Mo de données brutes.

Pour plus d'informations, sur les modes de récupération, je vous laisse lire l'URL suivante: http://wiki.openstreetmap.org/wiki/FR:Planet.osm . Pour ma part, j'utilise les extraits de géofabrik qui ont l'avantage d'être mis à jour tous les jours. Les données sont disponibles ici: http://download.geofabrik.de/osm/europe/france/ . Pour récupérer les données de notre région d'étude, un simple wget http://download.geofabrik.de/osm/europe/france/pays-de-la-loire.osm.bz2 suffit.

Ces données sont au format .osm qui est du XML à la sauce OSM. Pour information, c'est le format utilisé par JOSM. La référence du XML est présentée dans le Wiki officiel: http://wiki.openstreetmap.org/wiki/.osm . Maintenant, il reste à passer du format .osm à du SQL à injecter dans PostGIS. Pour cela, il existe un script nommé osm2pgsql, qui se charge d'effectuer la transformation et le chargement en base de données directement. Sous Debian, ce script est présent dans le paquet osm2pgsql (d'où un simple # aptitude install osm2pgsql.

L'utilisation du script est triviale: $ osm2pgsql -c -d GEOBASE_LOCALE -E 2154 -u -U sid_admin -H localhost -W pays-de-la-loire.osm.bz2

  • -c: permet de créer les tables dans la base de données.
  • -d GEOBASE_LOCALE: permet d'indiquer le nom de la base de données spatiale qui va servir à stocker les données.
  • -E 2154: permet de préciser que nous voulons des données en RGF93.
  • -u: permet de gérer les problèmes d'encodage UTF-8.
  • -U sid_admin : permet d'indiquer le login de l'utilisateur sous PostgreSQL.
  • -H localhost : le serveur est sur localhost.
  • -W : demande un mot de passe pour le login PostgreSQL.

Le lancement du script prend généralement du temps: compter environ 1 à 5 minutes de chargement pour une région. Le script génère 4 tables dans la base de données spatiale:

  • planet_osm_point: qui contient les données ponctuelles.
  • planet_osm_line: qui contient les données linéaires.
  • planet_osm_polygon: données sous forme de polygones.
  • planet_osm_roads: table contenant les données linéaires des routes.

Etape 2: Afficher les données avec QGIS

Les tables générées par le chargement des données d'OSM sont directement utilisables dans QGIS. Il suffit de lancer ce dernier, de se connecter à la base de données spatiale, de sélectionner les 4 couches et d'afficher le résultat.

OSM brut

Bon, c'est beau mais on peut mieux faire: sélectionner ce qu'on veut voir en utilisant une requête SQL depuis QGIS. Un exemple est souvent parlant par rapport à un discours. Si vous voulez afficher uniquement les polygones des communes, la marche à suivre est la suivante:

  • Se connecter à la base de données spatiale.
  • Sélectionner la couche planet_osm_polygon (ne pas double cliquer).
  • Cliquer sur le bouton "Construire une requête":

    Requête QGis

  • Dans la liste des champs, vous pouvez voir tous les Tags d'OpenStreetMap qui existent. Dans notre cas, nous allons sélectionner uniquement les polygones ayant un tag de limite administrative (boundary).
  • Sélectionner le champ boundary comme sur l'image précédente.
  • Cliquer sur le bouton = pour indiquer qu'on cherche une valeur.
  • Cliquer sur le bouton "echantillon" afin de voir quelles sont les valeurs qui existent pour ce champ.
  • Dans notre cas, il n'y a que deux valeurs: null ou "administrative".
  • Choisir la valeur "administrative".
  • La requête sous QGIS est en fait une simple clause WHERE, ce qui dans notre cas est parfaitement ce que nous voulons: WHERE "boundary" = 'administrative'
  • En cas de problème, il est possible de revenir en arrière en affichant les propriétés de la couche et, à partir de l'onglet "Général", de cliquer sur le bouton "Constructeur de requête".

Pour connaître la signification des Tags, vous pouvez consulter la page du Wiki dédiée: http://wiki.openstreetmap.org/wiki/FR:Map_Features .

Etape 3: Un peu de recherche

Limites communales:

Couche ~ planet_osm_polygon

Clause WHERE ~ "admin_level" = 8

Tag OSM ~ http://wiki.openstreetmap.org/wiki/Key:admin_level#admin_level

En suivant la méthode présentée plus haut, on obtient le résultat suivant:

Limites communales

Comme on peut le voir,la couverture du territoire de la région Pays-de-la-Loire est loin d'être complète en ce qui concerne les limites communales. Le département de la Mayenne est complètement dépourvu. A ce niveau, j'ai l'impression que les polygones de limites communales n'ont pas été rattachés à la bonne région administrative. Ensuite, le Maine-et-Loire est également loin d'être en totalité couvert. En revanche, en Loire-Atlantique, il ne manque qu'une seule commune et la Sarthe comme la Vendée semblent complètes.

Ce premier niveau d'information est très important: en disposant d'un fond de limites communales, on peut réaliser des cartes statistiques simples. C'est pourquoi, une couverture complète des départements est un impératif. Avec cette couche, on peut élaborer des modèles géométriques simplifiés à l'image de ce que l'IGN fait avec les contours GéoFLA(r).

Arrêts de bus

Couche ~ planet_osm_point

Clause WHERE ~ "highway" = 'bus_stop'

Tag OSM ~ http://wiki.openstreetmap.org/wiki/Tag:highway%3Dbus_stop

Bus stop

A première vue, on constate une nette différence avec les villes de Nantes et du Mans comparativement à Angers. Dans le Maine-et-Loire, assez peu d'arrêts de bus sont représentés.

Passage à niveau:

Couche ~ planet_osm_point

Clause WHERE ~ "railway" = 'crossing'

:Tag OSM:

Passages à niveau

On dispose de vraiment peu d'informations sur ce sujet. Peut-être que la donnée sera disponible uniquement quand le réseau routier et de chemin de fer aura été davantage représenté dans OSM. C'est un tag que j'ai pris au pif !

Pistes cyclables

Couche ~ planet_osm_line

Clause WHERE ~ "bicycle" IN ('yes','private') OR "highway" = 'cycleway'

:Tag OSM:

Pistes cyclables Bon, il y a un peu plus de matière mais on est loin du compte. Par exemple, seule une partie de la "Loire à Vélo" est vectorisée. En revanche, on peut remarquer la présence du chemin de halage de la Mayenne.

Radars automatiques

Couche ~ planet_osm_point

Clause WHERE ~ "highway" = 'speed_camera'

:Tag OSM:

Radars automatiques

Encore une fois, l'information est loin d'être exhaustive alors qu'il est peut-être possible de récupérer légalement et librement les emplacements (si l'information est considérée comme publique).

Etape 4: Soyons exhaustifs

Maintenant que nous avons vu quelques exemples, il est important de disposer d'un récaptitulatif complet des données présentes dans notre export par Tag d'OSM et par département.

SELECT DISTINCT count(access) As access,
                  count("addr:flats"),
                  count("addr:housenumber"),
                  count("addr:interpolation"),
                  count(admin_level) As admin_level,
                  count(aerialway),
                  count(aeroway),
                  count(amenity),
                  count(area),
                  count(barrier) As barrier,
                  count(bicycle) As bicycle,
                  count(bridge) As bridge,
                  count(boundary) As boundary,
                  count(building) As building,
                  count(capital) As capital,
                  count(construction),
                  count(cutting),
                  count(disused),
                  count(ele),
                  count(embankment),
                  count(foot),
                  count(highway),
                  count(historic),
                  count(horse),
                  count(junction),
          count(landuse),
                  count(layer),
                  count(learning),
                  count(leisure),
                  count("lock"),
                  count(man_made),
                  count(military),
                  count(motorcar),
                  count("name"),
                  count("natural"),
                  count(oneway),
                  count(poi),
                  count(power),
                  count(power_source),
                  count(place),
                  count(railway),
                  count(ref),
                  count(religion),
                  count(residence),
                  count(route),
                  count(service),
          count(sport),
                  count(tourism),
                  count(tunnel),
                  count(waterway),
                  count(width),
                  count(wood)
  from planet_osm_point;

Conclusion:

Après ce petit tour dans les données d'OSM, on voit qu'on peut faire pas mal de choses avec. On voit également que le niveau d'exhaustivité est à améliorer avec, par exemple, les limites communales qui ne sont pas toujours complètes d'un département à l'autre. OSM dispose d'un vrai potentiel que notre petit exercice vient illustrer. Il donne au citoyen, l'occasion de se rendre compte avec des éléments simples de la réalité du terrain. Cela lui permet de devenir un peu plus acteur de son environnement grâce à l'apport d'une meilleure connaissance du territoire où il vit.

On le voit bien, la crédibilité d'OSM ne se fera que lorsqu'il sera plus complet car pour l'instant, le volume d'information est assez faible et on voit que des disparités grandes sont présentes selon le lieu où l'on se trouve (grandes métropoles urbaines souvent bien fournies au contraire des zones rurales). Maintenant, on comprend mieux pourquoi OSM est surtout orienté sur le "remplissage": tous les outils de base sont faits pour créer de la donnée alors qu'on compte assez peu d'outils qui s'appuient sur cette donnée. En attendant, concrètement, l'accent doit être mis sur les limites communales: c'est le premier effort à porter car il permet de disposer d'éléments de comparaison avec d'autres sources de données.

Posted ven. 27 nov. 2009 10:22:00 Tags: