/Geocodage_IGN_geopy.ipynb Secret
Last active
August 29, 2015 14:12
Star
You must be signed in to star a gist
Notebook avec fichiers en entrée pour géocoder avec le géocodeur IGN France
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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