# Consommer les ressources distantes géospatiales sur data.gouv.fr

Le portail data.gouv.fr référence de nombreuses données OpenData. Certaines sont directement mises à disposition sur le site, d'autres jeux de données référencent des pages tierces avec les jeux de données ou bien un jeu de donnée référence une URL distante.

Nous allons nous concentrer sur le dernier cas en nous concentrant sur une partie spécifique, la donnée géospatiale. Si vous êtes plutôt intéressés par les API, nous documentons déjà l'API Adresse, l'API découpage administratif et les API d'accès aux tuiles vectorielles

# Pourquoi abordons nous spécifiquement ce cas?

Dans un passé pas si lointain, Etalab entretenait le site geo.data.gouv.fr mais la maintenance étant consommatrice de ressources, des choix pour le décommissionner ont été fait. Voir l'article "Extinction de geo.data.gouv.fr" pour en savoir plus

La problématique est que la plateforme permettait de mettre en cache des données géospatiales qui sont normalement mises à disposition sous forme de service web, difficilement accessibles pour les néophytes. Généralement, ces formats ne sont bien compris par des spécialistes dans les données géographiques qu'on désigne sous des termes peu connu comme géomaticiens (métier associé au mot géographie et informatique), spécialiste SIG (Système d'Information Géographique) ou SIGiste. Le but est de rémédier à cette situation en facilitant la compréhension pour mieux réutiliser la donnée.

La plateforme data.gouv.fr avec l'extinction de geo.data.gouv consomme maintenant les données de catalogues contenant des données géospatiales, en particulier le geocatalogue. On parle de métadonnées. Ces dernières contiennent les descriptions des jeux de données et des listes de service.

Ces services peuvent prendre la forme:

  • de service pour afficher des données vecteur et/ou télécharger la donnée sous forme de flux (WFS)
  • de services pour consommer des fichiers directement téléchargeables (Atom)
  • de service pour l'affichage sous forme d'image et l'interrogation ponctuelle (WMS),

# L'intérêt des 3 cas illustrés:

Nous n'insistons pas ici sur les modalités pour faire les opérations mais sur l'intérêt que cela présente

# WFS (Web Feature Service)

Cas 1:

Vous souhaitez disposer de données mises à jour régulièrement. Le WFS est un bon moyen pour cela car il contient les géométries et les attributs des données. Il vous permet d'avoir d'un côté la possibilité de styler comme si vous aviez un fichier SIG local type Shapefile/shp. Ainsi, on peut styler le WFS très facilement comme ci-dessous où on appliqué des motifs et où on a surtout accès aux attributs de la donnée visualisable sous forme tabulaire. url pour l'accès aux données sous forme GML, ouvrable dans le navigateur

Il économise de l'espace disque et/ou de la bande passante car il permet de ne récupérer la donnée que sur une emprise géographique ou des filtres suivant des conditions dans les champs et pas uniquement tout le jeu de données.

Les inconvénients: il peut s'avérer long à afficher car le contenu distant peut s'avérer lourd donc long à récupérer via votre connexion internet. Vous risquez d'avoir un jour le flux qui s'arrête donc plus rien à consommer.

Cas 2:

Vous pouvez aussi récupérer ce WFS et l'avoir sous forme de fichier sur votre machine. Cela évite si la donnée n'est pas mis à jour de la récupérer en permanence et d'avoir la lenteur du réseau qui vous affecte et ne plus dépendre du service si celui-ci disparait ou change (par exemple, ajout/suppression de colonnes ou nouvelle manière de remplir un même champ). Si c'est possible, il souvent recommandé de passer par le flux Atom s'il est disponible.

# Flux Atom

Il s'agit d'un format qui permet de diffuser une liste de flux pour permettre de suivre les mises à jour de données. Il permet aussi de récupérer les données associées à un WFS et/ou un WMS.

Dans le meilleur des cas, on a correspondance entre un flux WMS pour visualiser sous forme image, un WFS pour de la consultation en ligne vecteur ou du téléchargement et un flux Atom pour télécharger. Dans cette configuration, il faut généralement privilégier le flux Atom si on veut les données sur sa machine.

