Routing in Python mit casaGeoTools

Einführung

In diesem Tutorial verwenden wir ein einfaches Jupyter Notebook, um anhand von drei praxisnahen Beispielen zu zeigen, wie sich Routing in Python-basierte Geodaten-Workflows integrieren lässt. Die Beispiele zeigen, wie mehrere Routen in einer Batch-Verarbeitung berechnet, unterschiedliche Routing-Strategien verglichen und alternative Routen erzeugt werden können.

Dieses Tutorial richtet sich an Data Scientists, Geodatenanalysten und Entwickler, die mit räumlichen Daten in Python arbeiten.

Step 1

Importieren Sie zunächst die benötigten Python-Pakete, darunter Pandas, Shapely, GeoPandas und Folium. Mit Folium lassen sich die berechneten Routen anschließend auf interaktiven Karten visualisieren.

Passen Sie anschließend die Pandas-Anzeigeeinstellungen an. Dadurch zeigt das Notebook alle Zeilen und Spalten der Ergebnistabellen an, was bei der Analyse der Routing-Ergebnisse hilfreich ist.

Python Script


import os

import pandas as pd
import shapely
from dotenv import load_dotenv
import geopandas as gpd
import folium

# casaGeoTools Beta modules
from casageo import spatial as cs
from casageo import tools as ct



# Ensure dataframes are printed completely
pd.set_option("display.max_rows", None)
pd.set_option("display.max_columns",None)
pd.set_option("display.width",999)



Step 2 - Define Routing Inputs

Zunächst initialisieren wir den casaGeoTools-Client. Der API-Schlüssel wird aus einer lokalen .env-Datei geladen, sodass die Zugangsdaten getrennt vom Notebook gespeichert bleiben.

Anschließend definieren wir mehrere Shapely-Punkte, die die Ursprungs- und Zielorte für die Routing-Beispiele repräsentieren.

Die folgenden Standorte werden in den Beispielen verwendet:

  • casaGeo Hauptsitz, Itzehoe (izet)

  • Elmshorn Hauptbahnhof (iz)

  • Hamburg Hauptbahnhof (hh)

  • Kiel Hauptbahnhof (ki)

  • Lübeck Hauptbahnhof (hl)

Python Script



# Load environment variables (API key) and initialize casaGeoTools client
load_dotenv()
API_KEY = os.getenv("CASAGEOTOOLS_API_KEY")

if not API_KEY:
raise ValueError(
"No CASAGEOTOOLS_API_KEY found in .env file. Please set your casaGeoTools API key."
)

cga = ct.CasaGeoClient(API_KEY)



point_izet = shapely.Point(9.4854461, 53.9580118)
point_iz = shapely.Point(9.660475, 53.753110)
point_hh = shapely.Point(10.008223, 53.553089)
point_ki = shapely.Point(10.13008, 54.31367)
point_hl = shapely.Point(10.66865, 53.86621)


Beispiel 1 - Batch Routing

Im ersten Beispiel demonstrieren wir Batch-Routing. Dabei berechnen wir Routen von unserem Hauptsitz in Itzehoe als Ausgangspunkt zu drei verschiedenen Zielorten: den Hauptbahnhöfen in Hamburg, Kiel und Lübeck. Dazu erstellen wir ein DataFrame, in dem jede Zeile eine Routing-Anfrage repräsentiert. Jeder Eintrag enthält den Ursprung (Origin), das Ziel (Destination), den Routing-Modus sowie den Transportmodus.

Die Routen werden mit der Funktion routes_batch erzeugt. casaGeoTools verarbeitet alle Zeilen des DataFrames und gibt die Ergebnisse als GeoDataFrame mit den berechneten Routengeometrien zurück.

Anschließend visualisieren wir die Routen auf einer interaktiven Folium-Karte. Jede Routengeometrie wird dabei als GeoJSON-Layer zur Karte hinzugefügt, sodass sich die Ergebnisse einfach prüfen lassen.

Python Script



# Create first DataFrame for the batch routing with three different destinations
list_routing_1 = pd.DataFrame([
{"id": 1, "origin": point_izet, "destination": point_hh, "routing_mode": "fast", "transport_mode": "car",
"destination_name": "Hamburg Central Station"},
{"id": 2, "origin": point_izet, "destination": point_ki, "routing_mode": "fast","transport_mode": "car",
"destination_name": "Kiel Central Station"},
{"id": 3, "origin": point_izet, "destination": point_hl, "routing_mode": "fast", "transport_mode": "car",
"destination_name": "Lübeck Central Station"},
])
# Generate routes
cgs = cs.CasaGeoSpatial(cga)

