Comment trouver le bureau de poste le plus proche de chez vous à l’aide de Voronoï et Python ?
Bien entendu, cette question peut se formuler avec autre chose qu’un bureau de poste…
Si vous ne connaissez pas le pavage de Voronoï, je vous encourage à regarder ce post.
Vous pouvez aussi regarder cet article sur Wikipedia.
Comment trouver le bureau de poste le plus proche de chez vous? La méthode.
La méthode est “simple” : on répertorie toutes les coordonnées de ce que l’on cherche (ici, les bureaux de poste) et on fait notre pavage…
Facile à dire, mais concrètement ?
Récupération des coordonnées
On va s’aider de l’API OpenStreetMap.
import requests def get_post_offices_overpass(city_name): query = f""" [out:json]; area["name"="{city_name}"]->.searchArea; node["amenity"="post_office"](area.searchArea); out body; """ url = "http://overpass-api.de/api/interpreter" response = requests.post(url, data={'data': query}) data = response.json() post_offices = [(element['tags'].get('name', 'Post Office'), element['lat'], element['lon']) for element in data['elements']] return post_offices
Placement sur une carte et tracé du pavage de Voronoï
On va s’aider de folium.
import folium import numpy as np from shapely.geometry import Polygon from shapely.ops import unary_union from geovoronoi import voronoi_regions_from_coords def create_map(city_name="Bordeaux"): post_offices = get_post_offices_overpass(city_name) # Créer une carte centrée sur Bordeaux map_bordeaux = folium.Map(location=[44.8378, -0.5792], zoom_start=13) # Ajouter les bureaux de poste à la carte for name, lat, lng in post_offices: folium.Marker(location=[lat, lng], popup=name).add_to(map_bordeaux) # Convertir les coordonnées des bureaux de poste en objets Point coords = np.array([(lng, lat) for name, lat, lng in post_offices]) # Définir une zone de délimitation (par exemple, les limites de Bordeaux) # Utiliser un polygone explicite pour Bordeaux boundary_coords = [(-0.8, 45.1), (0.02, 45.1), (0.02, 44.6), (-0.8, 44.6), (-0.8, 45.1)] boundary_polygon = Polygon(boundary_coords) # Calculer les régions de Voronoi à partir des coordonnées try: region_polys, region_pts = voronoi_regions_from_coords(coords, boundary_polygon) except RuntimeError as e: print(f"Erreur lors de la génération des régions de Voronoi: {e}") return # Ajouter les régions de Voronoi à la carte folium for region in region_polys.values(): folium.Polygon(locations=[(lat, lng) for lng, lat in region.exterior.coords]).add_to(map_bordeaux) # Sauvegarder la carte dans un fichier HTML map_bordeaux.save('map_bordeaux.html') return None
Cela va générer une page HTML d’une carte zoomable:
Bon, là, ce n’est qu’une image car je ne peux pas insérer la page directement, mais vous voyez le genre ?
Et pour une autre ville ?
La seule chose qui diffère dans le code est le rectangle dans lequel se trouve la ville: il faudra le construire vous même (le boundary_polygon).
Pour se faire, vous pouvez ajouter l’instruction:
boundary_polygon = Polygon(boundary_coords) print("Coords:", coords) # ligne à ajouter
tout de suite après avoir défini la variable boundary_polygon. Vous verrez ainsi où se situent les points et vous n’aurez plus qu’à modifier les coordonnées des coins du rectangle :
boundary_coords = [(xmin, ymax), (xmax, ymax), (xmax, ymin), (xmin, ymin), (xmin, ymax)]
Et pour autre chose qu’un bureau de poste?
Il faudra changer les informations de la fonction get_post_offices_overpass. Concrètement, il faudra changer “Post Office” par ce que vous voulez. Pour connaître les termes, consultez la page:
https://wiki.openstreetmap.org/wiki/FR:Key:shop
Et c’est ainsi que je m’aperçus que je faisais 1 km pour rien à chaque fois…
cool