C'est le cas pour les données précédemment montrées en aperçu où on dispose d'un jeu de données Atom.

Dans ce cas précis, vous allez récupérer un ensemble de fichiers qui viennent du logiciel MapInfo car ils contiennent un fichier tab accompagné d'autres fichiers portant le même nom mais avec une autre extension (on parle de format MapInfo Tab) et un XML qui contient les métadonnées du fichier.

# WMS (Web Map Service)

Vous ne souhaitez pas télécharger les données mais les regarder dans votre SIG ou dans votre WebSIG, vous passez par un WMS. Pour illustrer, voici un exemple ci-dessous avec la superposition "Modelisation de l'urbanisation taches urbaines situation en 1980 en Franche Comte" (url de l'image consultable dans le navigateur) sur un fond de plan IGN

# Prérequis:

Il est utile, voire nécessaire d'installer QGIS sur votre machine. Allez sur la page officielle QGIS "Téléchargez QGIS" puis déplier le menu "Téléchargement pour Windows". Un gros bouton vert "Télécharger QGIS 3.28" apparaît . Si vous voulez les dernières fonctionnalités, téléchargez le fichier puis faites du "Suivant Suivant" pour installer QGIS.

Il faut noter la présence d'un texte juste en dessous du gros bouton vert, "En quête de la version la plus stable? Télécharger QGIS 3.22 LTR". Ceux qui prennent cette version cherche un support plus long dans le temps même s'ils ne disposeront de ce fait pas des fonctionnalités récemment introduites. Généralement, ce sont des entreprises, des collectivités qui préfèrent cette option afin de faire une mise à jour moins régulière pour maintenir leurs parcs de machine.

# Consommer le WFS

WFS comme Web Feature Service est un standard créé par l'OGC (comme Open Geospatial Consortium) qui permet de consommer des "features" (objets géographiques), c'est à dire des données vectorielles.

# Le standard WFS

Il existe plusieurs types de requêtes pour interroger un serveur WFS

<?xml version='1.0' encoding="UTF-8" ?>
<schema
   targetNamespace="http://mapserver.gis.umn.edu/mapserver" 
   xmlns:ms="http://mapserver.gis.umn.edu/mapserver" 
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns="http://www.w3.org/2001/XMLSchema"
   xmlns:gml="http://www.opengis.net/gml/3.2"
   elementFormDefault="qualified" version="0.1" >

  <import namespace="http://www.opengis.net/gml/3.2"
          schemaLocation="http://schemas.opengis.net/gml/3.2.1/gml.xsd" />

  <element name="Tache_urbaine_1980_R43" 
           type="ms:Tache_urbaine_1980_R43Type" 
           substitutionGroup="gml:AbstractFeature" />

  <complexType name="Tache_urbaine_1980_R43Type">
    <complexContent>
      <extension base="gml:AbstractFeatureType">
        <sequence>
          <element name="geometry" type="gml:SurfacePropertyType" minOccurs="0" maxOccurs="1"/>
          <element name="Id" minOccurs="0" type="string"/>
          <element name="Annee_tache" minOccurs="0" type="integer"/>
          <element name="Surface_ha" minOccurs="0" type="double"/>
        </sequence>
      </extension>
    </complexContent>
  </complexType>

</schema>

On déduit que la couche Tache_urbaine_1980_R43 dispose des colonnes Id de type string, Annee_tache de type integer et Surface_ha de type double et que la couche dispose d'une géométrie de type polygone.

Il existe une version du WFS dite WFS-T comme Transactionnel. C'est à dire qui permet de la mise à jour de la base de données depuis un service WFS qui permet l'écriture et pas seulement la lecture. On ne détaille pas les opérations liées à ce dernier, étant dans une logique de consommation des données.

# Pour en savoir plus

Voir les documentations suivantes :

# L'écosystème autour du WFS

# Client lourd SIG bureautique QGIS

Pour QGIS, vous pouvez prendre le guide mis à disposition par l'IGN "Utiliser les données IGN en flux WFS". Les instructions sont similaires, la seule chose qui change est l'URL à remplir.

# WFS client léger

Pour l'affichage de carte en WFS,

  • OpenLayers
  • Maplibre GL JS. Démo non fournie car compliquée à gérer. Cela dépend en effet selon si le serveur WFS retourne les données sous forme GeoJSON ou pas, ce qui relève de WFS au cas par cas.
  • Leaflet (Démo dédiée)

# bibliothèques WFS côté serveur

  • Utiliaires de GDAL ogrinfo et ogr2ogr. Pour comprendre leur utilisation, voir le tutoriel pour le WFS de l'IGN. Ce qui change ici est le fait que les URLs changent mais les principes restent les mêmes.
  • owslib (Python)

# Consommer le WMS

# Le standard WMS

Ce standard WMS comme Web Map Service est ancien (1999). Il est comme le WFS, produit par l'OGC. Il est basé sur SOAP. La spécification a 2 versions officielles. Les serveurs généralement supportent 2 versions, la version 1.1.1 et la 1.3.0.

# Les deux principaux types de requêtes

# Les types de requête optionnels

Ils existent des opérations optionnelles qui selon les serveurs sont activées ou non selon ce qui est indiqué dans le bloc <Request> de GetCapabilities

# Pour en savoir plus

Voir les documentations suivantes :

# L'écosystème pour consommer des WMS

# Client lourd SIG bureautique QGIS

Pour QGIS, vous pouvez prendre le guide mis à disposition par l'IGN "Utiliser les données IGN en flux WMS/WMTS". Les instructions sont similaires, la seule chose qui change est l'URL à remplir.

# Client léger web

Pour utiliser les "capabilities" WMS,

JavaScript

Pour l'affichage de carte en WMS (opération GetMap),

Vous avoir un aperçu visuel rapide d'un couche, vous pouvez passer par le projet MViewer comme illustré via cet exemple via un proxy ou ce même exemple via un autre proxy

Warning: Pour le web, il faut généralement utiliser un proxy car tous les serveurs ne supportent pas qu'on accède depuis une page web à leur contenu hébergé sur un autre domaine. Il existe des proxy publics comme https://data.europa.eu/deu-proxy? ou https://corsproxy.io/? mais nous vous recommandons d'installer le vôtre si vous avez un usage en production. Il en existe dans la plupart des languages de programmation. Vous pouvez trouvez une liste sur https://github.com/topics/cors-proxy?o=desc&s=stars (filtrez selon votre language de programmation)

# liste des couches et leur description ou bien une vignette d'une zone sous forme image, pour un aperçu

Python

Avec Owslib

from owslib.wms import WebMapService

wms = WebMapService('https://ogc.geo-ide.developpement-durable.gouv.fr/wxs?map=/opt/data/carto/geoide-catalogue/1.4/org_38154/aea04585-605e-4372-abec-ade0d2380076.internet.map', version='1.3.0')

for operation in wms.operations:
    print(operation.name)
    print(operation.methods)
    print(operation.formatOptions)

for name, content_metadata in wms.items():
    print('crsOptions', content_metadata.crsOptions)
    print('crs_list', content_metadata.crs_list)
    print('dataUrls', content_metadata.dataUrls)
    print('defaulttimeposition', content_metadata.defaulttimeposition)
    print('dimensions', content_metadata.dimensions)
    print('elevations', content_metadata.elevations)
    print('featureListUrls', content_metadata.featureListUrls)
    print('fixedHeight', content_metadata.fixedHeight)
    print('fixedWidth', content_metadata.fixedWidth)
    print('id', content_metadata.id)
    print('index', content_metadata.index)
    print('keywords', content_metadata.keywords)
    print('layers', content_metadata.layers)
    print('max_scale_denominator', content_metadata.max_scale_denominator.text if content_metadata.max_scale_denominator is not None else None)
    print('metadataUrls', content_metadata.metadataUrls)
    print('min_scale_denominator', content_metadata.min_scale_denominator.text if content_metadata.min_scale_denominator is not None else None)
    print('name', content_metadata.name)
    print('noSubsets', content_metadata.noSubsets)
    print('opaque', content_metadata.opaque)
    print('parent', content_metadata.parent)
    print('queryable', content_metadata.queryable)
    print('scaleHint', content_metadata.scaleHint)
    print('styles', content_metadata.styles)
    print('timepositions', content_metadata.timepositions)
    print('title', content_metadata.title)

Pour les autres languages de programmation, il faut vous appuyer sur le parsing XML natif ou fournit par des bibliothèques tierces.

# Manipulation côté serveur

Python

import json
import logging
from urllib.request import urlopen
from urllib.parse import urlparse
from owslib.wms import WebMapService

url_str = "https://demo.data.gouv.fr/fr/datasets/service-de-visualisation-cartographique-wms-du-jeu-de-donnees-driaaf-idf-territoire-maet-en-ile-de-france/"
url_parsed = urlparse(url_str)
slug = [i for i in url_parsed.path.split('/') if i != ''][-1]
base_url = f'{url_parsed.scheme}://{url_parsed.hostname}'
api_url = f'{base_url}/api/1/datasets/{slug}'

with urlopen(f'{api_url}/') as req:
    json_content = json.load(req)

wms_json = [i for i in json_content.get('resources') if 'WMS' in i.get('description') or 'WMS' in i.get('title')]
if len(wms_json) > 0:
    wms = WebMapService(wms_json[0].get('url'), version='1.3.0')
    print(wms.identification.type)
    print(wms.identification.title)
    print(wms.identification.abstract)
    print(wms.getOperationByName('GetMap').formatOptions)
    for name, layer in wms.items():
        # layer = wms.contents[name]
        print("Abstract: ", layer.abstract)
        print("BBox WGS84: ", layer.boundingBoxWGS84)
        print("BBox: ", layer.boundingBox)
        print("CRS: ", layer.crsOptions)
        print("Styles: ", layer.styles)
        print("Timestamps: ", layer.timepositions)
        print(layer.parent.abstract)
        sizex = 800
        # Ne fonctionne pas. Bug côté Geo-IDE sur le décodage de caractères
        # https://github.com/geopython/OWSLib/issues/846
        # Marche avec owslib 0.25.0 mais pas après
        response = wms.getmap(layers=[name,],
            bbox=layer.boundingBoxWGS84, # Left, bottom, right, top
            format=wms.getOperationByName('GetMap').formatOptions[0],
            size=(sizex,round(sizex * ((layer.boundingBoxWGS84[3] - layer.boundingBoxWGS84[1]) / (layer.boundingBoxWGS84[2] - layer.boundingBoxWGS84[0])))),
            srs='EPSG:4326',
        )
        with open(f"{name}.{wms.getOperationByName('GetMap').formatOptions[0].split('/')[-1]}", 'wb') as out:
            out.write(response.read())
else:
    print("Pas de WMS disponible")

from owslib.wms import WebMapService

wms = WebMapService('https://ogc.geo-ide.developpement-durable.gouv.fr/wxs?map=/opt/data/carto/geoide-catalogue/1.4/org_38154/aea04585-605e-4372-abec-ade0d2380076.internet.map', version='1.3.0')

response = wms.getmap(layers=['N_PERIM_MAET_ZINF_S_R11',],
    bbox=(1.44041, 48.1107, 3.56583, 49.2484),
    format='image/png',
    size=(800, 428),
    srs='EPSG:4326',
)
with open(f"N_PERIM_MAET_ZINF_S_R11.png", 'wb') as out:
    out.write(response.read())

# ATOM = WFS sans la complication

Le plus simple: assimilable à des fichiers SIG + autres données (données attributaires + doc PDF +...)

# Investigation:

Voir ce qu'il est possible d'améliorer en ligne

Retours après relecture

Guide: consommer les données géographiques sous tous leurs formats

  • WFS/WMS (palliatif disparition geo.data.gouv)
  • les autres formats usuels et leur exploitation: reprise mais avec quelques cas sur des jeux de données hébergés

http://opengeospatial.github.io/e-learning/wfs/text/operations.html

# Voir ultérieurement ce qu'on exploite de ce contenu

Partage

https://dds2010.github.io/mviewer/?x=706890&y=6242153&z=7&l=epci%2CAGENDA21_S_R44*&lb=positron&config=demo/addlayers.xml&mode=d

https://dds2010.github.io/mviewer/?x=439666&y=6394416&z=7&config=demo/addlayers.xml&addLayer=%7B%5C%22url%5C%22:%5C%22https://www.geo2france.fr/geoserver/hdf_common/ows%5C%22,%5C%22name%5C%22:%5C%22Antennes__HdF_EnService_Agreg%5C%22,%5C%22title%5C%22:%5C%22Antennes_test%5C%22%7D

https://corsproxy.io/?https://ogc.geo-ide.developpement-durable.gouv.fr/wxs?map=/opt/data/carto/geoide-catalogue/1.4/org_5443264/ccf16ee8-5b97-4cf5-9257-c88102c106e2.internet.map&service=WMS&cersion=1.3.0&request=GetCapabilities

https://corsproxy.io/?https://ogc.geo-ide.developpement-durable.gouv.fr/wxs?map=/opt/data/carto/geoide-catalogue/1.4/org_5443264/ccf16ee8-5b97-4cf5-9257-c88102c106e2.internet.map

https://ogc.geo-ide.developpement-durable.gouv.fr/wxs?map=/opt/data/carto/geoide-catalogue/1.4/org_38066/9a623f0c-bd2e-498e-b67b-2b363a5d6e0d.internet.map&service=WFS&request=GetCapabilities

https://ogc.geo-ide.developpement-durable.gouv.fr/wxs?map=/opt/data/carto/geoide-catalogue/1.4/org_38066/025777cb-1837-4898-bafc-71d60c44d7eb.internet.map&service=WFS&typeNames=ms:N_INT1_GENERATEUR_SUP_S_062&request=DescribeFeatureType&version=2.0.0

https://ogc.geo-ide.developpement-durable.gouv.fr/wxs?map=/opt/data/carto/geoide-catalogue/1.4/org_38066/025777cb-1837-4898-bafc-71d60c44d7eb.internet.map&service=WFS&VERSION=2.0.0&typeNames=ms:N_INT1_GENERATEUR_SUP_S_062&MaxFeatures=1&request=getfeature

https://jsonformatter.org/xml-formatter/?url=https%3A%2F%2Fogc.geo-ide.developpement-durable.gouv.fr%2Fwxs%3Fmap%3D%2Fopt%2Fdata%2Fcarto%2Fgeoide-catalogue%2F1.4%2Forg_38066%2F9a623f0c-bd2e-498e-b67b-2b363a5d6e0d.internet.map%26service%3DWFS%26request%3DGetCapabilities

curl -X 'GET'
'https://demo.data.gouv.fr/api/1/datasets/service-de-visualisation-cartographique-wms-du-jeu-de-donnees-driaaf-idf-territoire-maet-en-ile-de-france/'
-H 'accept: application/json'

var url_str = 'https://demo.data.gouv.fr/fr/datasets/service-de-visualisation-cartographique-wms-du-jeu-de-donnees-driaaf-idf-territoire-maet-en-ile-de-france/';

var url = new URL(url_str);
var baseUrl = url.origin;
var slug = url.pathname.split('/').filter(el => el != '').slice(-1)[0]
var api_url = `${baseUrl}/api/1/datasets/${slug}`
console.log(api_url)

fetch(api_url)
.then(resp => resp.json())
.then(json => {
  console.log(json);
  var wms = json.resources.filter(el => el.description.includes('WMS') || el.title.includes('WMS'))
  if (wms[0]) {
    wms[0].url
  }
}).catch(function (err) {
  // There was an error
  console.warn('Something went wrong.', err);
});

Ministère de la Transition écologique, Pôle national de données de Biodiversité, DREAL, DRAAF, DRIEE, CEREMA, DDT, DDTM, DEAL