Afficher les données de Paris OpenData avec polymaps

En ouvrant l'accès à un catalogue de données diverses (Équipements, bâti, arbres d'alignement, arrêtés municipaux, ...) l'initiative ParisData, l'Open Data de la capitale, nous donne l'occasion de manipuler des données georéférencées. Notre objectif ici sera de les publier sur une page Web grâce à un outil simple et léger : polymaps.

Transformation

Le système de projection utilisé pour certaines données du catalogue est la Lambert Conformal Conic (NTF, EPSG 9802)

Dans la mesure où nous voulons déployer quelquechose de très simple, nous n'avons pas l'intention de sortir la grosse artillerie habituelle (Serveur WMS, Mapserver, QGIS MapServer, ...), nous allons plutôt utiliser un fichier GeoJSON, en longitudes/latitudes WGS84 (EPSG:4326).

Pour cela, la bibliothèque GDAL nous offre tous les outils adéquates:

Pour notre exemple, nous avons choisi les emplacements des points de collecte de verre. Parmis les champs fournis, nous choisissons de ne conserver que leur état (Lb_Etat_E) et le nom de leur emplacement (Emplacemnt).

Comme python est notre language préféré, et que c'est toujours un plaisir de le montrer en action, voici la petite procédure qui fait tout ça :

# python gdal
from osgeo import ogr
from osgeo import osr
...
...
# Ouvrir le répertoire contenant les shape
source = ogr.Open(INPUT_FOLDER)

# La projection de sortie
spatialRef = osr.SpatialReference()
spatialRef.ImportFromEPSG(4326)

# Le fichier de sortie
driver = ogr.GetDriverByName('GeoJSON')
shape = driver.CreateDataSource(OUTPUT_FILE)

# Parcourir les couches
for layer in source:
    # Reprojection originale -> destination
    originalSpatialRef = layer.GetSpatialRef()
    coordTransform = osr.CoordinateTransformation(originalSpatialRef,
                                                  spatialRef)
    # Choix des champs des données
    properties = ogr.FeatureDefn()
    properties.AddFieldDefn(ogr.FieldDefn('Etat'))
    properties.AddFieldDefn(ogr.FieldDefn('Emplacement'))

    # Créer la nouvelle couche GeoJSON
    newLayer = shape.CreateLayer(layer.GetName(), spatialRef)

    # Parcourir les features
    for feature in layer:
        # Créer la nouvelle feature
        newFeature = ogr.Feature(properties)
        # Remplir les champs choisis
        newFeature.SetField('Etat', feature.GetField('Lb_Etat_E'))
        newFeature.SetField('Emplacement', feature.GetField('Emplacemnt'))
        # Reprojetter la feature
        geometry = feature.GetGeometryRef()
        geometry.Transform(coordTransform)
        # Sauvegarder
        newFeature.SetGeometry(geometry)
        newLayer.CreateFeature(newFeature)
        newFeature.Destroy()

Nous obtenons en sortie un fichier GeoJSON avec les points en lat / long et les données 'Etat' et 'Emplacement'.

...
{ "type": "Feature", "properties": { "Etat": "Actif", "Emplacement": "37 CHATEAU D'EAU ANGLE BOUCHARDON" }, "geometry": { "type": "Point", "coordinates": [ 2.358920, 48.871154 ] } },
{ "type": "Feature", "properties": { "Etat": "Actif", "Emplacement": "13 place de la Nation" }, "geometry": { "type": "Point", "coordinates": [ 2.398154, 48.848723 ] } },
...

Le fichier pèse 174Ko, mais lorsqu'Apache le servira il pèsera 20Ko (grâce à la compression gzip !)

Affichage

Nous choisissons d'afficher ces données dans une page avec polymaps. Il s'agit d'un composant Javascript permettant de créer des cartes interactives.

Les critères de comparaison avec OpenLayers (OL) sont:

Cependant, la couverture fonctionnelle n'est absolument pas comparable. Mais pour afficher une carte avec des points, c'est largement suffisant !

On commence par un fond de carte: Cloudmade, dont les tuiles sont dessinées à partir d'OpenStreetMap:

map.add(po.image()
        .url(po.url("http://{S}tile.cloudmade.com"
                  + "/1a1b06b230af4efdbb989ea99e9841af"
                  + "/998/256/{Z}/{X}/{Y}.png")
        .hosts(["a.", "b.", "c.", ""])));

On ajoute ensuite nos données GeoJSON:

map.add(po.geoJson()
        .url('collecteurs.json')

Polymaps facilite la personnalisation du dessin en fonction des données. Ici, nous affichons en vert les collecteurs à l'état "Actif" et en rouge les autres. De même nous mettons leur "Emplacement" en tooltip (svg:title, Firefox 4, Chrome, Opera 11).

map.add(po.geoJson()
        .url('collecteurs.json')
        .on("load", po.stylist()
                      .attr('fill',
                            function(d) {
                                 return d.properties.Etat == 'Actif' ?
                                        'green' : 'red';
                            }))
                      .title(function(d) {
                                 return d.properties.Emplacement
                            }));

Accéder à la page de démonstration

Conclusion

Finalement, l'étape la plus compliquée était de reprojetter les données. On regrettera donc que l'initiative ParisData les ait publié sous cette forme exotique.

Comme le soulignait David : Publieurs de données, concentrez vous sur la qualité, pas la taille, les développeurs vous remercieront !

À noter également que nous avons choisi une approche privilégiant la légèreté. Or, plusieurs sources de données de ParisData sont volumineuses et ne pourraient pas être affichées en GeoJSON sans mettre à genoux le navigateur. Nous serions alors contraints de servir les données sous forme de tuiles...

#python, #polymaps, #gis - Posted in the Dev category