2025
08.15

Remue-méninges


Résumé

De retour d’un voyage formidable de près de 24jours à travers la France, je me suis mis à discuter avec mon chat. Lui demandant de me dessiner de ses petites pattes toute mimi une carte simpliste et inspirée de celles du véritable Tour de France, et qui reprendrait les étapes de mon périple. Mon chat qui est toujours très « prompt » à jouer m’a demandé si le Python pouvait m’aller, et je lui ai dis que oui car du Python j’en ai déjà exécuté sur mon Pingouin… Pour cela, seront nécessaires python3 ainsi que quelques bibliothèques pour récupérer les positions GPS de chaque commune et « écrire » la carte dont voici le résultat. Un bon exercice après des jours entiers à pédaler pour remettre le cerveau en route… 😉

sudo apt install python3 python3-pip

pip install matplotlib geopandas shapely geopy requests

pip3 install --user --force-reinstall --no-deps numpy==1.22.4

pip install geodatasets

python3 carte_voyage_velo_v18.py

La carte de mon périple à travers la France, écrite via un script Python lancé sur une distribution Linux Mint, et un nouvel exemple de ce qu’il est possible de faire avec l’IA !


Code Python

Nom du fichier : carte_voyage_velo_v18.py

 

import matplotlib.pyplot as plt
import geopandas as gpd
from shapely.geometry import LineString
from geopy.geocoders import Nominatim
import time

# — Données —
stages_bike = [
« Virieu-le-Grand », « Gex », « Pontarlier », « Seppois-le-Bas », « Ribeauvillé »,
« Saverne », « Metz », « Mouzon 08210 », « Sémeries », « Boeschepe », « Escalles »,
« Groffliers », « Martigny », « Yport », « Honfleur », « Osmanville », « Cherbourg »,
« Saint Pair-sur-Mer », « Mont-Saint-Michel », « Saint Malo »,
« Nantes », « Loireauxence », « Chouzé-sur-Loire », « Muides-sur-Loire »,
« Gien », « Nevers »
]

stages_train = [
(« Saint Etienne », « Virieu-le-Grand »), # segment initial
(« Saint Malo », « Nantes »),
(« Nevers », « Saint Etienne »)
]

# — Géocodage —
geolocator = Nominatim(user_agent= »velo_carte »)
locations = {}
for place in set(stages_bike + [p for seg in stages_train for p in seg]):
loc = geolocator.geocode(f »{place}, France »)
if loc:
locations[place] = (loc.longitude, loc.latitude)
else:
print(f »Non trouvé : {place} »)
time.sleep(1)

# — Segments vélo —
bike_segment1 = [p for p in stages_bike if p not in [« Nantes », « Loireauxence », « Chouzé-sur-Loire », « Muides-sur-Loire », « Gien », « Nevers »]]
bike_segment2 = [« Nantes », « Loireauxence », « Chouzé-sur-Loire », « Muides-sur-Loire », « Gien », « Nevers »]

# — Carte France Métropole —
shapefile_path = « /media/damien/DATA/DOCUMENT/vélo/2025/27 – TDF/Python/ne_110m_admin_0_countries/ne_110m_admin_0_countries.shp »
world = gpd.read_file(shapefile_path)
france = world[world.NAME == « France »].copy()
france = france.to_crs(epsg=2154)
france[‘area’] = france.geometry.area
france_metropole = france.loc[france[‘area’].idxmax()].geometry
france_metropole_gs = gpd.GeoSeries([france_metropole], crs= »EPSG:2154″).to_crs(epsg=4326)

