Note
Go to the end to download the full example code.
Matching with an AequilibraE Model#
import uuid
from os.path import join
from tempfile import gettempdir
from aequilibrae.utils.create_example import create_example
from mapmatcher import MapMatcher
from mapmatcher.examples import nauru_data
nauru_gps = nauru_data()
# Let's see if the data has all the fields we need
nauru_gps.head()
Since it does not, let’s fix it
nauru_gps.rename(columns={"x": "longitude", "y": "latitude", "vehicle_unique_id": "trace_id"}, inplace=True)
We get our AequilibraE model for Nauru and create the map-mather from this model We also need to provide the transportation mode we want to consider for the map-matching
project = create_example(join(gettempdir(), uuid.uuid4().hex), "nauru")
# We need to have at least one centroid connector to the model due to a bug in AequilibraE 0.9.5
project.conn.execute("Update Nodes set is_centroid=1 where node_id = 1")
mmatcher = MapMatcher.from_aequilibrae(project, "c")
let’s add the GPS data to the map-matcher and run it!
mmatcher.load_gps_traces(nauru_gps)
mmatcher.map_match(parallel_threads=1)
building trips: 0%| | 0/100 [00:00<?, ?it/s]
building trips: 4%|▍ | 4/100 [00:00<00:02, 39.07it/s]
building trips: 9%|▉ | 9/100 [00:00<00:02, 44.04it/s]
building trips: 14%|█▍ | 14/100 [00:00<00:01, 45.58it/s]
building trips: 19%|█▉ | 19/100 [00:00<00:01, 44.74it/s]
building trips: 24%|██▍ | 24/100 [00:00<00:01, 44.28it/s]
building trips: 29%|██▉ | 29/100 [00:00<00:01, 44.42it/s]
building trips: 34%|███▍ | 34/100 [00:00<00:01, 43.69it/s]
building trips: 39%|███▉ | 39/100 [00:00<00:01, 42.84it/s]
building trips: 44%|████▍ | 44/100 [00:01<00:01, 42.48it/s]
building trips: 49%|████▉ | 49/100 [00:01<00:01, 42.11it/s]
building trips: 54%|█████▍ | 54/100 [00:01<00:01, 41.71it/s]
building trips: 59%|█████▉ | 59/100 [00:01<00:00, 42.09it/s]
building trips: 64%|██████▍ | 64/100 [00:01<00:00, 42.34it/s]
building trips: 69%|██████▉ | 69/100 [00:01<00:00, 43.64it/s]
building trips: 74%|███████▍ | 74/100 [00:01<00:00, 42.94it/s]
building trips: 79%|███████▉ | 79/100 [00:01<00:00, 42.87it/s]
building trips: 84%|████████▍ | 84/100 [00:01<00:00, 42.43it/s]
building trips: 89%|████████▉ | 89/100 [00:02<00:00, 41.67it/s]
building trips: 94%|█████████▍| 94/100 [00:02<00:00, 42.73it/s]
building trips: 99%|█████████▉| 99/100 [00:02<00:00, 41.51it/s]
building trips: 100%|██████████| 100/100 [00:02<00:00, 42.63it/s]
Map matching trips: 0%| | 0/100 [00:00<?, ?it/s]
Map matching trips: 6%|▌ | 6/100 [00:00<00:05, 17.98it/s]
Map matching trips: 11%|█ | 11/100 [00:00<00:05, 17.56it/s]
Map matching trips: 13%|█▎ | 13/100 [00:00<00:07, 12.37it/s]
Map matching trips: 15%|█▌ | 15/100 [00:01<00:08, 10.48it/s]
Map matching trips: 18%|█▊ | 18/100 [00:01<00:08, 9.30it/s]
Map matching trips: 19%|█▉ | 19/100 [00:01<00:10, 8.09it/s]
Map matching trips: 20%|██ | 20/100 [00:02<00:13, 5.99it/s]
Map matching trips: 25%|██▌ | 25/100 [00:02<00:09, 7.55it/s]
Map matching trips: 33%|███▎ | 33/100 [00:03<00:06, 11.12it/s]
Map matching trips: 36%|███▌ | 36/100 [00:03<00:07, 8.66it/s]
Map matching trips: 39%|███▉ | 39/100 [00:04<00:06, 8.96it/s]
Map matching trips: 42%|████▏ | 42/100 [00:04<00:06, 8.38it/s]
Map matching trips: 45%|████▌ | 45/100 [00:05<00:07, 7.40it/s]
Map matching trips: 53%|█████▎ | 53/100 [00:05<00:04, 11.05it/s]
Map matching trips: 62%|██████▏ | 62/100 [00:05<00:02, 13.69it/s]
Map matching trips: 64%|██████▍ | 64/100 [00:06<00:02, 12.69it/s]
Map matching trips: 66%|██████▌ | 66/100 [00:06<00:03, 9.19it/s]
Map matching trips: 69%|██████▉ | 69/100 [00:07<00:03, 8.86it/s]
Map matching trips: 70%|███████ | 70/100 [00:07<00:04, 6.63it/s]
Map matching trips: 73%|███████▎ | 73/100 [00:07<00:03, 6.80it/s]
Map matching trips: 76%|███████▌ | 76/100 [00:08<00:03, 6.77it/s]
Map matching trips: 79%|███████▉ | 79/100 [00:08<00:02, 7.49it/s]
Map matching trips: 80%|████████ | 80/100 [00:08<00:03, 6.47it/s]
Map matching trips: 93%|█████████▎| 93/100 [00:09<00:00, 13.34it/s]
Map matching trips: 95%|█████████▌| 95/100 [00:09<00:00, 11.51it/s]
Map matching trips: 100%|██████████| 100/100 [00:09<00:00, 10.15it/s]
for trip in mmatcher.trips:
if trip.success:
break
import folium
import geopandas as gpd
import numpy as np
Create a geometry list from the GeoDataFrame
trace = trip.trace.to_crs(4326)
geo_df_list = [[point.xy[1][0], point.xy[0][0], ts] for point, ts in zip(trace.geometry, trace.timestamp)]
result_layer = folium.FeatureGroup("Map-match result")
trace_layer = folium.FeatureGroup("GPS traces")
# Iterate through list and add a marker for each GPS ping.
i = 0
for lat, lng, ts in geo_df_list:
trace_layer.add_child(
folium.CircleMarker(
location=[lat, lng],
radius=1,
fill=True, # Set fill to True
color="black",
tooltip=str(ts),
fill_opacity=1.0,
)
)
gdf = gpd.GeoDataFrame({"d": [1]}, geometry=[trip.path_shape], crs=3857).to_crs(4326).explode(ignore_index=True)
for _, rec in gdf.iterrows():
coords = rec.geometry.xy
coordinates = [[y, x] for x, y in zip(coords[0], coords[1])]
folium.PolyLine(coordinates, weight=5, color="red").add_to(result_layer)
map = folium.Map(location=[np.mean(coords[1]), np.mean(coords[0])], tiles="OpenStreetMap", zoom_start=15)
result_layer.add_to(map)
trace_layer.add_to(map)
folium.LayerControl(position="bottomright").add_to(map)
map
trip.result
Total running time of the script: (0 minutes 12.636 seconds)