try:
routes_1_gdf = cgs.routes_batch(
list_routing_1,
)
except Exception as e:
routes_1_gdf = gpd.GeoDataFrame().join(list_routing_1.set_index("id"), on="id")
print(f"⚠️ Error during batch routing: {e}")

# Generate map
colors = ['blue','red','purple', 'black']
map_1 = folium.Map(location=[53.85, 9.51], zoom_start=8)
for idx, row in routes_1_gdf.iterrows():
if row['geometry'] is not None:
color = colors[row['id'] % len(colors)]
folium.GeoJson(
row['geometry'],
style_function=lambda x, c=color: {
'color': c,
'weight': 3,
'opacity': 0.7
}
).add_to(map_1)



Beispiel 2 - Fast vs Short Route

In diesem Beispiel berechnen wir zwei Routen zwischen demselben Ursprung — unserem Hauptsitz — und dem Hauptbahnhof Elmshorn als Ziel. Eine Anfrage verwendet den Routing-Modus fast, der auf eine möglichst kurze Fahrzeit optimiert ist, während die zweite Anfrage den Routing-Modus short verwendet, der auf die kürzeste Distanz optimiert ist.

Dieses Beispiel zeigt, wie unterschiedliche Routing-Strategien die resultierende Routengeometrie beeinflussen.

Anschließend werden die Routen auf einer interaktiven Karte visualisiert, um die unterschiedlichen Streckenverläufe miteinander zu vergleichen.

Python Script


list_routing_2 = pd.DataFrame([
{"id": 1, "origin": point_izet, "destination": point_iz, "routing_mode": "fast","transport_mode": "car",
"destination_name": "Elmshorn Central Station, fastest way"},
{"id": 2, "origin": point_izet, "destination": point_iz, "routing_mode": "short","transport_mode": "car",
"destination_name": "Elmshorn Central Station, shortest way"},
])



# Generate routes

cgs = cs.CasaGeoSpatial(cga)

try:
routes_2_gdf = cgs.routes_batch(
list_routing_2,
)
except Exception as e:
routes_2_gdf = gpd.GeoDataFrame().join(list_routing_2.set_index("id"), on="id")
print(f"⚠️ Error during batch routing: {e}")



# interactive map

map_2 = folium.Map(location=[53.85, 9.51], zoom_start=10)
for idx, row in routes_2_gdf.iterrows():
if row['geometry'] is not None:
color = colors[row['id'] % len(colors)]
folium.GeoJson(
row['geometry'],
style_function=lambda x, c=color: {
'color': c,
'weight': 3,
'opacity': 0.7
}
).add_to(map_2)




Beispiel 3 - Alternative Routen

Abschließend fordern wir mehrere alternative Routen an und visualisieren diese auf einer interaktiven Karte. In unserem Beispiel ist der Parameter alternatives auf drei gesetzt, sodass bis zu drei zusätzliche Routenoptionen zurückgegeben werden können. Der Parameter unterstützt Werte von bis zu sieben Alternativen.

Alternative Routen werden jedoch nur zurückgegeben, wenn sie sinnvolle Routenvarianten darstellen. In diesem Beispiel liefert der Routing-Service insgesamt vier Routen: die Hauptroute und drei Alternativen.

Wie zuvor erstellen wir eine interaktive Karte, um die Ergebnisse zu untersuchen.

Python Script


# Create third DataFrame for alternative routes

list_routing_3 = pd.DataFrame([
{"id": 1, "origin": point_izet, "destination": point_hh,"routing_mode": "fast", "transport_mode": "car", "destination_name": "Hamburg Central Station", "alternatives": 3}
])



# Generate routes

try:
routes_3_gdf = cgs.routes_batch(
list_routing_3,
)
except Exception as e:
routes_3_gdf = gpd.GeoDataFrame().join(list_routing_3.set_index("id"), on="id")
print(f"⚠️ Error during batch routing: {e}")



map_3 = folium.Map(location=[53.55, 10], zoom_start=11)
for idx, row in routes_3_gdf.iterrows():
if row['geometry'] is not None:
color = colors[row['subid'] % len(colors)]
folium.GeoJson(
row['geometry'],
style_function=lambda x, c=color: {
'color': c,
'weight': 3,
'opacity': 0.7
}
).add_to(map_3)




Download

Um direkt mit der Entwicklung zu starten, können Sie dieses Beispiel unten als Jupyter Notebook herunterladen.