Skip to content

Instantly share code, notes, and snippets.

@ThomasG77
Last active August 29, 2015 14:12
Show Gist options
  • Save ThomasG77/6b0525707674b1bbb343 to your computer and use it in GitHub Desktop.
Save ThomasG77/6b0525707674b1bbb343 to your computer and use it in GitHub Desktop.
Notebook avec fichiers en entrée pour géocoder avec le géocodeur IGN France
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
# coding: utf-8
# Nous avons pour le moment ignoré le support des codes EPSG. Il est en effet possible de retourner les coordonnées transformées en coordonnées locales (EPSG 2154, ...) mais comme les objets retournés par Geopy lors du géocodage contiennent une référence à latitude, longitude, cela ne nous paraissait pas très pertinent pour rester générique. Ce support pourra toujours être ajouté ultérieurement.
#
# Nous avons rencontrés quelques cas qui ne semblent pas fonctionner ou bien nous avons loupé des informations dans la documentation officielle http://api.ign.fr/tech-docs-js/fr/developpeur/search.html
#
# ## Enregistrez-vous auprès de l'IGN
#
# Vous devez pour vos tests, vous enregistrer sur le site http://api.ign.fr pour créer une clé pour un usage "développeurs". Il vous faut créer une clé avec le support de OpenLS (c'est un standard OGC pour le géocodage). Cela pourra être une clé "Sig" ou "Web" qui permettent d'accéder aux trois fonctionnalités de géocodage qu'offrent l'API.
# Celle-ci permet une recherche adresse, une recherche par parcelles (sous réserve que ces parcelles soient des parcelles avec cadastre vecteur) ou par toponymes.
# Vous avez aussi la fonctionnalité de reverse geocoding qui consiste à faire l'opposer du géocodage c'est à dire d'associer une adresse à une position. Typiquement, cal répond à une question vous êtes livreur et souhaitez confirmer que vous êtes dans la bonne rue où livrer. Depuis votre mobile, vous envoyez vos coordonnées et vous connaissez votre rue.
#
# Selon, votre usage, attention de souscrire à la "bonne" licence. Pour cela, allez voir les conditions d'utilisation sur http://professionnels.ign.fr/api-web#tab-3
#
# ## Installer Geopy
#
# Pour essayer le géocodeur de l'IGN, vous devez installer GeoPy (version 1.7) avec
#
# pip install geopy
#
#
# ## Configurer les variables d'environnement
#
# Après installation, nous allons vous montrer quelques exemples d'opérations de géocodage
#
# Pour éviter de coder "en dur", c'est à dire dans un fichier contenant du code, nous allons utiliser des variables d'environnement pour par exemple éviter de laisser trainer des informations confidentielles sur un gestionnaire de version type SVN, Git ou Mercurial
#
# Pour vous authentifier, vous avez deux choix (qui s'excluent):
#
# * en passant par ce qu'on appel le `referer` avec la clé d'API
# * avec un couple nom utilisateur / mot de passe avec la clé d'API.
#
# Selon votre clé et votre système d'exploitation, l'exportation des variables d'environnement varie aussi. Voir le récapitulatif ci-dessous.
#
# ** Linux / Mac **
#
# # Clé Sig
# export IGNFRANCE_KEY='votre_cle'
# export IGNFRANCE_USERNAME='votre_nom_utilisateur'
# export IGNFRANCE_PASSWORD='votre_mot_de_passe'
# unset IGNFRANCE_REFERER
#
# ou
#
# # Clé Web
# export IGNFRANCE_KEY='votre_cle'
# export IGNFRANCE_REFERER='localhost' # En dev, c'st localhost mais cela peut changer quand vous avez une clé "pro"
# unset IGNFRANCE_USERNAME
# unset IGNFRANCE_PASSWORD
#
# ** Windows **
#
# # Clé Sig
# set IGNFRANCE_KEY='votre_cle'
# set IGNFRANCE_USERNAME='votre_nom_utilisateur'
# set IGNFRANCE_PASSWORD='votre_mot_de_passe'
# setx IGNFRANCE_REFERER ""
#
# ou
#
# # Clé Web
# set IGNFRANCE_KEY='votre_cle'
# set IGNFRANCE_REFERER='localhost' # En dev, c'st localhost mais cela peut changer quand vous avez une clé "pro"
# setx IGNFRANCE_USERNAME ""
# setx IGNFRANCE_PASSWORD ""
#
# In[1]:
# Pour la compatibilité Python 2/3
from __future__ import absolute_import, division, print_function
from builtins import (bytes, str, open, super, range,
zip, round, input, int, pow, object)
from geopy.geocoders.ignfrance import IGNFrance
import os
# Si on veut le mode debug qui permet d'afficher les urls appelées ainsi que le contenu XML qui est envoyé et reçu,
# on décommente les 4 lignes ci-dessous
#import logging
#logger = logging.getLogger('geopy')
#logger.addHandler(logging.StreamHandler())
#logger.setLevel('DEBUG')
# Partie authentification qui nécessite d'avoir enregistré les variables d'environnement avant d'avoir lancé le "notebook"
ign = IGNFrance(
api_key=os.environ.get('IGNFRANCE_KEY'),
username=os.environ.get('IGNFRANCE_USERNAME'),
password=os.environ.get('IGNFRANCE_PASSWORD'),
referer=os.environ.get('IGNFRANCE_REFERER'),
timeout=20 # Set to 20 seconds
)
# In[2]:
# Appel au cadastre pour avoir les coordonnées d'une parcelle
cadastre_call = ign.geocode('44109000EX0114', 'CadastralParcel', maximum_responses=10, exactly_one=True)
print (cadastre_call.raw)
# In[3]:
# Adresse avec retour de type freeform
adress_call_with_freeform = ign.geocode(
query="8 rue Général Buat, Nantes",
query_type="StreetAddress",
is_freeform=True,
exactly_one=False,
maximum_responses=5
)
print (adress_call_with_freeform)
for adr in adress_call_with_freeform:
print (adr.raw)
# In[4]:
# Adresse avec retour "classique"
adress_call = ign.geocode('8 rue Général Buat, Nantes', 'StreetAddress',
maximum_responses=10, exactly_one=False)
for poi in adress_call:
print (poi.raw)
# In[5]:
# Cas PositionOfInterest en réalité les toponymes
position_of_interest_call_attrib_filtering = ign.geocode(
'Les Molettes',
'PositionOfInterest',
maximum_responses=10,
filtering='<Place type="Departement">38</Place>',
exactly_one=False
)
for poi in position_of_interest_call_attrib_filtering:
print (poi.raw)
# In[7]:
# Filtrage des résultats en fonction d'une enveloppe
lat_min, lng_min, lat_max, lng_max = 45.00, 5, 46, 6.40
spatial_filtering_envelope = """
<gml:envelope>
<gml:pos>{lat_min} {lng_min}</gml:pos>
<gml:pos>{lat_max} {lng_max}</gml:pos>
</gml:envelope>
""".format(
lat_min=lat_min,
lng_min=lng_min,
lat_max=lat_max,
lng_max=lng_max
)
position_of_interest_call_spatial_filtering_envelope = ign.geocode(
'Les Molettes',
'PositionOfInterest',
maximum_responses=10,
filtering=spatial_filtering_envelope,
exactly_one=False
)
for poi in position_of_interest_call_spatial_filtering_envelope:
print (poi.raw)
# In[8]:
# Reverse géocodage "Normal" c'est à dire sans filtre
point_call = ign.reverse(
query='47.229554,-1.541519',
exactly_one=True
)
print (point_call.raw)
# In[11]:
# Il existe la possibilité de retourner à la fois des adresses et des toponymes via des "preferences
point_call_preference = ign.reverse('47.229554,-1.541519',
reverse_geocode_preference=['StreetAddress', 'PositionOfInterest'])
print (point_call_preference[0].raw)
# Reverse geocodage en spécifiant le centre et le rayon de recherche en mètres
spatial_filtering_radius = """
<gml:CircleByCenterPoint>
<gml:pos>{coord}</gml:pos>
<gml:radius>{radius}</gml:radius>
</gml:CircleByCenterPoint>
""".format(coord='48.8033333 2.3241667', radius='50')
point_call_radius = ign.reverse('48.8033333,2.3241667',
maximum_responses=10,
filtering=spatial_filtering_radius)
print (len(point_call_radius))
# Test avec les mêmes coordonnées, sans filtre spatial
point_call_no_radius = ign.reverse('48.8033333,2.3241667',
maximum_responses=10)
print (len(point_call_no_radius))
# In[10]:
# Filtrage avec un polygone
# Ne marche pas ou bien on a loupé quelque chose dans la documentation
# http://api.ign.fr/tech-docs-js/fr/developpeur/search.html#Recherche_avec_une_contrainte_polygonale
spatial_filtering_polygon = """
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:pos>48.8033 2.3241</gml:pos>
<gml:pos>48.8033 2.3242</gml:pos>
<gml:pos>48.8032 2.3242</gml:pos>
<gml:pos>48.8032 2.3241</gml:pos>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
"""
point_call_polygon = ign.reverse('48.8033333,2.3241667',
maximum_responses=10, filtering=spatial_filtering_polygon)
print (point_call_polygon)
# ## Exemple avec des données tabulaires
#
# On termine avec un exemple plus complet qui utilise des bibliothèques de haut niveau comme Pandas pour manipuler un CSV
# Il permet d'utiliser aussi en entrée des données Excel et d'écrire en Excel
#
# Selon votre besoin et vos contraintes, le [module CSV de Python](https://docs.python.org/2/library/csv.html) peut faire l'affaire.
#
# Si vous devez utiliser Excel, il est possible de travailler avec [Tablib](https://tablib.readthedocs.org/en/latest/) ou bien le couple [xlrd/xlwt](http://www.python-excel.org/)
#
# Pour LibreOffice, il est possible d'utiliser une bibliothèque comme [Unotools](https://pypi.python.org/pypi/unotools/0.3.2) qui s'interface avec LibreOffice/OpenOffice via Python
#
# Vous devez installer Pandas et Numpy avec
#
# pip install numpy pandas
#
# In[14]:
import pandas as pd
import numpy as np
import urllib
# Les données viennent de http://www.ign.fr/institut/adresses-lign
df = pd.read_csv(
'ign_adresse_a_geocoder.tsv',
sep='\t',
encoding='utf-8'
)
columns_names = list(df.columns.values)
print (columns_names)
# [u'NOM', u'ADRESSE', u'CP_VILLE', u'TEL']
# Ajout de nouvelles "colonnes"
df.insert(len(columns_names), "R_ADRESS", np.nan)
df.insert(len(columns_names) + 1, "LONGITUDE", np.nan)
df.insert(len(columns_names) + 2, "LATITUDE", np.nan)
df.insert(len(columns_names) + 3, "ACCURACY", np.nan)
df.insert(len(columns_names) + 4, "QUALITE", np.nan)
df.insert(len(columns_names) + 5, "MATCH_TYPE", np.nan)
# Appel au service de géocodage et mise à jour des colonnes avec les résultats
for index, row in df.iterrows():
url_encoded_address = (row['ADRESSE'] + ', ' + row['CP_VILLE']).encode('ascii', errors='xmlcharrefreplace') # Pour éviter des erreurs sur les accents
#print url_encoded_address
results = ign.geocode(
url_encoded_address,
query_type="StreetAddress",
exactly_one=True
)
df.loc[index, 'R_ADRESS'] = results.address
df.loc[index, 'LONGITUDE'] = results.longitude
df.loc[index, 'LATITUDE'] = results.latitude
df.loc[index, 'ACCURACY'] = results.raw['accuracy']
df.loc[index, 'QUALITE'] = results.raw['qualite']
df.loc[index, 'MATCH_TYPE'] = results.raw['match_type']
# Write results
df.to_csv('adresses_avec_geocodage.txt', sep='\t', encoding='utf-8', index=False)
df
# Les résultats dans adresses_avec_geocodage.txt sont très bons mais aussi quelquefois très mauvais. On les identifie assez vite car le résultat est alors avec une précision "à la ville" `City`
#
# Voici quelques cas où le résultat est à la ville et ce n'est pas toujours la bonne ville d'ailleurs.
# In[12]:
# Ville où code postal et adresses ne correspondent pas en fait à une commune (ville nouvelle)
# Voir https://fr.wikipedia.org/wiki/Marne-la-Vall%C3%A9e
adress_call = ign.geocode('6/8, avenue Blaise Pascal, 77455 MARNE-LA-VALLÉE CEDEX 2', 'StreetAddress',
maximum_responses=10, exactly_one=True)
print (adress_call.address)
adress_call = ign.geocode('6/8, avenue Blaise Pascal, Champs sur Marne', 'StreetAddress',
maximum_responses=10, exactly_one=True)
print (adress_call.address)
# In[13]:
# Juste un édifice mais sans rue donc un peu normal mais gagnerait à utiliser des noms de bâtiments
# Pour éviter des erreurs sur les accents
address = 'Château des Barres, 45290 NOGENT-SUR-VERNISSON'.encode('ascii', errors='xmlcharrefreplace')
adress_call = ign.geocode(address, maximum_responses=10, exactly_one=True)
print (adress_call.address)
# In[16]:
# Correspondance la meilleure (similarité de chaîne du genre calcul de la distance de Levenshtein)
# Malheureusement, le nom de la commune est incomplet donc c'est faux.
# Le calculateur semble ignorer l'indication que fournit le code postal dans la chaîne envoyée
address = "6, avenue de l'Europe - BP 42116, 31521 RAMONVILLE CEDEX".encode('ascii', errors='xmlcharrefreplace')
adress_call = ign.geocode(address, maximum_responses=10, exactly_one=True)
print (adress_call.address)
address = "6, avenue de l'Europe - BP 42116, 31521 RAMONVILLE-SAINT-AGNE CEDEX".encode('ascii', errors='xmlcharrefreplace')
adress_call = ign.geocode(address, maximum_responses=10, exactly_one=True)
print (adress_call.address)
# ## Support du géocodeur en dehors de Python
#
# Le support du géocodage est plus limité mais existe aussi [côté PHP](https://github.com/geocoder-php/geocoder-extra/blob/master/src/Geocoder/Provider/IGNOpenLSProvider.php).
#
# Vous pouvez aussi utiliser [CURL](http://curl.haxx.se/), un utilitaire en ligne de commande même s'il vous restera toujours à gérer le XML retourné.
#
# Par ailleurs, des exemples sont aussi disponibles sur le site officiel de l'IGN lorsque vous voulez géocoder directement côté client (en JavaScript ou Flash) mais sans avoir besoin de garder le résultat du géocodage en mémoire
# http://api.ign.fr/tech-docs-js/examples/
NOM ADRESSE CP_VILLE TEL
Institut national de l'information géographique et forestière - Siège 73, avenue de Paris 94165 SAINT-MANDÉ CEDEX Tél. : 01 43 98 80 00
Le monde des cartes 50, rue de la Verrerie 75004 PARIS Tél. : 01 43 98 85 10
IGN France International 90, avenue de Flandre 75019 PARIS Tél. : 01 42 34 56 56
ENSG (École nationale des sciences géographiques) - Cité Descartes 6/8, avenue Blaise Pascal 77455 MARNE-LA-VALLÉE CEDEX 2 Tél. : 01 64 15 30 01
Centre de production Île-de-France 73, avenue de Paris 94165 SAINT-MANDÉ CEDEX
Service de l'inventaire forestier Château des Barres 45290 NOGENT-SUR-VERNISSON
Direction interrégionale centre-est 239 rue Garibaldi 69422 LYON CEDEX 03
Direction interrégionale nord-ouest - Nantes 2, boulevard de la Loire - BP 30412 44204 NANTES CEDEX 02
Direction interrégionale nord-ouest - Caen 73, rue Marie Curie 14200 HEROUVILLE-SAINT-CLAIR
Direction interrégionale sud-est - Europarc de Pichaury 1330, avenue JRGG de la Lauzière, CS 80518 13593 AIX-EN-PROVENCE CEDEX 3
Direction interrégionale nord-est 11, rue de l'Île de Corse 54000 NANCY
Direction interrégionale sud-ouest Rue Pierre Ramond-Caupian, BP 60104 33166 SAINT-MÉDARD-EN-JALLES CEDEX
Base aérienne de Creil Route de la Forêt de Verneuil-en-Halatte, BP 125 60107 CREIL CEDEX
IGN Espace - Parc technologique du canal 6, avenue de l'Europe - BP 42116 31521 RAMONVILLE CEDEX
IGN Sologne Camp des Landes 41200 VILLEFRANCHE-SUR-CHER
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment