Une situation qui revient tous les ans : un client envoie un fichier de positions géographiques en Lambert 93 (livré par l'IGN, le cadastre ou un bureau d'études) et il faut l'afficher sur une carte web Leaflet ou Mapbox, qui attend du WGS84 en latitude/longitude. Le réflexe naturel est d'aller chercher la formule de la projection Lambert conique conforme et de la coder à la main. C'est une perte de temps : la formule existe, mais elle se complique vite avec les transformations de datum (NTF → RGF93) et les ajustements de grille. J'ai vu deux projets passer une demi-journée là-dessus avant que quelqu'un découvre pyproj.

Cet article montre la conversion Lambert 93 ↔ WGS84 en Python en trois lignes, les pièges qui font perdre du temps malgré tout, et l'alternative API quand vous partez d'une adresse plutôt que de coordonnées déjà calculées.


WGS84 vs Lambert 93 en 30 secondes

WGS84 (EPSG:4326) est le système géodésique mondial. Coordonnées en degrés décimaux, latitude et longitude. C'est ce que sortent les récepteurs GPS, ce qu'attendent Google Maps, OpenStreetMap, Leaflet, Mapbox et 99 % des cartes web. Pour Paris, la rue de la Paix est à lat: 48.8689, lon: 2.3311.

Lambert 93 (EPSG:2154) est une projection conique conforme officielle de l'IGN pour la France métropolitaine. Coordonnées en mètres, x (est) et y (nord). Même rue de la Paix : x: 650 936, y: 6 863 425. C'est le système de référence du cadastre, des logiciels SIG français (QGIS configuré FR, ArcGIS, Géoportail) et de toutes les bases de données métiers qui calculent des distances en mètres sans repasser par la trigonométrie sphérique.

Les deux coexistent parce qu'ils servent des choses différentes : WGS84 pour positionner et afficher, Lambert 93 pour mesurer et croiser avec les données françaises.

Conversion en Python avec pyproj

Installation :

pip install pyproj

WGS84 → Lambert 93 :

from pyproj import Transformer

wgs84_to_lambert93 = Transformer.from_crs("EPSG:4326", "EPSG:2154", always_xy=True)

lon, lat = 2.3311, 48.8689
x, y = wgs84_to_lambert93.transform(lon, lat)
print(f"x={x:.2f}, y={y:.2f}")
# x=650936.23, y=6863425.69

Lambert 93 → WGS84 (inverse) :

lambert93_to_wgs84 = Transformer.from_crs("EPSG:2154", "EPSG:4326", always_xy=True)

x, y = 650936.23, 6863425.69
lon, lat = lambert93_to_wgs84.transform(x, y)
print(f"lat={lat:.6f}, lon={lon:.6f}")
# lat=48.868900, lon=2.331100

C'est tout. Le transformer est sans état et réentrant : pour traiter un fichier complet, instanciez-le une seule fois et bouclez dessus.

Prêt à intégrer l'API TrustyData ?

Tester les services →Découvrir les plans →

Les pièges qui font perdre des heures

Le piège qui m'a fait perdre le plus de temps est l'ordre des axes. PROJ a changé deux fois d'avis sur l'ordre par défaut (latitude-longitude vs longitude-latitude), et sans l'option always_xy=True, pyproj attend les coordonnées dans l'ordre déclaré par l'EPSG du système. Pour WGS84, c'est (lat, lon) ; pour Lambert 93, c'est (x, y). On inverse silencieusement sa longitude et sa latitude, on obtient un point au milieu de l'Atlantique, et on cherche pendant trois heures. Toujours passer always_xy=True et travailler en (lon, lat) partout, c'est la convention la moins surprenante.

Autre piège classique : Lambert 93 n'est pas Lambert II étendu. Si vous récupérez un fichier IGN d'avant 2009, il y a de fortes chances qu'il soit en Lambert II étendu (EPSG:27572), pas en Lambert 93. Les ordres de grandeur sont différents : en Lambert 93, y est autour de 6 à 7 millions ; en Lambert II étendu, y est autour de 2 millions. Si vos points retombent à 5 000 km de la France après conversion, c'est probablement ça. Lisez l'en-tête du fichier (le .prj d'un shapefile, ou la doc du producteur) avant de présumer.

