Il y quelques années, Howard Butler, Martin Daly, Allan Doyle, Sean Gillies, Tim Schaub et Christopher Schmidt (quelques grands noms de la planète géomatique OpenSource) se sont mis en tête de créer le format le plus simple possible pour représenter et échanger les données géospatiales (géométries et attributs), avec en vue, les services WEB.
Leur choix s'est tout de suite porté vers le format JSON (de préférence au format XML) et ainsi est né GeoJSON dont la première mouture a été publiée en 2008 en une page: The GeoJSON Format Specification.
- le format prend en charge toutes les géométries de l'OGC (tag "geometry"):
- {"type": "Point", "coordinates": [50.0, 70.0]}
- {"type": "LineString","coordinates": [[50.0, 70.0], [80.0, 40.0]]}
- {type": "Polygon","coordinates": [[[50.0, 70.0], [80.0, 40.0], [20.0, 10.0], [30.0, 60.0], [50.0, 70.0]]]}
- plus les MultiPoints, les MultiLineString, les MultiPolygon, ..., et les géométries 3D.
- il prend aussi en charge les attributs qui peuvent être de plusieurs types (tag "properties"):
- {"prop0": "valeur0"}
- {"prop1": {"moi": "lui"}}
- ensuite tout est assemblé suivant le principe d'une collection d'objets (tag "type"= "FeatureCollection" comprenant plusieurs features):
- { "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {"type": "Point", "coordinates": [50.0, 70.0]},
"properties": {"prop0": "valeur0", "prop1": "valeur1", ...,"propn": "valeurn"}
]},
{ "type": "Feature",
"geometry": "type": "Point", "coordinates": [80.0, 40.0],
...
]}
- { "type": "FeatureCollection",
- à l'inverse des fichiers shapefiles ou des bases de données géospatiales, plusieurs types de géométries peuvent coexister dans une FeatureCollection:
- { "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {"type": "Point", "coordinates": [50.0, 70.0]},
"properties": {"prop0": "valeur0"}
},
{ "type": "Feature",
"geometry": {"type": LineString","coordinates": [[50.0, 70.0], [80.0, 40.0]]}
"properties": {"prop0": "valeur3","prop1": "valeur4"}
},
{ "type": "Feature",
"geometry": {type": "Polygon","coordinates": [[[50.0, 70.0], [80.0, 40.0], [20.0, 10.0], [30.0, 60.0], [50.0, 70.0]]]},
"properties": {"prop0": "valeurn","prop1": {"moi": "lui"}
},
....
]}
- { "type": "FeatureCollection",
- peuvent aussi y figurer le système de projection, de diverses manières (tag "crs"), et un cadre (Bounding box, tag "bbox")
- { "type": "FeatureCollection",
"bbox": [100.0, 0.0, 105.0, 1.0],
"features": [...]}
- { "type": "FeatureCollection",
Réactions
- Trop simple, trop lourd, enfantin, pas sérieux, ridicule, faux,..., ont affirmé certains (voir, entre autres, les réactions sur la liste QGIS-Developer à la proposition de kimaidou Get rid of Shapefiles ! Go GeoJSON ! ), mais générique, facile à lire et à écrire quelque soit le langage de programmation, sérialisable, portable, et autodéfini;
- Paradoxalement, son succès a été très rapide. En peu de temps, il a été adopté par Google, Bings Map, Yahoo Maps, OpenLayers, Leaflet, CartoDB, D3js, App coverage d'Apple (JavaScript), GitHub, GeoServer (serveur cartographique) ou GeoDjango (serveur cartographique Python), Safe Sofware FME, de multiples librairies Python (voir plus bas) et les bases de données NoSQL comme MongoDB ou CouchDB qui utilisaient déjà le format JSON (voir Le NoSQL dans le domaine géospatial : MongoDB avec JavaScript ou Python, ArcGIS et Quantum Gis et Le NoSQL dans le domaine géospatial : CouchDB et GeoCouch (Couchbase), shp2geocouh, importation de shapefiles et serveur cartographique).
- De plus, grâce à GDAL/OGR, Quantum GIS, PostGIS ou SpatiaLite peuvent lire ou écrire des couches GeoJSON;
- Toutes les autres implémentations du format sont reprises dans GeoJSON users (Java, Ruby, php, etc.)
Pourquoi ?
- Essentiellement du fait de sa simplicité pour la représentation (simple fichier texte) et le transfert de données (format JSON, adapté à Internet), bien qu'il ne soit pas certifié ISO19107 (OGC) comme le souligne ironiquement Sean Gillies dans GeoJSON is Spectacularly Wrong,Yet Somehow Right Enough.
Avec JavaScript:
Quelques exemples simples illustreront son intérêt:
- Edit GeoJSON de Tom MacWright: dessinez sur la carte et récupérez les données;
- GeoJSONLint composer ou coller, validez et visualisez vos couches GeoJSON en «live»;
- Wikigeo vous permet de chercher les articles de Wikipedia qui fournissent des coordonnées géographiques;
- uMap qui permet de créer des cartes personnalisées à partir d'OpenSteetMap, soit en les dessinant, soit en les important (GeoJSON) (voir exemple à partir d'une couche géologique introduite dans ce format à GeoJSON import);
- et maintenant GitHub, placez un fichier texte au format GeoJSON dans un de vos «repository» et il apparait directement sur un fond OpenStreetMap (voir mon exemple à exemple de fichier GeoJSON) ;
- même plus, vous pouvez récupérer cette couche dans QGIS (voir: GeoJSON on GitHub: Now What?)
Sans parler des très nombreux exemples sur Internet:
- avec OpenLayers (GeoJSON example );
- avec Leaflet:( Using GeoJSON with Leaflet);
- avec Google Maps (Importing Data ou Mapping earthquakes with the Google Maps API);
- et bien d'autres....
Avec Python (GeoJSON et __geo_interface__):
Si l'on regarde la structure du format JSON, il est facile de constater qu'elle correspond à un dictionnaire Python (dict= {}) qui peut être manipulé en tant que tel. Rien d'étonnant à ce que le format ait été adopté par la plupart des modules géospatiaux:
- geojson
- Shapely
- Fiona
- descartes
- pygeoif, version simplifiée de Shapely
- PySAL
- ArcPy
- PyShp, version adaptée par Christian Lederman
- osgeo.ogr: osgeo.ogr.Feature.ExportToJson()
- PyQGIS avec le nouvel API de la version 1.9/2.0: geom.exportToGeoJSON()
Mais, pour la plupart, cela ne concerne encore que le tag "geometry" et pas les autres. C'est pourquoi Sean Gillies a proposé le __geo_interface__ (GeoJSON-like protocol for geo-spatial (GIS) vector data) qu'il a implémenté dans Fiona (lecture et écriture, voir Python: traitement des couches vectorielles dans une perspective géologique, lecture et enregistrement des couches sous forme de dictionnaires avec le module Fiona) et dans Shapely (implémentés ensuite dans PySAL, pygeoif, PyShp et ogr):
import fiona
f = fiona.open('point.shp')
f.next()
{'geometry': {'type': 'Point', 'coordinates': (161821.09375, 79076.0703125)}, 'id': '0', 'properties': {u'DIP_DIR': 120, u'STRATI_TYP': 1, u'DIP': 30}}
f.next()['geometry']['coordinates']
(161485.09375, 79272.34375)
f.next()['properties']['DIP']
55
qui peut maintenant être parfaitement adapté au module PyShp (voir PyShp as Fiona (with the GeoJSON-like protocol))::
import shapefile
def records(fichier):
# génerateur
reader = shapefile.Reader(fichier)
fields = reader.fields[1:]
field_names = [field[0] for field in fields]
for sr in reader.shapeRecords():
geom = sr.shape.__geo_interface__
atr = dict(zip(field_names, sr.record))
yield dict(geometry=geom,properties=atr)
a = records('point.shp')
a.next()
{'geometry': {'type': 'Point', 'coordinates': (161821.09375, 79076.0703125)}, 'properties': {'DIP_DIR': 120, 'STRATI_TYP': 1, 'DIP': 30}}
a.next()['geometry']['coordinates']
(161485.09375, 79272.34375)
a.next()['properties']['DIP']
55
et au nouvel API de PyQGIS:
layer = qgis.utils.iface.activeLayer()
def records(layer):
fields = layer.pendingFields()
field_names = [field.name() for field in fields]
for elem in layer.getFeatures():
geom= elem.geometry()
atr = dict(zip(field_names, elem.attributes()))
yield dict(geometry=geom.exportToGeoJSON(),properties=atr)
c = records(layer)
c.next()
{'geometry': u'{ "type": "LineString", "coordinates": [ [164917.66073716, 115230.16694565], [170806.15565476, 116401.17445767] ] }', 'properties': {u'id': 1,u'test':u'ligne'}}
et ogr avec .ExportToJson()...
Une simple boucle pour obtenir la représentation GeoJSON complète d'une couche, un copier-coller dans les exemples en JavaScript présentés et l'affaire est réglée...
Problèmes et solutions présentées (TopoJSON)
Indépendamment des réactions déjà soulignées, très vives par moments, le principal problème est, vous vous en doutez, la taille des fichiers textes résultants. Diverses solutions ont été proposées, (comme How to minify GeoJSON files?), mais la plus convaincante est le format TopoJSON de Mike Bostock, extension de GeoJSON qui se base sur les relations topologiques de ESRI ArcInfo (un seul arc pour la limite commune entre 2 polygones, par exemple). Le gain de taille est significatif (environ 80%) mais le format est récent et donc encore relativement peu utilisé. Tout ce que l'on peut dire est que la boucle est bouclée, de ArcInfo aux shapefiles et.... retour.
Conclusions
"A remarkably simple feature, which i think significantly disrupts the traditional geospatial market" est un avis parmi d'autres sur le format GeoJSON (feomike.github.io/post/thoughts-on-disruption.htm). D'autres sont beaucoup plus négatifs, notamment les « professionnels » des SIGs et des SGBD pour qui c'est trop « simple ». C'est vrai, pas besoin de serveur cartographique, de REST ou de SOAP, de ..., un simple fichier texte et du JavaScript suffisent.
C'est en effet bien Internet et la cartographie en ligne qui ont assuré le succès inespéré du format et les utilitaires de conversion abondent, payants ou non: de KML vers GeoJSON (et vice-versa) et de (ce que vous voulez) vers GeoJSON alors qu'avec ogr2ogr:
ogr2ogr -f "GeoJSON" -lco votre.geojson votre.shp
Son adoption récente par ESRI dans ArcPy (à ne pas confondre avec l' ESRI Json de l'API REST) lui apportera sans doute une certaine reconnaissance « officielle »:
import arcpy
geojson_point = {"type": "Point", "coordinates": [50.0, 75.0]}
point = arcpy.AsShape(geojson_point)
petit emprunt à Shapely...
from shapely.geometry import shape
geojson_point = {"type": "Point", "coordinates": [50.0, 75.0]}
point = shape(geojson_point)
print point
POINT (50.00 75.00)
Mais il faut garder en mémoire son objectif: pas de styles ou d'autres fioritures ici, ce n'est qu'un format d'échange qui se veut universel, comme l'est le format WKT, mais bien plus complet et plus souple à utiliser.
GeoJSON is not Lat, Lng
To match OGR
To match KML
It surprises the naive
It annoys the expert
It is what it is
The Web loves JSON because it is
minimal, portable, textual
self-describing
a subset of JavaScript
(and other languages with Map literals)
The Little Format that Could
GeoJSON gets many things right
It gets some things wrong
Requirements, opinions, and tastes differ
GeoJSON is flexible and evolvable
It's been a valuable experiment in standards making
Les gens de chez Safe Software (FME) ne se sont pas trompés en résumant la situation dans Spatial Data Formats: ‘Esperanto’ vs ‘Lingua Franca’ et en adoptant dès le début le format (d'où le titre de l'article).
Site officiel : Le NoSQL dans le domaine géospatial : MongoDB avec JavaScript ou Python, ArcGIS et Quantum Gis
Site officiel : Le NoSQL dans le domaine géospatial : CouchDB et GeoCouch (Couchbase), shp2geocouh, importation de shapefiles et serveur cartographique
Site officiel : Python: traitement des couches vectorielles dans une perspective géologique, lecture et enregistrement des couches sous forme de dictionnaires avec le module Fiona
licence Creative Commons Paternité-Pas d'Utilisation Commerciale-Partage des Conditions Initiales à l'Identique Commerciale 2.0 France
Commentaires
Et maintenant ?
5 ans et demi après cet article, alors que QGIS 3 et son utilisation par défaut du format GeoPackage gpkg vont sans doute propulser en avant le gpkg, soutenu en outre par l'OGC, mais passablement "boite noire" à mon humble avis, j'aimerais beaucoup avoir l'actualisation des informations et opinions de Martin Laloux (et Marc Léobet aussi !) exprimées ci-dessus.
Comme programmeur, je trouve commode d'accéder directement à un bas niveau de représentation de la donnée, et donc j'ai toujours tendance à préférer un format texte.
Ayant débuté dans les SIG par la lecture de 'Understanding GIS with PC Arc/Info', et ayant de ce fait le modèle topologique gravé dans la tête, j'aimerais aussi un développement plus long sur TopoJSON, car vos articles sont toujours particulièrement éclairants.
Le problème c'est que c'est
Le problème c'est que c'est un combat d'arrière garde (SOAP XML vs REST JSON JavaScript):
de OGC Abandons the Web
GeoJSON & INSPIRE
En direct de la Conference INSPIRE 2013 : l'article tombe à point nommé dans un environnement mouvant, où le lien entre INSPIRE (l'IG pure et dure) et Open Data (la donnée à la pelle mais souvent en vrac) est omniprésent. Au moment où le Royaume-Uni et la Commission européenne pose la question du recours au W3C pour produire des widgets et des apps. La question du recours à GeoJSON a même été posée dans le groupe chargé spécifiquement des services en réseau sur le thème : "qu'en fait-on". Pas de réponse à ce jour, mais à titre personnel, je pense que l'on va vers des widgets et des apps alimentés, par en-dessous, par des services OGC.
Cordialement
Poster un nouveau commentaire