# — Figure 5000×5000 px —
fig, ax_map = plt.subplots(figsize=(50, 50))
france_metropole_gs.plot(ax=ax_map, color= »#FFD433″, edgecolor= »black »)

# — Tracés vélo —
if bike_segment1:
coords1 = [locations[p] for p in bike_segment1 if p in locations]
gpd.GeoSeries(LineString(coords1), crs= »EPSG:4326″).plot(ax=ax_map, color= »black », linewidth=2)

if bike_segment2:
coords2 = [locations[p] for p in bike_segment2 if p in locations]
gpd.GeoSeries(LineString(coords2), crs= »EPSG:4326″).plot(ax=ax_map, color= »blue », linewidth=2)

# — Tracés train pointillé rouge —
for start, end in stages_train:
if start in locations and end in locations:
gpd.GeoSeries(LineString([locations[start], locations[end]]), crs= »EPSG:4326″).plot(
ax=ax_map, color= »red », linewidth=2, linestyle=’–‘
)

# — Numéros sur points —
# Premier segment vélo (noir)
for idx, place in enumerate(bike_segment1):
if place in locations:
lon, lat = locations[place]
ax_map.plot(lon, lat, ‘o’, markersize=15, markeredgecolor=’black’, markerfacecolor=’white’, zorder=5)
ax_map.text(lon, lat, str(idx), fontsize=12, ha=’center’, va=’center’, zorder=6)

# Deuxième segment vélo (bleu) avec numéros spécifiques
etapes_numero = [(« Loireauxence », 20), (« Chouzé-sur-Loire », 21),
(« Muides-sur-Loire », 22), (« Gien », 23), (« Nevers », 24)]

for place, numero in etapes_numero:
if place in locations:
lon, lat = locations[place]
ax_map.plot(lon, lat, ‘o’, markersize=15, markeredgecolor=’blue’, markerfacecolor=’white’, zorder=5)
ax_map.text(lon, lat, str(numero), fontsize=12, ha=’center’, va=’center’, zorder=6)

# — Dates départ/arrivée —
if « Virieu-le-Grand » in locations:
ax_map.text(locations[« Virieu-le-Grand »][0], locations[« Virieu-le-Grand »][1] – 0.5,
« 22 juillet 2025″, fontsize=14, color= »black »)
if « Nevers » in locations:
ax_map.text(locations[« Nevers »][0], locations[« Nevers »][1] – 0.5,
« 14 août 2025″, fontsize=14, color= »black »)

# — Labels supplémentaires —
if « Saint Etienne » in locations:
ax_map.text(locations[« Saint Etienne »][0], locations[« Saint Etienne »][1] + 0.2,
« Saint Etienne », fontsize=14, color= »black », ha=’center’)
if « Saint Malo » in locations:
ax_map.text(locations[« Saint Malo »][0], locations[« Saint Malo »][1] + 0.2,
« Saint Malo », fontsize=14, color= »black », ha=’center’)

# — Kilométrage total —
ax_map.text(0.02, 0.95, « 3000 km », transform=ax_map.transAxes,
fontsize=24, fontweight=’bold’, color= »black », ha=’left’, va=’top’)

# — Légende des villes —
legend_text = [f »{i}: {p} » for i, p in enumerate(stages_bike)]
n = len(legend_text)
margin_top = 0.95
margin_bottom = 0.05
for i, text in enumerate(legend_text):
y_pos = margin_top – i * (margin_top – margin_bottom) / max(n-1, 1)
ax_map.text(1.02, y_pos, text, transform=ax_map.transAxes,
fontsize=12, color= »red », va=’top’, ha=’left’)

ax_map.set_axis_off()

# — Titre avec drapeau pirate —
ax_map.set_title(« Saint Malo, par les routes du Tour de France ‍☠️ »,
fontsize=36, fontweight=’bold’, color= »black », pad=50)

# — Sauvegarde SVG —
plt.savefig(« carte_voyage_velo_metropole_legende_5000px.svg », format= »svg », bbox_inches= »tight »)
plt.close()

print(« ✅ Carte finale mise à jour : segment bleu vélo Nantes → Loireauxence inclus, tout le reste conservé. »)

 

Aucun commentaire.

Les commentaires sont fermés