Lambert 93 ne couvre que la métropole. Pour l'outre-mer, chaque territoire a sa projection UTM dédiée : Antilles EPSG:32620, Guyane EPSG:2972, Réunion EPSG:2975, Mayotte EPSG:4471. Sur un fichier national complet, prévoyez une logique de routage par territoire avant d'appeler le transformer.

Côté précision enfin : pyproj atteint sur le territoire français une précision sub-millimétrique pour Lambert 93 ↔ WGS84, au-delà de ce dont 99 % des usages ont besoin. Pour la géodésie haute précision (topographie au millimètre), activez les grilles de transformation NTF/RGF93 fournies par l'IGN.

Un peu d'histoire pour s'y retrouver

Lambert 93 a remplacé une famille de systèmes basés sur la NTF (Nouvelle Triangulation Française, datum dérivé de l'ellipsoïde Clarke 1880). Le décret 2006-272 a fait du RGF93 (compatible WGS84/ETRS89) le système géodésique légal en France métropolitaine, et l'IGN a fini la migration de ses produits autour de 2009. C'est pourquoi le millésime du fichier source est un signal fort sur le système qu'il porte.

Les EPSG à connaître si vous croisez des données françaises de différentes époques :

EPSG Système Quand on le rencontre
2154 Lambert 93 (RGF93) Standard officiel depuis 2009
27572 Lambert II étendu (NTF) Fichiers IGN/cadastre pré-2009 « France entière »
27561-27564 Lambert zones I, II, III, IV (NTF) Anciens fichiers découpés par bande de latitude
3942-3950 Coniques Conformes CC42 à CC50 (RGF93) Cadastre et cartographie de très haute précision (zones de 1° de latitude)
4326 WGS84 GPS, cartes web, échanges internationaux

pyproj convertit d'un EPSG à l'autre dès lors que le code source est correct dans le fichier de départ. La conversion NTF → RGF93 inclut une transformation de datum (corrections de l'ordre de 100 m selon la zone), pas seulement une projection. C'est cette transformation qui explique pourquoi un point lu « tel quel » en pensant que c'est du Lambert 93 alors qu'il est en NTF retombe à plusieurs dizaines de mètres de sa vraie position.

L'alternative pour les adresses françaises

Si vous n'avez pas un fichier de positions déjà géocodées mais une liste d'adresses à transformer en coordonnées, vous pouvez sauter complètement l'étape pyproj. L'API TrustyData calcule les deux systèmes côté serveur depuis le référentiel BAN et les renvoie dans la même réponse /address/verify.

import requests

response = requests.post(
    "https://api.trustydata.app/services/v1/address/verify",
    json={"q": "10 rue de la paix 75002 paris", "max_results": 1},
    headers={"Authorization": "Bearer VOTRE_CLE_API"},
    timeout=5,
)
top = response.json()["matches"][0]
pos = top["position"]
print(f"WGS84      : lat={pos['lat']}, lon={pos['lon']}")
print(f"Lambert 93 : x={pos['x']}, y={pos['y']}")
# WGS84      : lat=48.868989, lon=2.33115
# Lambert 93 : x=650936.23, y=6863425.69

Le bloc position héberge les quatre champs ; vous n'avez aucune conversion à faire côté client. Cette double sortie est ouverte dès le plan Starter.

Quand utiliser quoi

Pour un fichier de coordonnées déjà existantes (livraison IGN, export cadastre, données métier en Lambert), pyproj est l'outil pensé pour ça : gratuit, robuste, sans dépendance réseau. Pour partir d'adresses textuelles, l'API évite la double opération (géocoder puis convertir) et garantit que les deux systèmes sortent de la même position BAN. La validation géographique de l'adresse tombe au passage.

Pour résumer

pyproj règle la conversion Lambert 93 ↔ WGS84 en trois lignes, à condition de passer always_xy=True et de vérifier que votre fichier source est bien en EPSG:2154 et pas en Lambert II étendu. Pour les adresses françaises, l'API TrustyData renvoie les deux systèmes directement dans la réponse, sans étape supplémentaire.

Tester la démo de géocodage ou voir le détail des plans sur la page tarifs.