D’une donnée brute à une donnée enrichie

Posted on

Cet article va tenter de décrire mes étapes pour exploiter certaines données géographiques mises à disposition par Keolis Rennes et le Service d’Information Géographique (SIG) de Rennes métropole.

Le pitch

Mon besoin était de m’appuyer sur l’empreinte du réseau de transports de bus dans la métropole pour déterminer le tracé précis entre deux arrêts de bus consécutifs sur une ligne donnée, et d’en calculer la longeur.

Un peu de naïveté ne fait pas de mal

Ma première idée fut de me tourner vers le portail de Keolis. En effet, il me semblait naturel d’y trouver les données des itinéraires même si je ne m’attendais pas à ce qu’elles soient publiées via leur API. Sur ce point, j’avais raison, l’API ne s’intéresse qu’aux données de l’état du réseau.

Keolis propose aussi quelques jeux de données statiques téléchargeables directement. Malheureusement, hormis les données graphiques des pictogrammes des lignes, Keolis ne publie que le GTFS qui représente les informations de transits, mais pas les données géographiques.

La première étape fit donc choux blanc.

Bon sang, mais c’est bien sûr !

Puisque Keolis ne fournissait pas les données dont j’avais besoin, je me suis tourné vers le grand service libre de données géographiques : OpenStreetMap. En effet, OSM est très actif et il me semblait probable d’y trouver ce que je cherchais.

J’atterris donc rapidement sur le wiki d’OSM listant les jeux couvrants le réseau de transport en commun sur la métropole. Mais là trois obstacles se dressèrent devant moi :

  • L’ensemble du réseau n’est pas couvert
  • Certains itinéraires sont incomplets
  • Les données sont moins directement exploitables que je n’aurais espérer

En revanche, un des grands intérêts d’OSM est qu’il est mis à jour régulièrement, même lorsque des travaux prennent place durablement, modifiant le tracé d’une ligne de bus.

Le problème des itinéraires incomplets pourrait se résoudre simplement en éditant OSM. Malheureusement, même si cette tâche est désormais facilitée depuis un simple navigateur grâce aux outils d’OSM, ils ne peuvent pas résoudre des cas plus compliqués tels que celui illustré ci-dessous :

osm_ligne67

Voir directement la source

 

Si vous le notez bien, la ligne 67 quitte la voie centrale pour rejoindre l’avenue Maginot, avant de tourner au nord par le pont de Strasbourg. Or, le tracé est interrompu le long de cette avenue, la ligne 67 ne la parcourant qu’en partie. Les outils de bases d’OSM ne permettent pas de choisir un segment me semble-t-il. Techniquement, c’est dû au fait que l’entité qui représente l’avenue Maginot est considérée comme une ligne continue. D’ailleurs, on remarque aussi que la ligne 67 semble venir d’abord de l’avenue Maginot, mais ce n’est pas le cas. En fait, la sorte de V à l’envers est aussi un segment d’un seul tenant et l’éditeur qui l’a sélectionné n’a pas pu faire autrement que de le prendre entièrement, même sa section ouest qui n’est pas utilisé en réalité par la ligne 67.

Mes compétences en édition OSM sont trop limitées pour savoir si il est possible de créer le lien manquant. J’ai tenté ma chance avec l’éditeur avancé JOSM mais sans succès.

D’autre part, le format d’export des données est bien particulier. Il définit essentiellement un graphe de noeuds et de relations entre ces noeuds. Je dois admettre n’avoir pas poussé mes recherches pour en tirer les informations sous une forme qui me semblait utilisable pour mes besoins.

Le SIG à la rescousse

Le SIG de Rennes métropole est un service prolifique puisqu’il publie à lui seul près de 30% des données ouvertes proposées sur le portail. Au sein de cette forêt de jeux de données, j’ai pu trouver celui qui me semblait être précisément ce dont j’avais besoin : “Données géographiques du réseau STAR“.

Ce lot données contient les couches géographiques (géodonnées) décrivant le réseau de transport en commun de Rennes Métropole.

Le lot de données contient :
– les itinéraires des lignes principales
– les arrêts physiques
– les arrêts logiques
– la correspondance entre les arrêts physiques et les itinéraires de ligne (fichier CSV)

Les arrêts physiques sont des points à la localisation des arrêts de bus sur les trottoirs. Les arrêts logiques sont des points sur les lignes et représentants les arrêts physiques de la ligne dans les deux sens. Une image vaut mieux qu’un long discours :

Vert: lignes, orange : arrêts logiques, bleus : arrêts physiques

Vert: lignes, orange : arrêts logiques, bleus : arrêts physiques

Les arrêts logiques sont décrits comme étant positionnés sur la ligne. Il me semblait donc évident que la combinaison “lignes + arrêts logiques” allaient enfin répondre à mes besoins. En effet, mon objectif initial était de pouvoir couper les lignes en segments dont les extrémités seraient deux arrêts logiques sur cette ligne.

Sauf que tout n’est jamais si simple…

Ma première action fût de choisir les données au format shapefile. Ce format contient les données géographiques et peut aisément se charger dans la base de données spatiales PostGIS via les outils fournis :

Cette commande a crée une table “star_arret_physique” dans ma base de données spatiales “rennes_sig”. Voici la définition de cette table :

Pour les données d’itinéraires :

Qui produit la description suivante :

Il suffit d’exécuter la même commande sur les données de lignes et on se retrouve alors avec une base de données prêtes à être exploitée. Enfin presque. Si vous regardez bien la déclaration des deux tables, il n’existe pas de clés communes entre elles. La table des arrêts logiques n’offre aucune relation directe avec les itinéraires. Il faut en fait utiliser une table pivot constituée depuis un simple fichier CSV : star_ap_iti. Ce fichier CSV relie les arrêts physiques aux itinéraires.

L’import se passe différement. D’abord créez une table pour recevoir les données :

Puis copiez les données depuis un shell psql :

Maintenant que les données sont dans la base, nous pouvons effectuer les requêtes pour lier les arrêts logiques aux lignes.

L’idée est simple, nous parcourons la table des arrêts physiques pour obtenir les arrêts logiques associés. Puis nous procédons à une jointure avec la table créée précédemment en utilisant le code de l’arrêt physique comme pivot. Finalement, nous ordonnançons les résultats par itinéraire et position de l’arrêt sur cet itinéraire. Ci-dessous un petit extrait des données que nous obtenons :

A ce moment là, je dois avouer, je voulais crier victoire. En effet, il me semblait que j’avais enfin le lien entre les arrêts, les itinéraires la géolocalisation des arrêts et, cerise sur le gâteau, l’ordonnancement des arrêts.

Sauf que tout n’est jamais si simple (bis)…

J’ai en effet rapidement été confronté à un problème. Prenons un exemple simple, la ligne C4 et l’arrêt (logique) Pont de Strasbourg :

line4_zoom1

A une échelle assez grande, on se dit que l’arrêt est effectivement sur la ligne. Mais en zoomant, on se rend compte que non :

line4_zoom16

Cela pose une difficulté, puisque pour calculer la distance entre deux arrêts le long d’une ligne, les outils proposés par PostGIS nécessitent que les points soient contenus par la ligne. Du coup, il est impossible d’appliquer une requête simple.

La solution est de projetter le point représentant l’arrêt sur l’itinéraire via la fonction ST_ClosestPoint, et en reprenant la requête ci-dessus :

La table résultante est l’ensemble des points projetés sur les lignes du réseau.

Une fois cette étape atteinte, il suffit de dérouler l’algorithme pour découper chaque ligne par couple de points et mesurer la longueur du segment. Cela parait simple mais, une fois traduit en SQL, c’est beaucoup moins amusant à lire :

J’avais prévenu, c’est assez hideux mais ça fait le job. Enfin presque…

Sauf que tout n’est jamais si simple (ter)…

Lorsque l’on exécute cette requête, on obtient l’erreur suivante :

En effet, les lignes fournies dans le shapefile par le SIG de Rennes métropole sont en fait des multi-lignes. La plupart peuvent être combinées en lignes continues, mais pas toutes. Or, PostGIS ne sait traiter, dans certaines de ces fonctions, que des lignes continues.

J’aurais pu essayer de charger les données initialement ainsi :

Notez le -S dans la ligne de commande. Mais on obtient alors une erreur confirmant que certaines lignes ne peuvent pas être considérées comme continues :

Un exemple de représentation sur l’itinéraire 6 :

multilines

 

La seule solution que j’ai trouvé est de filtrer les itinéraires que je ne peux pas  combiner en des lignes continues afin de ne pas les traiter du tout. Pour ce faire, il faut modifier la requête géante comme suit :

Notez la présence des appels à la fonction ST_LineMerge qui combine une géométrie à plusieurs lignes en une seule. Malheureusement, cette fonction ne peut pas faire de miracle sur des cas comme celui de la ligne 6.

Et voilà ! J’avais enfin une table décrivant les segments des itinéraires entre chaque arrêts les parcourant. Pfiou !

Conclusion

L’objectif de cet article est de montrer qu’une donnée brute est parfois difficile à utiliser, principalement dans le cadre d’une automatisation de son traitement. Mais l’intérêt réside aussi pour moi dans la réflexion que cela provoque. C’est comme un casse-tête géant.

Malgré cela, je dois admettre que je ne m’attendais pas à autant de complication pour un besoin qui me paraissait plutôt simple. Je ne critique pas la donnée disponible, en revanche il me semble important de voir à quel point ces écueils peuvent ralentir, voir même bloquer l’innovation qui est souvent espérée des données publiques.

Je ne suis pas certain que les agents publics doivent porter la responsabilité de fournir une donnée enrichie comme il en résulterait de mon travail ci-dessus. A mon sens, cela les ferait sortir du cadre de l’opendata. En revanche, cela laisse une porte grande ouverte à celles et ceux qui souhaiteraient se positionner sur l’aggrégation et l’enrichissement des données brutes (comme le font l’IGN ou DataPublica d’une certaine façon).

 

Remerciements

Le SIG de Rennes métropole évidemment qui a toujours été à l’écoute de mes plaintes.


Laisser un commentaire

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

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">