import r5py
import pandas as pd
import geopandas
import contextily as cx
from lokigi.travel_utils import process_uk_network, prepare_valhalla_network, \
build_time_matrix_valhalla, WayInspector, \
valhalla_audit_route_speeds, valhalla_detailed_route, \
valhalla_maneuvers_to_gdfModifying speed data in OSM files
Living in rural Devon, we are surrounded by many roads that have a nominal speed limit of 60mph on which that would be a wholly inadvisable speed to travel, with likely speeds generally falling closer to the 20-40mph range.
For some journeys, this could have a significant impact when calculating the journey time using r5py and valhalla, which (presumably) assume free-flowing traffic at the maximum permitted speed for the road.
If you’re a bilingual R/Python user, you could choose to switch over to r5r at this point as they natively support modifying max car speeds, both at a granular level or applying a more general scaling factor to certain types of roads.
process_uk_network(
"../../datasets/devon-260422.osm.pbf",
"../../datasets/devon-260422-modified.osm.pbf",
debug=True,
minor_road_cap=5,
debug_limit=50
)Reading from C:\lokigi\examples\datasets\devon-260422.osm.pbf
Will write to C:\lokigi\examples\datasets\devon-260422-modified.osm.pbf
Processing C:\lokigi\examples\datasets\devon-260422.osm.pbf...
[WAY 2252] ALL TAGS:
highway: residential
lit: yes
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
name: Holland Road
[WAY 2252] MAXSPEED-RELATED TAGS:
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
[WAY 2252] residential | original='30 mph' (parsed=30.0) -> new='5.0 (5 mph)' | reasons=['minor road cap -> 5'] | inferred_missing=False
[WAY 2253] ALL TAGS:
highway: tertiary
lanes: 2
lit: yes
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
name: Bradham Lane
surface: asphalt
[WAY 2253] MAXSPEED-RELATED TAGS:
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
[WAY 2253] tertiary | original='30 mph' (parsed=30.0) -> new='5.0 (5 mph)' | reasons=['minor road cap -> 5'] | inferred_missing=False
[WAY 2255] ALL TAGS:
foot: yes
highway: cycleway
segregated: yes
smoothness: good
surface: asphalt
[WAY 2256] ALL TAGS:
foot: yes
highway: cycleway
lit: no
railway: abandoned
segregated: no
smoothness: good
surface: asphalt
[WAY 2470] ALL TAGS:
highway: service
[WAY 2470] service | original='None' (parsed=60.0) -> new='5.0 (5 mph)' | reasons=['minor road cap -> 5'] | inferred_missing=True
[WAY 2471] ALL TAGS:
highway: tertiary
lanes: 2
lit: yes
maxspeed: 20 mph
name: Withycombe Village Road
sidewalk:both: separate
surface: asphalt
[WAY 2471] MAXSPEED-RELATED TAGS:
maxspeed: 20 mph
[WAY 2471] tertiary | original='20 mph' (parsed=20.0) -> new='5.0 (5 mph)' | reasons=['minor road cap -> 5'] | inferred_missing=False
Debug output truncated at 50/50 changes
Done! Saved to C:\lokigi\examples\datasets\devon-260422-modified.osm.pbf
Total Changes made: 134159
And let’s repeat this applying a simple multiplier for traffic.
process_uk_network(
"../../datasets/devon-260422.osm.pbf",
"../../datasets/devon-260422-modified-traffic.osm.pbf",
debug=True,
traffic_multiplier=0.6, # Lower = slower max speed assumed
debug_limit=50
)Reading from C:\lokigi\examples\datasets\devon-260422.osm.pbf
Will write to C:\lokigi\examples\datasets\devon-260422-modified-traffic.osm.pbf
Processing C:\lokigi\examples\datasets\devon-260422.osm.pbf...
[WAY 2252] ALL TAGS:
highway: residential
lit: yes
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
name: Holland Road
[WAY 2252] MAXSPEED-RELATED TAGS:
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
[WAY 2252] residential | original='30 mph' (parsed=30.0) -> new='18.0 (18 mph)' | reasons=['traffic multiplier x0.6'] | inferred_missing=False
[WAY 2253] ALL TAGS:
highway: tertiary
lanes: 2
lit: yes
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
name: Bradham Lane
surface: asphalt
[WAY 2253] MAXSPEED-RELATED TAGS:
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
[WAY 2253] tertiary | original='30 mph' (parsed=30.0) -> new='18.0 (18 mph)' | reasons=['traffic multiplier x0.6'] | inferred_missing=False
[WAY 2255] ALL TAGS:
foot: yes
highway: cycleway
segregated: yes
smoothness: good
surface: asphalt
[WAY 2256] ALL TAGS:
foot: yes
highway: cycleway
lit: no
railway: abandoned
segregated: no
smoothness: good
surface: asphalt
[WAY 2470] ALL TAGS:
highway: service
[WAY 2470] service | original='None' (parsed=60.0) -> new='18.0 (18 mph)' | reasons=['minor road cap -> 30', 'traffic multiplier x0.6'] | inferred_missing=True
[WAY 2471] ALL TAGS:
highway: tertiary
lanes: 2
lit: yes
maxspeed: 20 mph
name: Withycombe Village Road
sidewalk:both: separate
surface: asphalt
[WAY 2471] MAXSPEED-RELATED TAGS:
maxspeed: 20 mph
[WAY 2471] tertiary | original='20 mph' (parsed=20.0) -> new='12.0 (12 mph)' | reasons=['traffic multiplier x0.6'] | inferred_missing=False
Debug output truncated at 50/50 changes
Done! Saved to C:\lokigi\examples\datasets\devon-260422-modified-traffic.osm.pbf
Total Changes made: 141920
Confirming the change has worked
Let’s load this modified file back in to confirm the change has taken.
inspector = WayInspector([
2253 # from the debug output
])Original File
inspector.apply_file("../../datasets/devon-260422.osm.pbf")
================================================================================
WAY 2253
highway: tertiary
maxspeed: 30 mph
-- maxspeed-related tags --
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
-- all tags --
highway: tertiary
lanes: 2
lit: yes
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
name: Bradham Lane
surface: asphalt
Modified file
inspector.apply_file("../../datasets/devon-260422-modified.osm.pbf")
================================================================================
WAY 2253
highway: tertiary
maxspeed: 5 mph
-- maxspeed-related tags --
maxspeed: 5 mph
maxspeed:motorcar: 5 mph
-- all tags --
highway: tertiary
lanes: 2
lit: yes
maxspeed: 5 mph
maxspeed:motorcar: 5 mph
name: Bradham Lane
surface: asphalt
And our traffic file:
inspector.apply_file("../../datasets/devon-260422-modified-traffic.osm.pbf")
================================================================================
WAY 2253
highway: tertiary
maxspeed: 18 mph
-- maxspeed-related tags --
maxspeed: 18 mph
maxspeed:motorcar: 18 mph
-- all tags --
highway: tertiary
lanes: 2
lit: yes
maxspeed: 18 mph
maxspeed:motorcar: 18 mph
name: Bradham Lane
surface: asphalt
Trying this out
Let’s now show the impact of this change. First, let’s do the calculation on the unedited file.
Generating origins and destinations in the expected format
Let’s just calculate a single route we know covers a lot of minor roads.
Travelling from Cullompton to Cheriton Fitzpaine takes us along a large number of minor roads, so is a good test case.
Let’s travel from EX15 1HN to EX17 4JG.
origins = pd.DataFrame([{'id':'EX15 1HN', 'longitude': -3.3964515912457207, 'latitude': 50.85510704952628},
])
origins = geopandas.GeoDataFrame(
origins,
geometry = geopandas.points_from_xy(
origins['longitude'],
origins['latitude']
),
crs = 'EPSG:4326'
)
origins| id | longitude | latitude | geometry | |
|---|---|---|---|---|
| 0 | EX15 1HN | -3.396452 | 50.855107 | POINT (-3.39645 50.85511) |
destinations = pd.DataFrame([{'id':'EX17 4JG', 'longitude': -3.6102812023506217, 'latitude': 50.844712763862496},
{'id':'Exeter Airport', 'longitude': -3.413323770890914, 'latitude':50.73714162801647},
{'id': "Cornish Arms Tavistock", 'longitude': -4.146750479096123, 'latitude': 50.551448737522115}])
destinations = geopandas.GeoDataFrame(
destinations,
geometry = geopandas.points_from_xy(
destinations['longitude'],
destinations['latitude']
),
crs = 'EPSG:4326'
)
destinations| id | longitude | latitude | geometry | |
|---|---|---|---|---|
| 0 | EX17 4JG | -3.610281 | 50.844713 | POINT (-3.61028 50.84471) |
| 1 | Exeter Airport | -3.413324 | 50.737142 | POINT (-3.41332 50.73714) |
| 2 | Cornish Arms Tavistock | -4.146750 | 50.551449 | POINT (-4.14675 50.55145) |
Routingpy
First, let’s calculate the travel for our unedited pbf file.
transport_network = r5py.TransportNetwork(
"../../datasets/devon-260422.osm.pbf",
)
travel_time_matrix_car = r5py.TravelTimeMatrix(
transport_network,
origins=origins,
destinations=destinations,
transport_modes=[r5py.TransportMode.CAR]
)travel_time_matrix_car| from_id | to_id | travel_time | |
|---|---|---|---|
| 0 | EX15 1HN | EX17 4JG | 28 |
| 1 | EX15 1HN | Exeter Airport | 28 |
| 2 | EX15 1HN | Cornish Arms Tavistock | 62 |
Comparing these with real-world travel times, it looks like they’d be reasonably accurate for early morning free-flowing traffic, though optimistic in some cases and pessimistic in others.



travel_time_matrix_car_valhalla = build_time_matrix_valhalla(
origins_gdf=origins,
destinations_gdf=destinations,
valhalla_config_path="../../datasets/devon-260422_valhalla.json",
costing="auto"
)Let’s take a look at a detailed breakdown of this journey.
This point-to-point router isn’t really r5py’s strong point! So these routes may look a bit squiffy - but they do show us something useful for our experiments, so I’ve left it in.
This is explained in the following github issues: https://github.com/conveyal/r5/issues/863, https://github.com/r5py/r5py/issues/386
We haven’t used the point-to-point routing server for many years and it is not actively maintained. This dates from a time when we were exploring use of R5 as a replacement for OpenTripPlanner, but there has since been a clearer division of roles between the two projects with OpenTripPlanner 2 handling passenger-facing and point-to-point routing, while R5 is specialized in many-to-many urban analytics use cases. The point-to-point routing code paths do work somewhat differently than the one-to-many routing we use heavily for travel time mapping and accessibility calculations. We have not (yet) removed the point-to-point functionality in case anyone finds it useful, but realistically we probably won’t spend time exploring issues with this part of the codebase.
detailed_itineraries = r5py.DetailedItineraries(
transport_network,
origins=origins,
destinations=destinations,
transport_modes=[r5py.TransportMode.CAR],
snap_to_network=True,
)
detailed_itineraries| from_id | to_id | option | segment | transport_mode | departure_time | distance | travel_time | wait_time | feed | agency_id | route_id | start_stop_id | end_stop_id | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | EX15 1HN | EX17 4JG | 0 | 0 | TransportMode.CAR | NaT | 20403.065 | 0 days 00:35:49 | 0 days | None | None | None | None | None | LINESTRING (-3.39673 50.85504, -3.39672 50.855... |
| 1 | EX15 1HN | Exeter Airport | 0 | 0 | TransportMode.CAR | NaT | 20527.246 | 0 days 00:26:13 | 0 days | None | None | None | None | None | LINESTRING (-3.39673 50.85539, -3.39671 50.855... |
| 2 | EX15 1HN | Cornish Arms Tavistock | 0 | 0 | TransportMode.CAR | NaT | 86600.881 | 0 days 01:59:35 | 0 days | None | None | None | None | None | LINESTRING (-3.39673 50.85504, -3.39672 50.855... |
ax = detailed_itineraries.plot(column="to_id")
cx.add_basemap(
ax, # the figure we created using our plot method
crs=detailed_itineraries.crs.to_string(), # we can pull the CRS out of the geodataframe!
)
Repeating this with the modified matrix
Now let’s repeat this with our new matrix.
transport_network_modified = r5py.TransportNetwork(
"../../datasets/devon-260422-modified.osm.pbf",
)Our travel times appear to be unchanged.
travel_time_matrix_car_modified = r5py.TravelTimeMatrix(
transport_network_modified,
origins=origins,
destinations=destinations,
transport_modes=[r5py.TransportMode.CAR]
)
travel_time_matrix_car_modified| from_id | to_id | travel_time | |
|---|---|---|---|
| 0 | EX15 1HN | EX17 4JG | 28 |
| 1 | EX15 1HN | Exeter Airport | 28 |
| 2 | EX15 1HN | Cornish Arms Tavistock | 62 |
What about the detailed routes - even if they’re probably not right?
detailed_itineraries_modified = r5py.DetailedItineraries(
transport_network_modified,
origins=origins,
destinations=destinations,
transport_modes=[r5py.TransportMode.CAR],
snap_to_network=True,
)These have changed!
detailed_itineraries_modified| from_id | to_id | option | segment | transport_mode | departure_time | distance | travel_time | wait_time | feed | agency_id | route_id | start_stop_id | end_stop_id | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | EX15 1HN | EX17 4JG | 0 | 0 | TransportMode.CAR | NaT | 21388.334 | 0 days 00:35:47 | 0 days | None | None | None | None | None | LINESTRING (-3.39673 50.85504, -3.39672 50.855... |
| 1 | EX15 1HN | Exeter Airport | 0 | 0 | TransportMode.CAR | NaT | 20527.246 | 0 days 00:32:57 | 0 days | None | None | None | None | None | LINESTRING (-3.39673 50.85539, -3.39671 50.855... |
| 2 | EX15 1HN | Cornish Arms Tavistock | 0 | 0 | TransportMode.CAR | NaT | 86600.881 | 0 days 01:58:39 | 0 days | None | None | None | None | None | LINESTRING (-3.39673 50.85504, -3.39672 50.855... |
ax = detailed_itineraries_modified.plot(column="to_id")
cx.add_basemap(
ax, # the figure we created using our plot method
crs=detailed_itineraries_modified.crs.to_string(), # we can pull the CRS out of the geodataframe!
)
Repeating with our traffic-altered file
Finally, let’s repeat with our traffic-altered file.
transport_network_modified_traffic = r5py.TransportNetwork(
"../../datasets/devon-260422-modified-traffic.osm.pbf",
)Once again, our travel matrix times are unchanged.
travel_time_matrix_car_modified_traffic = r5py.TravelTimeMatrix(
transport_network_modified_traffic,
origins=origins,
destinations=destinations,
transport_modes=[r5py.TransportMode.CAR]
)
travel_time_matrix_car_modified| from_id | to_id | travel_time | |
|---|---|---|---|
| 0 | EX15 1HN | EX17 4JG | 28 |
| 1 | EX15 1HN | Exeter Airport | 28 |
| 2 | EX15 1HN | Cornish Arms Tavistock | 62 |
But our detailed itineraries have changed.
detailed_itineraries_modified_traffic = r5py.DetailedItineraries(
transport_network_modified_traffic,
origins=origins,
destinations=destinations,
transport_modes=[r5py.TransportMode.CAR],
snap_to_network=True,
)detailed_itineraries_modified_traffic| from_id | to_id | option | segment | transport_mode | departure_time | distance | travel_time | wait_time | feed | agency_id | route_id | start_stop_id | end_stop_id | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | EX15 1HN | EX17 4JG | 0 | 0 | TransportMode.CAR | NaT | 21388.334 | 0 days 00:26:54 | 0 days | None | None | None | None | None | LINESTRING (-3.39673 50.85504, -3.39672 50.855... |
| 1 | EX15 1HN | Exeter Airport | 0 | 0 | TransportMode.CAR | NaT | 20527.246 | 0 days 00:25:06 | 0 days | None | None | None | None | None | LINESTRING (-3.39673 50.85539, -3.39671 50.855... |
| 2 | EX15 1HN | Cornish Arms Tavistock | 0 | 0 | TransportMode.CAR | NaT | 85051.652 | 0 days 01:29:07 | 0 days | None | None | None | None | None | LINESTRING (-3.39673 50.85504, -3.39672 50.855... |
ax = detailed_itineraries_modified_traffic.plot(column="to_id")
cx.add_basemap(
ax, # the figure we created using our plot method
crs=detailed_itineraries_modified_traffic.crs.to_string(), # we can pull the CRS out of the geodataframe!
)
It looks like routingpy uses some other way of calculating travel time when using its matrix function.
And they’re not bad! But it does mean we won’t be able to use this method for things like traffic modifications either.
Valhalla
Let’s compare with valhalla, a routing engine that’s much more focussed on car travel times.
In the past, valhalla had to be set up in a fairly daunting way, but we now have the pyvalhalla option, which is much more approachable!
prepare_valhalla_network(
osm_path="../../datasets/devon-260422.osm.pbf",
output_dir="../../datasets/",
output_name="devon-260422_valhalla.json"
)Using existing Valhalla build
{'config_path': 'C:\\lokigi\\examples\\datasets\\devon-260422_valhalla.json.json',
'tile_dir': 'C:\\lokigi\\examples\\datasets\\devon-260422_valhalla.json_tiles',
'traffic_path': 'C:\\lokigi\\examples\\datasets\\devon-260422_valhalla.json_traffic.tar'}
travel_time_matrix_car_valhalla = build_time_matrix_valhalla(
origins_gdf=origins,
destinations_gdf=destinations,
valhalla_config_path="../../datasets/devon-260422_valhalla.json",
costing="auto"
)travel_time_matrix_car_valhalla| from_id | to_id | travel_time_minutes | distance_km | |
|---|---|---|---|---|
| 0 | EX15 1HN | EX17 4JG | 21.783333 | 26.503 |
| 1 | EX15 1HN | Exeter Airport | 14.166667 | 17.259 |
| 2 | EX15 1HN | Cornish Arms Tavistock | 54.383333 | 89.2 |
This has worked!
Although compared to google maps, it seems quite optimistic - more so than r5py was.



We can now repeat this with our modified files.
prepare_valhalla_network(
osm_path="../../datasets/devon-260422-modified.osm.pbf",
output_dir="../../datasets/",
output_name="devon-260422_valhalla-modified"
)Using existing Valhalla build
{'config_path': 'C:\\lokigi\\examples\\datasets\\devon-260422_valhalla-modified.json',
'tile_dir': 'C:\\lokigi\\examples\\datasets\\devon-260422_valhalla-modified_tiles',
'traffic_path': 'C:\\lokigi\\examples\\datasets\\devon-260422_valhalla-modified_traffic.tar'}
travel_time_matrix_car_valhalla_modified = build_time_matrix_valhalla(
origins_gdf=origins,
destinations_gdf=destinations,
valhalla_config_path="../../datasets/devon-260422_valhalla-modified.json",
costing="auto"
)This looks a little better - but it’s still optimistic, and the journey to the Cornish Arms has actually become a tiny bit faster, which is unexpected!
travel_time_matrix_car_valhalla_modified| from_id | to_id | travel_time_minutes | distance_km | |
|---|---|---|---|---|
| 0 | EX15 1HN | EX17 4JG | 24.066667 | 20.382 |
| 1 | EX15 1HN | Exeter Airport | 16.1 | 23.31 |
| 2 | EX15 1HN | Cornish Arms Tavistock | 54.35 | 89.2 |
And finally, let’s do this with our very heavy traffic file that assumed all traffic would only be travelling at 60% of the listed road speed.
prepare_valhalla_network(
osm_path="../../datasets/devon-260422-modified-traffic.osm.pbf",
output_dir="../../datasets/",
output_name="devon-260422_valhalla-modified-traffic"
)Using existing Valhalla build
{'config_path': 'C:\\lokigi\\examples\\datasets\\devon-260422_valhalla-modified-traffic.json',
'tile_dir': 'C:\\lokigi\\examples\\datasets\\devon-260422_valhalla-modified-traffic_tiles',
'traffic_path': 'C:\\lokigi\\examples\\datasets\\devon-260422_valhalla-modified-traffic_traffic.tar'}
travel_time_matrix_car_valhalla_modified = build_time_matrix_valhalla(
origins_gdf=origins,
destinations_gdf=destinations,
valhalla_config_path="../../datasets/devon-260422_valhalla-modified-traffic.json",
costing="auto"
)travel_time_matrix_car_valhalla_modified| from_id | to_id | travel_time_minutes | distance_km | |
|---|---|---|---|---|
| 0 | EX15 1HN | EX17 4JG | 35.05 | 18.699 |
| 1 | EX15 1HN | Exeter Airport | 25.466667 | 23.309 |
| 2 | EX15 1HN | Cornish Arms Tavistock | 88.566667 | 88.944 |
So we can conclude that valhalla definitely responds to the maximum speed tags in a way that routingpy doesn’t - though it’s still not a perfect fix.
Routingpy remains an extremely good option if you are interested in public transport.
Valhalla is probably the better choice if you are looking for car travel times.
Valhalla does also have the benefit of having no java requirements whatsoever - so it’s easier to install in locked down environments.
For some projects, you may end up using a mix of both!
Let’s do one more modified file to see if we can make a difference.
This time, we’ll apply our same substantial slowdown to unclassified roads.
On top of that, we’ll add the assumption that all journies are slower than the posted speed limit on average, so we’ll bring speeds down to 90% of reality.
process_uk_network(
"../../datasets/devon-260422.osm.pbf",
"../../datasets/devon-260422-combined-modified.osm.pbf",
debug=True,
traffic_multiplier=0.9, # Lower = slower max speed assumed
minor_road_cap=30,
debug_limit=100
)Reading from C:\lokigi\examples\datasets\devon-260422.osm.pbf
Will write to C:\lokigi\examples\datasets\devon-260422-combined-modified.osm.pbf
Processing C:\lokigi\examples\datasets\devon-260422.osm.pbf...
[WAY 2252] ALL TAGS:
highway: residential
lit: yes
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
name: Holland Road
[WAY 2252] MAXSPEED-RELATED TAGS:
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
[WAY 2252] residential | original='30 mph' (parsed=30.0) -> new='27.0 (27 mph)' | reasons=['traffic multiplier x0.9'] | inferred_missing=False
[WAY 2253] ALL TAGS:
highway: tertiary
lanes: 2
lit: yes
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
name: Bradham Lane
surface: asphalt
[WAY 2253] MAXSPEED-RELATED TAGS:
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
[WAY 2253] tertiary | original='30 mph' (parsed=30.0) -> new='27.0 (27 mph)' | reasons=['traffic multiplier x0.9'] | inferred_missing=False
[WAY 2255] ALL TAGS:
foot: yes
highway: cycleway
segregated: yes
smoothness: good
surface: asphalt
[WAY 2256] ALL TAGS:
foot: yes
highway: cycleway
lit: no
railway: abandoned
segregated: no
smoothness: good
surface: asphalt
[WAY 2470] ALL TAGS:
highway: service
[WAY 2470] service | original='None' (parsed=60.0) -> new='27.0 (27 mph)' | reasons=['minor road cap -> 30', 'traffic multiplier x0.9'] | inferred_missing=True
[WAY 2471] ALL TAGS:
highway: tertiary
lanes: 2
lit: yes
maxspeed: 20 mph
name: Withycombe Village Road
sidewalk:both: separate
surface: asphalt
[WAY 2471] MAXSPEED-RELATED TAGS:
maxspeed: 20 mph
[WAY 2471] tertiary | original='20 mph' (parsed=20.0) -> new='18.0 (18 mph)' | reasons=['traffic multiplier x0.9'] | inferred_missing=False
[WAY 3363] ALL TAGS:
highway: unclassified
lit: yes
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
name: Prince of Wales Drive
[WAY 3363] MAXSPEED-RELATED TAGS:
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
[WAY 3363] unclassified | original='30 mph' (parsed=30.0) -> new='27.0 (27 mph)' | reasons=['traffic multiplier x0.9'] | inferred_missing=False
[WAY 3364] ALL TAGS:
highway: unclassified
lit: yes
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
name: Prince of Wales Drive
[WAY 3364] MAXSPEED-RELATED TAGS:
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
[WAY 3364] unclassified | original='30 mph' (parsed=30.0) -> new='27.0 (27 mph)' | reasons=['traffic multiplier x0.9'] | inferred_missing=False
[WAY 3365] ALL TAGS:
highway: unclassified
maxspeed: 20 mph
maxspeed:type: GB:zone20
name: Moorfield Road
[WAY 3365] MAXSPEED-RELATED TAGS:
maxspeed: 20 mph
maxspeed:type: GB:zone20
[WAY 3365] unclassified | original='20 mph' (parsed=20.0) -> new='18.0 (18 mph)' | reasons=['traffic multiplier x0.9'] | inferred_missing=False
[WAY 3368] ALL TAGS:
highway: residential
lit: yes
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
name: Park Road
[WAY 3368] MAXSPEED-RELATED TAGS:
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
[WAY 3368] residential | original='30 mph' (parsed=30.0) -> new='27.0 (27 mph)' | reasons=['traffic multiplier x0.9'] | inferred_missing=False
[WAY 78851] ALL TAGS:
highway: residential
lit: yes
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
name: Newlands Avenue
[WAY 78851] MAXSPEED-RELATED TAGS:
maxspeed: 30 mph
maxspeed:type: GB:nsl_restricted
[WAY 78851] residential | original='30 mph' (parsed=30.0) -> new='27.0 (27 mph)' | reasons=['traffic multiplier x0.9'] | inferred_missing=False
[WAY 78856] ALL TAGS:
Debug output truncated at 100/100 changes
Done! Saved to C:\lokigi\examples\datasets\devon-260422-combined-modified.osm.pbf
Total Changes made: 141920
prepare_valhalla_network(
osm_path="../../datasets/devon-260422-combined-modified.osm.pbf",
output_dir="../../datasets/",
output_name="devon-260422_valhalla-combined-modified"
)Using existing Valhalla build
{'config_path': 'C:\\lokigi\\examples\\datasets\\devon-260422_valhalla-combined-modified.json',
'tile_dir': 'C:\\lokigi\\examples\\datasets\\devon-260422_valhalla-combined-modified_tiles',
'traffic_path': 'C:\\lokigi\\examples\\datasets\\devon-260422_valhalla-combined-modified_traffic.tar'}
travel_time_matrix_car_valhalla_final = build_time_matrix_valhalla(
origins_gdf=origins,
destinations_gdf=destinations,
valhalla_config_path="../../datasets/devon-260422_valhalla-combined-modified.json",
costing="auto"
)
travel_time_matrix_car_valhalla_final| from_id | to_id | travel_time_minutes | distance_km | |
|---|---|---|---|---|
| 0 | EX15 1HN | EX17 4JG | 23.783333 | 18.699 |
| 1 | EX15 1HN | Exeter Airport | 17.5 | 23.309 |
| 2 | EX15 1HN | Cornish Arms Tavistock | 60.383333 | 89.2 |
While this still isn’t great for one of our journies, the other two are now quite accurate.
Advanced valhalla route inspection and debugging
We can do a bit more debugging…
from valhalla import Actor
result, summary = valhalla_detailed_route(engine=Actor("../../datasets/devon-260422_valhalla-combined-modified.json"),
origin=(origins.iloc[0].latitude, origins.iloc[0].longitude),
destination=(destinations.iloc[0].latitude, destinations.iloc[0].longitude),
)
result
=== OVERALL ===
Time: 23.8 min
Distance: 11.62 miles
--- LEG 0 ---
Time: 23.8 min
Distance: 11.62 miles
Speed: 29.3 miles/h
Maneuvers:
23.279s | 0.1721 | Drive north on Shortlands Road.
177.943s | 1.3023 | Turn left onto Tiverton Road.
193.822s | 1.4366 | Bear left.
67.676s | 0.479 | Turn left.
8.794s | 0.0596 | Turn left.
41.361s | 0.2746 | Turn right.
13.657s | 0.1 | Turn left.
154.684s | 1.1414 | Turn right.
99.832s | 0.7052 | Turn right.
54.456s | 0.2516 | Turn right.
32.896s | 0.2491 | Turn right onto A396.
201.203s | 2.8471 | Turn left onto A3072.
47.666s | 0.3324 | Turn right onto Uppincott Lane.
56.956s | 0.4212 | Turn left.
240.096s | 1.7789 | Keep left at the fork.
12.825s | 0.0671 | Turn right.
0.0s | 0.0 | Your destination is on the right.
{'trip': {'locations': [{'type': 'break',
'lat': 50.855107,
'lon': -3.396451,
'side_of_street': 'right',
'original_index': 0},
{'type': 'break',
'lat': 50.844712,
'lon': -3.610281,
'side_of_street': 'right',
'original_index': 1}],
'legs': [{'maneuvers': [{'type': 2,
'instruction': 'Drive north on Shortlands Road.',
'verbal_succinct_transition_instruction': 'Drive north. Then, in 900 feet, Turn left onto Tiverton Road.',
'verbal_pre_transition_instruction': 'Drive north on Shortlands Road. Then, in 900 feet, Turn left onto Tiverton Road.',
'verbal_post_transition_instruction': 'Continue for 900 feet.',
'street_names': ['Shortlands Road'],
'bearing_after': 4,
'time': 23.279,
'length': 0.1721,
'cost': 34.167,
'begin_shape_index': 0,
'end_shape_index': 18,
'verbal_multi_cue': True,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 15,
'instruction': 'Turn left onto Tiverton Road.',
'verbal_transition_alert_instruction': 'Turn left onto Tiverton Road.',
'verbal_succinct_transition_instruction': 'Turn left.',
'verbal_pre_transition_instruction': 'Turn left onto Tiverton Road.',
'verbal_post_transition_instruction': 'Continue for 1.5 miles.',
'street_names': ['Tiverton Road'],
'bearing_before': 14,
'bearing_after': 284,
'time': 177.943,
'length': 1.3023,
'cost': 194.035,
'begin_shape_index': 18,
'end_shape_index': 107,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 16,
'instruction': 'Bear left.',
'verbal_transition_alert_instruction': 'Bear left.',
'verbal_succinct_transition_instruction': 'Bear left.',
'verbal_pre_transition_instruction': 'Bear left.',
'verbal_post_transition_instruction': 'Continue for 1.5 miles.',
'bearing_before': 338,
'bearing_after': 296,
'time': 193.822,
'length': 1.4366,
'cost': 189.706,
'begin_shape_index': 107,
'end_shape_index': 168,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 15,
'instruction': 'Turn left.',
'verbal_transition_alert_instruction': 'Turn left.',
'verbal_succinct_transition_instruction': 'Turn left.',
'verbal_pre_transition_instruction': 'Turn left.',
'verbal_post_transition_instruction': 'Continue for a half mile.',
'bearing_before': 334,
'bearing_after': 235,
'time': 67.676,
'length': 0.479,
'cost': 70.843,
'begin_shape_index': 168,
'end_shape_index': 215,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 15,
'instruction': 'Turn left.',
'verbal_transition_alert_instruction': 'Turn left.',
'verbal_succinct_transition_instruction': 'Turn left. Then, in 300 feet, Turn right.',
'verbal_pre_transition_instruction': 'Turn left. Then, in 300 feet, Turn right.',
'verbal_post_transition_instruction': 'Continue for 300 feet.',
'bearing_before': 230,
'bearing_after': 160,
'time': 8.794,
'length': 0.0596,
'cost': 11.733,
'begin_shape_index': 215,
'end_shape_index': 221,
'verbal_multi_cue': True,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 10,
'instruction': 'Turn right.',
'verbal_transition_alert_instruction': 'Turn right.',
'verbal_succinct_transition_instruction': 'Turn right.',
'verbal_pre_transition_instruction': 'Turn right.',
'verbal_post_transition_instruction': 'Continue for a quarter mile.',
'bearing_before': 140,
'bearing_after': 222,
'time': 41.361,
'length': 0.2746,
'cost': 40.804,
'begin_shape_index': 221,
'end_shape_index': 237,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 15,
'instruction': 'Turn left.',
'verbal_transition_alert_instruction': 'Turn left.',
'verbal_succinct_transition_instruction': 'Turn left.',
'verbal_pre_transition_instruction': 'Turn left.',
'verbal_post_transition_instruction': 'Continue for 500 feet.',
'bearing_before': 276,
'bearing_after': 228,
'time': 13.657,
'length': 0.1,
'cost': 16.631,
'begin_shape_index': 237,
'end_shape_index': 250,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 10,
'instruction': 'Turn right.',
'verbal_transition_alert_instruction': 'Turn right.',
'verbal_succinct_transition_instruction': 'Turn right.',
'verbal_pre_transition_instruction': 'Turn right.',
'verbal_post_transition_instruction': 'Continue for 1 mile.',
'bearing_before': 203,
'bearing_after': 251,
'time': 154.684,
'length': 1.1414,
'cost': 154.73,
'begin_shape_index': 250,
'end_shape_index': 331,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 10,
'instruction': 'Turn right.',
'verbal_transition_alert_instruction': 'Turn right.',
'verbal_succinct_transition_instruction': 'Turn right.',
'verbal_pre_transition_instruction': 'Turn right.',
'verbal_post_transition_instruction': 'Continue for a half mile.',
'bearing_before': 213,
'bearing_after': 296,
'time': 99.832,
'length': 0.7052,
'cost': 99.687,
'begin_shape_index': 331,
'end_shape_index': 386,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 10,
'instruction': 'Turn right.',
'verbal_transition_alert_instruction': 'Turn right.',
'verbal_succinct_transition_instruction': 'Turn right.',
'verbal_pre_transition_instruction': 'Turn right.',
'verbal_post_transition_instruction': 'Continue for a quarter mile.',
'bearing_before': 285,
'bearing_after': 6,
'time': 54.456,
'length': 0.2516,
'cost': 60.248,
'begin_shape_index': 386,
'end_shape_index': 414,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 10,
'instruction': 'Turn right onto A396.',
'verbal_transition_alert_instruction': 'Turn right onto A396.',
'verbal_succinct_transition_instruction': 'Turn right.',
'verbal_pre_transition_instruction': 'Turn right onto A396.',
'verbal_post_transition_instruction': 'Continue for a quarter mile.',
'street_names': ['A396'],
'bearing_before': 303,
'bearing_after': 349,
'time': 32.896,
'length': 0.2491,
'cost': 51.46,
'begin_shape_index': 414,
'end_shape_index': 436,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 15,
'instruction': 'Turn left onto A3072.',
'verbal_transition_alert_instruction': 'Turn left onto A3072.',
'verbal_succinct_transition_instruction': 'Turn left.',
'verbal_pre_transition_instruction': 'Turn left onto A3072.',
'verbal_post_transition_instruction': 'Continue for 3 miles.',
'street_names': ['A3072'],
'bearing_before': 357,
'bearing_after': 288,
'time': 201.203,
'length': 2.8471,
'cost': 186.702,
'begin_shape_index': 436,
'end_shape_index': 636,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 10,
'instruction': 'Turn right onto Uppincott Lane.',
'verbal_transition_alert_instruction': 'Turn right onto Uppincott Lane.',
'verbal_succinct_transition_instruction': 'Turn right.',
'verbal_pre_transition_instruction': 'Turn right onto Uppincott Lane.',
'verbal_post_transition_instruction': 'Continue for a quarter mile.',
'street_names': ['Uppincott Lane'],
'bearing_before': 273,
'bearing_after': 344,
'time': 47.666,
'length': 0.3324,
'cost': 56.611,
'begin_shape_index': 636,
'end_shape_index': 656,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 15,
'instruction': 'Turn left.',
'verbal_transition_alert_instruction': 'Turn left.',
'verbal_succinct_transition_instruction': 'Turn left.',
'verbal_pre_transition_instruction': 'Turn left.',
'verbal_post_transition_instruction': 'Continue for a half mile.',
'bearing_before': 356,
'bearing_after': 305,
'time': 56.956,
'length': 0.4212,
'cost': 57.667,
'begin_shape_index': 656,
'end_shape_index': 679,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 24,
'instruction': 'Keep left at the fork.',
'verbal_transition_alert_instruction': 'Keep left at the fork.',
'verbal_pre_transition_instruction': 'Keep left at the fork.',
'verbal_post_transition_instruction': 'Continue for 2 miles.',
'bearing_before': 293,
'bearing_after': 279,
'time': 240.096,
'length': 1.7789,
'cost': 251.375,
'begin_shape_index': 679,
'end_shape_index': 824,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 10,
'instruction': 'Turn right.',
'verbal_transition_alert_instruction': 'Turn right.',
'verbal_succinct_transition_instruction': 'Turn right. Then, in 400 feet, Your destination will be on the right.',
'verbal_pre_transition_instruction': 'Turn right. Then, in 400 feet, Your destination will be on the right.',
'verbal_post_transition_instruction': 'Continue for 400 feet.',
'bearing_before': 242,
'bearing_after': 319,
'time': 12.825,
'length': 0.0671,
'cost': 17.142,
'begin_shape_index': 824,
'end_shape_index': 837,
'verbal_multi_cue': True,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 5,
'instruction': 'Your destination is on the right.',
'verbal_transition_alert_instruction': 'Your destination will be on the right.',
'verbal_pre_transition_instruction': 'Your destination is on the right.',
'bearing_before': 282,
'time': 0.0,
'length': 0.0,
'cost': 0.0,
'begin_shape_index': 837,
'end_shape_index': 837,
'travel_mode': 'drive',
'travel_type': 'car'}],
'summary': {'has_time_restrictions': False,
'has_toll': False,
'has_highway': False,
'has_ferry': False,
'min_lat': 50.836754,
'min_lon': -3.610295,
'max_lat': 50.867483,
'max_lon': -3.396712,
'time': 1427.153,
'length': 11.6191,
'cost': 1493.55},
'shape': '}k}~_BhfinEWAqFWqG\\iBZyFpAeT|B{Cx@qB`CoExJsCjJcCfImEpJsBnByBz@wBTyEa@uNyDyWwHwC`]SbCe@lGoArLsC`UqF~[cG|XyF~PoBdGiCfHoDfJ{DbLqKv[eIvR_IrSqBdGcAxDmBnHkCpLeClMk@|FYpFOhF@lFFrGPbHb@vMP|FLlDv@xWXtKBrCCpCEtAQxHgA~e@SdJStJm@lXgAfXcAbOMbB_@fE}@pF{@rG}C~VwFrd@_F|X}I~a@_Jlh@cEh[_Kvt@_Jpp@cHnh@gGbd@kDv]cD|a@wCrYsCpTgDlR{J~c@cKha@a@dAgFzMcGjSiIjWcFpLcFtJ_GrKgHfL}K~OiEpFgGvJ}DrHuAhEiDzNyKht@mGt\\uHb^gGnS}FrSqAzCuBdD_DnDaEvCkLnFaVjJaSfIeZbPY`CaKr_@cCzRyB~XsAfW@bMfA|PrB|QvSfaBjLrx@fBnQ|@hN|Adc@dAb[\\xaA`@nYh@zZ`Bdj@nLho@vNpi@bD`XpBfY`EdvAt@lkAfB~lABtm@?rl@tCv}@nAly@yBj]aDjcAkBlr@}Dp}@oKlTuOpHgEfCgA|CKdF\\jKxGzaAfB`^FlKOlD}@pEuCnIqCfKgD~YqCj_@qBxS{BpNoD~OoErPgDlKcArFqB|EgBtCmExCcM|Her@x^k^rQ}QnMd@vB~HhR`LfVpGbRvFxSxEzWzFzVlAfFtAxCpE~HrV|b@jZpw@dTfm@bHzPbP|`@r@jAv@bAtHbIbA`ATRrBlBvGpFjIrGv@n@v@t@r@v@rBbCrApBpAxBhJxPp@bAr@~@pCdD~FbHxAnB|A|BrDrFpB`DrAlBzAnB~ExFj@t@l@hAl@vA|AvD|ChI~AbDvAs@xEwA~F_F`BuAhG}H~NaTfKhPvCdH|Erj@~En_@v@dEhGbSpJtWnQbh@bO~f@tHr^jInZlC`LdAlIX~GG~EU~ElAh@~@nDhDnO~DtOxE|OvAfEpBpEfBtB|C|B~EtCjBfA|KpEfAlAdAhF^pIErLtCxb@lBvN|AjHzA|EpEjIbG~H`AzBb@tCj@tCzTbx@dJjXdTbZpAbEnE|WvIxa@lAdLIlLhGnj@w@d_@jBdc@bIrl@cBf[mBjGu@hCwAhIRvJ|CnRhD`Td@zHThVBlV|@|ChB~CzH|NfHd^zEjXbErIlHjI|EtO~BjGdBjB~BlD`AxDfBrV|AfSf@fGt@vGfJxq@|Ips@z@bFtAlEjAzBbDxFjFrInBpC~DjJ`DxIhBfKjDj[bDdY`ElZhFx[dBjJfC|KpC|J`DtIlEjKbDhLzAtHN`Md@xTf@bS~BbUbC`PtClLrZng@d_@xi@`DnCYv@qArFWbHr@`UpAtLp@nIp@|Gf@xHVtSE|MMn[`@xQlB~QxF~WrDp`@xAbQJ~DoCtS[xFHlHVrM[z_@]|DeAfGoB`K_EtQkCtF{CnGgCrKcAdJc@pKO|IiBd{@kFpzAe@vNaBjKmAfF]hE|Alr@|BbX`@xJPzQElNKrTTfKzAje@zEdk@|E~c@bAnMXlHDvDEnBg@~Ea@fEGz@uEe@wFa@yCN_Cv@uDtC_ClAoBZiBp@yQ~LyPpJ{HdGoBzCcHfMu@W_C`NkEtRaDdRiEnS}BfGqCvEqChBwFhDkIvFsGlI}C|CuCzC[pBEjBwAG{A\\mB~@wBpBgDbJqKjVsHtW}CrLwQpy@yDdHcEnFcDzBmGjC}TpDyJnCsFbGuJp\\eB`EwBxAqAVaAAoBaAYpBe@~Dk@dEQhB]dHAxMBrG?XXdMX`Ff@nFnA`JnAtKRz@Zh@rBpAxAfA~BrDjBvDrCrFhCjEbDfClDlAhFb@zCZrD~@|IvDvD|CtDvDzB|B|DjEvHtHlEpC`BdBrGpFnOzExK~@jKvClHfGpEvLbDvHxCfFrDlCtFb@pIsFtMiO~IsBxHl@pG~DdHpItTp`@zErMfTf^vGdOnQjq@zYfu@pAnCnFbJlFrKfQnYnKzR`H`SzBjK|AvTfG~zA~IvfB|Bd\\lCtVxB|NjBpH~B~GhDhH|HhOvEpMpAlF|@vG~@lJdAl_@dBpi@r@x^hBnWhCjR~CfQjVnnApDfIbClDnAhA`Ax@`Dx@nP^tOoAbEQ`GbCnHlHjOlWrIvLnCpD|AxDfAfEv@nFt@vL`AjJz@bF~AdFtEbEl]~[xSfQ|ItCjW`I`MvEpJfCdJjDlFvBzDpBnItGrD`FlDjG`CtFnAtDbAhDtArG|C`RjDfTzGjb@rC|SfJvy@vEza@tBzNtBvIjCtHvBbFfCbEfNzOzG`IpEvI|B`IlE~MlD~IvDxGbClC~AxA`Aj@tCxArMhEdLdE``@fO~HvD|IhF`M`JvCvBbEnB`KhE~EdCbExCdC`CrB|CjB~E|AhFzAnM|A~UrDpo@vB|WbDrZ~Ef^dGlZdK`b@zLdh@~CjM`CxHbDbI~JpQxUdc@lI~NjHfJ|GzGnEhIhFdLnD`MxLll@|Ltv@tDfVpFvYhEbWhFn]hBdO`AxJ^bF^vEj@`Ih@~Mf@hSJrOGpNaAhi@yBhnA@p{@Bxb@uAt|@{@|XUvRqADsBl@iGbI}C|Iqb@ju@cN`^sOlZuGpFcM_@gJVuYtHmPx@sTT}N`DcKrHiKh@eU{J{CcAiAT}@x@iAtCo}@lxCsOzd@aQ|h@q@|CiB`KkCxQyC~OiDxMmHbUkIhXyApGwAvJeAdJ}@|KiB|WuBtQeDbUoA|F}DxKoDxIgDpMyB~Li@jL}@vb@mBba@gA~NuB`RcEhX{B|O}Hnl@_Dt]_AhZNhe@Jje@y@bb@y@xf@c@`Oo@xOGlHGbJBhIErQXlJd@jKJnH_@bP]xHe@|Gc@xK_@pe@m@jUiCxp@}@xT?xM\\`Xw@lVf@d\\b@jMJtFR~KC|IQ|KWdVc@tJw@zQQdTJnI^zD|@bHzBxIjCzJ|@zEP`E@lK[tKSvJiAzRkArNuB`RcCnR}@vFiCrLuAlK}@fKoAlRsA|QgApK}AtH{BzGkInRqJjVyFxQsF~QeD`NqC`NwCvPwBtO{AfQ_AxLcBh^oAj[MdNCjFAjB^~Jh@|GrAhN`BrP~Aj[MlPcCbi@ObDA`CPjHn@dN~AvHbGrRp@dBv@fCbI|XhCdLhAvFlAhI~AvKbDx[|C~]fC|RhB`Nx@hGrB`RvAxTXfI^hPD|FI|FJhIf@bKxAlNnBtRhAxLbAfKzDxXt@|FxDtSlB~SbBnOlCjVzAjN^nDpAjL`BrTj@rIX~ELrU^~MHhLb@r[BvO\\|MTnQp@bMp@bIv@fGbArHdDjRrDxSdAfDsGvJmCrB{CdAmAt@qAp@m@`@a@p@m@|AuB|Im@rD{@bF{@|JWjE'}],
'summary': {'has_time_restrictions': False,
'has_toll': False,
'has_highway': False,
'has_ferry': False,
'min_lat': 50.836754,
'min_lon': -3.610295,
'max_lat': 50.867483,
'max_lon': -3.396712,
'time': 1427.153,
'length': 11.6191,
'cost': 1493.55},
'status_message': 'Found route between points',
'status': 0,
'units': 'miles',
'language': 'en-US'}}
summary{'total_time_s': 1427.153,
'total_dist': 11.6191,
'legs': [{'leg_index': 0,
'time_s': 1427.153,
'distance': 11.6191,
'speed': 29.309233137582304}]}
valhalla_audit_route_speeds(result)
=== ROUTE SUMMARY ===
Total time: 23.8 min
Total dist: 11.62 km
=== SPEED DISTRIBUTION ===
< 20 km/h (urban/stop-start) | time: 1.1 min ( 4.7%) | dist: 0.3 km ( 2.7%)
20–40 km/h (dense urban) | time: 19.3 min ( 81.2%) | dist: 8.5 km ( 72.8%)
40–60 km/h (suburban) | time: 3.4 min ( 14.1%) | dist: 2.8 km ( 24.5%)
60–90 km/h (A-road) | time: 0.0 min ( 0.0%) | dist: 0.0 km ( 0.0%)
90+ km/h (motorway-like) | time: 0.0 min ( 0.0%) | dist: 0.0 km ( 0.0%)
{'total_time_s': 1427.146,
'total_dist_km': 11.6182,
'band_stats': {'20–40 km/h (dense urban)': {'time': 1158.6619999999998,
'dist': 8.452399999999999},
'< 20 km/h (urban/stop-start)': {'time': 67.281, 'dist': 0.3187},
'40–60 km/h (suburban)': {'time': 201.203, 'dist': 2.8471},
'60–90 km/h (A-road)': {'time': 0.0, 'dist': 0.0},
'90+ km/h (motorway-like)': {'time': 0.0, 'dist': 0.0}}}
result_gdf = valhalla_maneuvers_to_gdf(result)
ax = result_gdf.plot(column="speed_kmh", legend=True, figsize=(8,4))
cx.add_basemap(
ax, # the figure we created using our plot method
crs=result_gdf.crs.to_string(), # we can pull the CRS out of the geodataframe!
)
# Grab the auto-generated attribution object from matplotlib axes
txt = ax.texts[-1]
# Adjust its position to outside the map, just below the bottom edge
txt.set_position([0.5, -0.1])
txt.set_ha('center') # Center the text
txt.set_va('top')
Let’s repeat this for our other routes.
To Exeter Airport
result, summary = valhalla_detailed_route(engine=Actor("../../datasets/devon-260422_valhalla-combined-modified.json"),
origin=(origins.iloc[0].latitude, origins.iloc[0].longitude),
destination=(destinations.iloc[1].latitude, destinations.iloc[1].longitude),
)
result
=== OVERALL ===
Time: 17.5 min
Distance: 14.48 miles
--- LEG 0 ---
Time: 17.5 min
Distance: 14.48 miles
Speed: 49.6 miles/h
Maneuvers:
23.279s | 0.1721 | Drive north on Shortlands Road.
32.749s | 0.2025 | Turn right onto Tiverton Road.
17.196s | 0.118 | Turn left onto High Street/B3181.
23.658s | 0.1584 | Turn right onto Station Road/B3181.
1.606s | 0.0118 | Enter the roundabout and take the 1st exit onto Station Road/B3181.
9.096s | 0.0671 | Exit the roundabout onto Station Road/B3181.
9.91s | 0.0223 | Enter the roundabout and take the 2nd exit onto Station Road/B3181.
17.397s | 0.1273 | Exit the roundabout onto Station Road/B3181.
3.722s | 0.0223 | Enter the roundabout and take the 3rd exit onto Station Road/A373.
6.367s | 0.0466 | Exit the roundabout onto Station Road/A373. Continue on A373.
574.004s | 9.9431 | Turn right to take the M5 ramp.
16.461s | 0.2858 | Take exit 29 toward Honiton/Exeter Airport.
73.52s | 1.1346 | Bear left onto A30/Honiton Road. Continue on A30.
17.467s | 0.2317 | Take the exit.
2.167s | 0.0273 | Enter the roundabout and take the 1st exit onto Clyst Honiton Bypass/B3174.
134.147s | 1.2595 | Exit the roundabout onto Clyst Honiton Bypass/B3174. Continue on B3174.
3.628s | 0.0242 | Enter the roundabout and take the 2nd exit onto B3174.
17.728s | 0.1764 | Exit the roundabout onto B3174.
66.635s | 0.4524 | Turn right onto Treasbeare Lane.
0.0s | 0.0 | Your destination is on the right.
{'trip': {'locations': [{'type': 'break',
'lat': 50.855107,
'lon': -3.396451,
'side_of_street': 'right',
'original_index': 0},
{'type': 'break',
'lat': 50.737141,
'lon': -3.413323,
'side_of_street': 'right',
'original_index': 1}],
'legs': [{'maneuvers': [{'type': 2,
'instruction': 'Drive north on Shortlands Road.',
'verbal_succinct_transition_instruction': 'Drive north. Then, in 900 feet, Turn right onto Tiverton Road.',
'verbal_pre_transition_instruction': 'Drive north on Shortlands Road. Then, in 900 feet, Turn right onto Tiverton Road.',
'verbal_post_transition_instruction': 'Continue for 900 feet.',
'street_names': ['Shortlands Road'],
'bearing_after': 4,
'time': 23.279,
'length': 0.1721,
'cost': 34.167,
'begin_shape_index': 0,
'end_shape_index': 18,
'verbal_multi_cue': True,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 10,
'instruction': 'Turn right onto Tiverton Road.',
'verbal_transition_alert_instruction': 'Turn right onto Tiverton Road.',
'verbal_succinct_transition_instruction': 'Turn right.',
'verbal_pre_transition_instruction': 'Turn right onto Tiverton Road.',
'verbal_post_transition_instruction': 'Continue for a quarter mile.',
'street_names': ['Tiverton Road'],
'bearing_before': 14,
'bearing_after': 104,
'time': 32.749,
'length': 0.2025,
'cost': 44.81,
'begin_shape_index': 18,
'end_shape_index': 29,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 15,
'instruction': 'Turn left onto High Street/B3181.',
'verbal_transition_alert_instruction': 'Turn left onto High Street.',
'verbal_succinct_transition_instruction': 'Turn left.',
'verbal_pre_transition_instruction': 'Turn left onto High Street, B3181.',
'verbal_post_transition_instruction': 'Continue for 600 feet.',
'street_names': ['High Street', 'B3181'],
'bearing_before': 83,
'bearing_after': 4,
'time': 17.196,
'length': 0.118,
'cost': 27.109,
'begin_shape_index': 29,
'end_shape_index': 44,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 10,
'instruction': 'Turn right onto Station Road/B3181.',
'verbal_transition_alert_instruction': 'Turn right onto Station Road.',
'verbal_succinct_transition_instruction': 'Turn right.',
'verbal_pre_transition_instruction': 'Turn right onto Station Road, B3181.',
'verbal_post_transition_instruction': 'Continue for 800 feet.',
'street_names': ['Station Road', 'B3181'],
'bearing_before': 14,
'bearing_after': 80,
'time': 23.658,
'length': 0.1584,
'cost': 31.815,
'begin_shape_index': 44,
'end_shape_index': 63,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 26,
'instruction': 'Enter the roundabout and take the 1st exit onto Station Road/B3181.',
'verbal_transition_alert_instruction': 'Enter the roundabout and take the 1st exit onto Station Road.',
'verbal_succinct_transition_instruction': 'Enter the roundabout and take the 1st exit.',
'verbal_pre_transition_instruction': 'Enter the roundabout and take the 1st exit onto Station Road, B3181.',
'bearing_before': 51,
'bearing_after': 39,
'time': 1.606,
'length': 0.0118,
'cost': 7.375,
'begin_shape_index': 63,
'end_shape_index': 68,
'roundabout_exit_count': 1,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 27,
'instruction': 'Exit the roundabout onto Station Road/B3181.',
'verbal_succinct_transition_instruction': 'Exit the roundabout.',
'verbal_pre_transition_instruction': 'Exit the roundabout onto Station Road, B3181.',
'verbal_post_transition_instruction': 'Continue for 400 feet.',
'street_names': ['Station Road', 'B3181'],
'bearing_before': 39,
'bearing_after': 19,
'time': 9.096,
'length': 0.0671,
'cost': 14.64,
'begin_shape_index': 68,
'end_shape_index': 80,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 26,
'instruction': 'Enter the roundabout and take the 2nd exit onto Station Road/B3181.',
'verbal_transition_alert_instruction': 'Enter the roundabout and take the 2nd exit onto Station Road.',
'verbal_succinct_transition_instruction': 'Enter the roundabout and take the 2nd exit.',
'verbal_pre_transition_instruction': 'Enter the roundabout and take the 2nd exit onto Station Road, B3181.',
'bearing_before': 57,
'bearing_after': 345,
'time': 9.91,
'length': 0.0223,
'cost': 9.038,
'begin_shape_index': 80,
'end_shape_index': 91,
'roundabout_exit_count': 2,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 27,
'instruction': 'Exit the roundabout onto Station Road/B3181.',
'verbal_succinct_transition_instruction': 'Exit the roundabout.',
'verbal_pre_transition_instruction': 'Exit the roundabout onto Station Road, B3181.',
'verbal_post_transition_instruction': 'Continue for 700 feet.',
'street_names': ['Station Road', 'B3181'],
'bearing_before': 143,
'bearing_after': 100,
'time': 17.397,
'length': 0.1273,
'cost': 27.233,
'begin_shape_index': 91,
'end_shape_index': 105,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 26,
'instruction': 'Enter the roundabout and take the 3rd exit onto Station Road/A373.',
'verbal_transition_alert_instruction': 'Enter the roundabout and take the 3rd exit onto Station Road.',
'verbal_succinct_transition_instruction': 'Enter the roundabout and take the 3rd exit.',
'verbal_pre_transition_instruction': 'Enter the roundabout and take the 3rd exit onto Station Road, A373.',
'bearing_before': 55,
'bearing_after': 47,
'time': 3.722,
'length': 0.0223,
'cost': 4.038,
'begin_shape_index': 105,
'end_shape_index': 114,
'roundabout_exit_count': 3,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 27,
'instruction': 'Exit the roundabout onto Station Road/A373. Continue on A373.',
'verbal_succinct_transition_instruction': 'Exit the roundabout. Then, in 200 feet, Turn right to take the M5 ramp.',
'verbal_pre_transition_instruction': 'Exit the roundabout onto Station Road, A373. Then, in 200 feet, Turn right to take the M5 ramp.',
'verbal_post_transition_instruction': 'Continue on A373 for 200 feet.',
'street_names': ['A373'],
'begin_street_names': ['Station Road', 'A373'],
'bearing_before': 146,
'bearing_after': 123,
'time': 6.367,
'length': 0.0466,
'cost': 6.013,
'begin_shape_index': 114,
'end_shape_index': 119,
'verbal_multi_cue': True,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 18,
'instruction': 'Turn right to take the M5 ramp.',
'verbal_transition_alert_instruction': 'Turn right to take the M5 ramp.',
'verbal_pre_transition_instruction': 'Turn right to take the M5 ramp.',
'verbal_post_transition_instruction': 'Continue for 10 miles.',
'street_names': ['M5'],
'bearing_before': 92,
'bearing_after': 167,
'time': 574.004,
'length': 9.9431,
'cost': 560.112,
'begin_shape_index': 119,
'end_shape_index': 297,
'highway': True,
'sign': {'exit_branch_elements': [{'text': 'M5'}]},
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 21,
'instruction': 'Take exit 29 toward Honiton/Exeter Airport.',
'verbal_transition_alert_instruction': 'Take exit 29.',
'verbal_pre_transition_instruction': 'Take exit 29 toward Honiton, Exeter Airport.',
'street_names': ['M5'],
'bearing_before': 186,
'bearing_after': 173,
'time': 16.461,
'length': 0.2858,
'cost': 17.625,
'begin_shape_index': 297,
'end_shape_index': 309,
'sign': {'exit_number_elements': [{'text': '29'}],
'exit_toward_elements': [{'text': 'Honiton', 'consecutive_count': 1},
{'text': 'Exeter Airport', 'consecutive_count': 1},
{'text': 'Exeter'}],
'exit_name_elements': [{'text': 'Sowton Interchange'}]},
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 16,
'instruction': 'Bear left onto A30/Honiton Road. Continue on A30.',
'verbal_transition_alert_instruction': 'Bear left onto A30.',
'verbal_succinct_transition_instruction': 'Bear left.',
'verbal_pre_transition_instruction': 'Bear left onto A30, Honiton Road.',
'verbal_post_transition_instruction': 'Continue on A30 for 1 mile.',
'street_names': ['A30'],
'begin_street_names': ['A30', 'Honiton Road'],
'bearing_before': 131,
'bearing_after': 85,
'time': 73.52,
'length': 1.1346,
'cost': 116.382,
'begin_shape_index': 309,
'end_shape_index': 344,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 21,
'instruction': 'Take the exit.',
'verbal_transition_alert_instruction': 'Take the exit.',
'verbal_pre_transition_instruction': 'Take the exit.',
'bearing_before': 95,
'bearing_after': 90,
'time': 17.467,
'length': 0.2317,
'cost': 16.567,
'begin_shape_index': 344,
'end_shape_index': 356,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 26,
'instruction': 'Enter the roundabout and take the 1st exit onto Clyst Honiton Bypass/B3174.',
'verbal_transition_alert_instruction': 'Enter the roundabout and take the 1st exit onto Clyst Honiton Bypass.',
'verbal_succinct_transition_instruction': 'Enter the roundabout and take the 1st exit.',
'verbal_pre_transition_instruction': 'Enter the roundabout and take the 1st exit onto Clyst Honiton Bypass, B3174.',
'bearing_before': 39,
'bearing_after': 7,
'time': 2.167,
'length': 0.0273,
'cost': 7.229,
'begin_shape_index': 356,
'end_shape_index': 362,
'roundabout_exit_count': 1,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 27,
'instruction': 'Exit the roundabout onto Clyst Honiton Bypass/B3174. Continue on B3174.',
'verbal_succinct_transition_instruction': 'Exit the roundabout.',
'verbal_pre_transition_instruction': 'Exit the roundabout onto Clyst Honiton Bypass, B3174.',
'verbal_post_transition_instruction': 'Continue on B3174 for 1.5 miles.',
'street_names': ['B3174'],
'begin_street_names': ['Clyst Honiton Bypass', 'B3174'],
'bearing_before': 75,
'bearing_after': 44,
'time': 134.147,
'length': 1.2595,
'cost': 143.657,
'begin_shape_index': 362,
'end_shape_index': 439,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 26,
'instruction': 'Enter the roundabout and take the 2nd exit onto B3174.',
'verbal_transition_alert_instruction': 'Enter the roundabout and take the 2nd exit onto B3174.',
'verbal_succinct_transition_instruction': 'Enter the roundabout and take the 2nd exit.',
'verbal_pre_transition_instruction': 'Enter the roundabout and take the 2nd exit onto B3174.',
'bearing_before': 17,
'bearing_after': 19,
'time': 3.628,
'length': 0.0242,
'cost': 7.799,
'begin_shape_index': 439,
'end_shape_index': 449,
'roundabout_exit_count': 2,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 27,
'instruction': 'Exit the roundabout onto B3174.',
'verbal_succinct_transition_instruction': 'Exit the roundabout.',
'verbal_pre_transition_instruction': 'Exit the roundabout onto B3174.',
'verbal_post_transition_instruction': 'Continue for 900 feet.',
'street_names': ['B3174'],
'bearing_before': 128,
'bearing_after': 109,
'time': 17.728,
'length': 0.1764,
'cost': 24.746,
'begin_shape_index': 449,
'end_shape_index': 468,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 10,
'instruction': 'Turn right onto Treasbeare Lane.',
'verbal_transition_alert_instruction': 'Turn right onto Treasbeare Lane.',
'verbal_succinct_transition_instruction': 'Turn right.',
'verbal_pre_transition_instruction': 'Turn right onto Treasbeare Lane.',
'verbal_post_transition_instruction': 'Continue for a half mile.',
'street_names': ['Treasbeare Lane'],
'bearing_before': 52,
'bearing_after': 143,
'time': 66.635,
'length': 0.4524,
'cost': 75.167,
'begin_shape_index': 468,
'end_shape_index': 488,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 5,
'instruction': 'Your destination is on the right.',
'verbal_transition_alert_instruction': 'Your destination will be on the right.',
'verbal_pre_transition_instruction': 'Your destination is on the right.',
'bearing_before': 145,
'time': 0.0,
'length': 0.0,
'cost': 0.0,
'begin_shape_index': 488,
'end_shape_index': 488,
'travel_mode': 'drive',
'travel_type': 'car'}],
'summary': {'has_time_restrictions': False,
'has_toll': False,
'has_highway': True,
'has_ferry': False,
'min_lat': 50.729028,
'min_lon': -3.462135,
'max_lat': 50.861101,
'max_lon': -3.38319,
'time': 1050.746,
'length': 14.4843,
'cost': 1175.531},
'shape': '}k}~_BhfinEWAqFWqG\\iBZyFpAeT|B{Cx@qB`CoExJsCjJcCfImEpJsBnByBz@wBTyEa@uNyDyWwHhBkT`AuUh@mQCk[EmDQmPy@ey@yAc~@wB{]k@}NImEyAImDO_KsAmDu@iDcAs@UuG_CmB_AqLoGyGqDsJ}HmDiBwDyBaCoAeF{ANmCc@kFaEaYeBiLgBiMiBgOuB}WoAuNeCeUIw@y@gHo@{BcB}E{BsEeCqDyEaFcEoDuAyBa@sBq@VeAOw@aAa@aB?mByASsDiB{DoCmBqBkAqBgBqDmAiDaCkGeCeH{C_Kw@cC{@qCs@d@y@Fw@Wm@w@_@kAKyAHaB^sAp@{@z@W|@L\\uB^eGBgGEoK_AgReAmWeAyUy@oRq@kHS}Hg@sPoA}GaB{EyAgDi@y@a@eA_@sBMuDPeA`@qBn@sAx@_AbAe@`A_EbDcJt@g]J_ED{HjBqApBu@pDIzWfD~d@zGfH`Ax^xFf_B~RzPrHdhCjPxo@rEdt@lIjm@~Lrf@dLpe@~Ox[tKr[xN|X`Nte@bWxIhFb}@rn@fk@jd@z]tVre@dW`WbLjUpItY`IhWtE~ThDrg@~DrsAnBnm@p@~i@jFte@lIxm@hQpf@lT|c@|Xrf@`_@v`@v_@|c@~i@``@rf@tgAxyA||@~jAja@de@`f@fe@xc@n^fe@n[rpAjr@`kAfn@bf@|Y`e@n\\te@pa@la@l`@tmA|rA|dAtiAzcA`iAndAviAbhAdmAnPlRbn@bs@xFtHx`@th@h`@~k@bRb]lc@hx@d_@xt@v]l{@d_@ldAvUdt@te@tyA~q@nkBno@z}A`v@z`B~y@|bBjbAhdBtTx^p]hj@rs@xlAbcAz`B|y@ztAh}@|xA`z@puAz~@l{A`y@ltAlx@frAbfA|dB|^jg@jZj`@v`@rd@t^na@ze@rb@|b@v]jc@hZxPhK|GfEzHxEfd@fU|g@hTta@nNrk@`Qtb@fJdf@lGbNpAfZ|Czp@lI`VxBpn@zI|ZzFhZbH`\\dJxg@lQzOrGv[hNh_@vRpk@f]~^xW`f@f`@p\\tYj_Axz@ty@nv@byAhsAbQ~OjIvHduAzoAzpBfiBfzAvsAvo@dg@zq@dc@np@f]zo@bXl`@tMr_@zJh[vHn`@~Gvg@fG`d@rDnv@lBhf@Qdj@kBt^oCp_@gEj^wF`a@{Hhw@{QvaBsa@`IoBtbFwnAnuAaYbvAsTjjAwLbjAeH|gAkCpdAa@t{@hBpPt@t]dBj`@pCj]|CtO|A|PbBv_A~Ljb@|HzJlBjnArWzhAv\\tw@rYn}@j]taD|xAxi@|T~MdGxPtFdNxD`fBde@zg@fLr}@rNz|@zKf_@tCn]tC|SiChZ?hz@h@xd@BrY{Avs@kG|HoDtBmA|AcBx@_A~@oBjE}Jq@w[oDgv@i@mLQyEUuFw@cR_@sK{Aec@qCwv@aCac@yFg|@qH_|@oFoh@sRagB}NorAuHw|@eDek@eBwb@cBkm@s@aj@Skp@^{h@dAcl@dBci@rCin@tAyYlEcp@lJi`BrL_cB|E{r@lB}ZbB_^zBuh@jCet@x@o_@GyhBc@en@aBsm@yBwVcD}YuCsPoA}GqCcLgB{F_BwEgAsB{DoFyC[uBiAiBsBsAyCy@sDY}CwF{JwAgBqGsE}EcC_EFuDNaE@{Cv@wCvAgi@vY_VbLwMvEqNtDqRnCkZbGgXjH_HhBgPpC_BNqLjAaITkJM{Hk@wScAwDyBgG_AiB_@mFgBqHkCsNgG}GkDiRoLyEg@qFmF}AwAkBcDkAsBmCIkBgBkFuFyE{GgD_KuG}RgEkRoMy_@uMyb@oI}VwKmZmI{TyF_RiBeFgJmWiGoPyFsPuM_`@qQce@kDmKeS_j@yDwJqGmP{IuSkSya@aRi[}R{\\eNgV{CsGoGcNsb@yeAwLa`@mTqx@{Hq`@iGa^wAmG_BeBqAcA}CeBoEgAeAWaAo@s@aAk@qA]aBOgBAkBJgBZaBp@cBr@sEb@oCZiDh@_FC}GKgGc@uGa@_De@{CgEiWsAqHsAqFoEmRgAgEeC{IuBsHcFcQcLq[{Lm[n@u@~@uAhAwAZWjAgAbGeDxQkIzQ_Ktw@_a@pJ{D|NqDd~@gNbS}DjJyDnTeJxF{DbEgFvn@{aAdp@kv@??'}],
'summary': {'has_time_restrictions': False,
'has_toll': False,
'has_highway': True,
'has_ferry': False,
'min_lat': 50.729028,
'min_lon': -3.462135,
'max_lat': 50.861101,
'max_lon': -3.38319,
'time': 1050.746,
'length': 14.4843,
'cost': 1175.531},
'status_message': 'Found route between points',
'status': 0,
'units': 'miles',
'language': 'en-US'}}
summary{'total_time_s': 1050.746,
'total_dist': 14.4843,
'legs': [{'leg_index': 0,
'time_s': 1050.746,
'distance': 14.4843,
'speed': 49.625199620079435}]}
valhalla_audit_route_speeds(result)
=== ROUTE SUMMARY ===
Total time: 17.5 min
Total dist: 14.48 km
=== SPEED DISTRIBUTION ===
< 20 km/h (urban/stop-start) | time: 0.2 min ( 0.9%) | dist: 0.0 km ( 0.2%)
20–40 km/h (dense urban) | time: 6.0 min ( 34.0%) | dist: 2.8 km ( 19.6%)
40–60 km/h (suburban) | time: 1.6 min ( 8.9%) | dist: 1.4 km ( 9.6%)
60–90 km/h (A-road) | time: 9.8 min ( 56.2%) | dist: 10.2 km ( 70.6%)
90+ km/h (motorway-like) | time: 0.0 min ( 0.0%) | dist: 0.0 km ( 0.0%)
{'total_time_s': 1050.737,
'total_dist_km': 14.483400000000001,
'band_stats': {'20–40 km/h (dense urban)': {'time': 357.20799999999997,
'dist': 2.8386},
'< 20 km/h (urban/stop-start)': {'time': 9.91, 'dist': 0.0223},
'60–90 km/h (A-road)': {'time': 590.465, 'dist': 10.2289},
'40–60 km/h (suburban)': {'time': 93.154, 'dist': 1.3936000000000002},
'90+ km/h (motorway-like)': {'time': 0.0, 'dist': 0.0}}}
result_gdf = valhalla_maneuvers_to_gdf(result)
ax = result_gdf.plot(column="speed_kmh", legend=True, figsize=(10,6))
cx.add_basemap(
ax, # the figure we created using our plot method
crs=result_gdf.crs.to_string(), # we can pull the CRS out of the geodataframe!
)
# Grab the auto-generated attribution object from matplotlib axes
txt = ax.texts[-1]
# Adjust its position to outside the map, just below the bottom edge
txt.set_position([0.5, -0.1])
txt.set_ha('center') # Center the text
txt.set_va('top')
Cullompton to Tavistock (Cornish Arms)
result, summary = valhalla_detailed_route(
engine=Actor("../../datasets/devon-260422_valhalla-combined-modified.json"),
origin=(origins.iloc[0].latitude, origins.iloc[0].longitude),
destination=(destinations.iloc[2].latitude, destinations.iloc[2].longitude),
)
result
=== OVERALL ===
Time: 60.4 min
Distance: 55.43 miles
--- LEG 0 ---
Time: 60.4 min
Distance: 55.43 miles
Speed: 55.1 miles/h
Maneuvers:
23.279s | 0.1721 | Drive north on Shortlands Road.
32.749s | 0.2025 | Turn right onto Tiverton Road.
17.196s | 0.118 | Turn left onto High Street/B3181.
23.658s | 0.1584 | Turn right onto Station Road/B3181.
1.606s | 0.0118 | Enter the roundabout and take the 1st exit onto Station Road/B3181.
9.096s | 0.0671 | Exit the roundabout onto Station Road/B3181.
9.91s | 0.0223 | Enter the roundabout and take the 2nd exit onto Station Road/B3181.
17.397s | 0.1273 | Exit the roundabout onto Station Road/B3181.
3.722s | 0.0223 | Enter the roundabout and take the 3rd exit onto Station Road/A373.
6.367s | 0.0466 | Exit the roundabout onto Station Road/A373. Continue on A373.
843.429s | 14.6388 | Turn right to take the M5 ramp.
54.772s | 0.7083 | Keep left to take exit 31 onto A30.
1525.255s | 26.5816 | Continue on A30.
13.947s | 0.2429 | Take the Sourton Cross exit.
973.709s | 11.8563 | Turn left onto A386.
26.07s | 0.1926 | Bear left onto A386/Dolvin Road. Continue on Dolvin Road.
7.953s | 0.0211 | Enter Whitchurch Road and take the 2nd exit onto A386/Abbey Place.
33.781s | 0.2352 | Exit the roundabout onto A386/Abbey Place.
0.0s | 0.0 | You have arrived at your destination.
{'trip': {'locations': [{'type': 'break',
'lat': 50.855107,
'lon': -3.396451,
'side_of_street': 'right',
'original_index': 0},
{'type': 'break', 'lat': 50.551448, 'lon': -4.14675, 'original_index': 1}],
'legs': [{'maneuvers': [{'type': 2,
'instruction': 'Drive north on Shortlands Road.',
'verbal_succinct_transition_instruction': 'Drive north. Then, in 900 feet, Turn right onto Tiverton Road.',
'verbal_pre_transition_instruction': 'Drive north on Shortlands Road. Then, in 900 feet, Turn right onto Tiverton Road.',
'verbal_post_transition_instruction': 'Continue for 900 feet.',
'street_names': ['Shortlands Road'],
'bearing_after': 4,
'time': 23.279,
'length': 0.1721,
'cost': 34.167,
'begin_shape_index': 0,
'end_shape_index': 18,
'verbal_multi_cue': True,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 10,
'instruction': 'Turn right onto Tiverton Road.',
'verbal_transition_alert_instruction': 'Turn right onto Tiverton Road.',
'verbal_succinct_transition_instruction': 'Turn right.',
'verbal_pre_transition_instruction': 'Turn right onto Tiverton Road.',
'verbal_post_transition_instruction': 'Continue for a quarter mile.',
'street_names': ['Tiverton Road'],
'bearing_before': 14,
'bearing_after': 104,
'time': 32.749,
'length': 0.2025,
'cost': 44.81,
'begin_shape_index': 18,
'end_shape_index': 29,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 15,
'instruction': 'Turn left onto High Street/B3181.',
'verbal_transition_alert_instruction': 'Turn left onto High Street.',
'verbal_succinct_transition_instruction': 'Turn left.',
'verbal_pre_transition_instruction': 'Turn left onto High Street, B3181.',
'verbal_post_transition_instruction': 'Continue for 600 feet.',
'street_names': ['High Street', 'B3181'],
'bearing_before': 83,
'bearing_after': 4,
'time': 17.196,
'length': 0.118,
'cost': 27.109,
'begin_shape_index': 29,
'end_shape_index': 44,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 10,
'instruction': 'Turn right onto Station Road/B3181.',
'verbal_transition_alert_instruction': 'Turn right onto Station Road.',
'verbal_succinct_transition_instruction': 'Turn right.',
'verbal_pre_transition_instruction': 'Turn right onto Station Road, B3181.',
'verbal_post_transition_instruction': 'Continue for 800 feet.',
'street_names': ['Station Road', 'B3181'],
'bearing_before': 14,
'bearing_after': 80,
'time': 23.658,
'length': 0.1584,
'cost': 31.815,
'begin_shape_index': 44,
'end_shape_index': 63,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 26,
'instruction': 'Enter the roundabout and take the 1st exit onto Station Road/B3181.',
'verbal_transition_alert_instruction': 'Enter the roundabout and take the 1st exit onto Station Road.',
'verbal_succinct_transition_instruction': 'Enter the roundabout and take the 1st exit.',
'verbal_pre_transition_instruction': 'Enter the roundabout and take the 1st exit onto Station Road, B3181.',
'bearing_before': 51,
'bearing_after': 39,
'time': 1.606,
'length': 0.0118,
'cost': 7.375,
'begin_shape_index': 63,
'end_shape_index': 68,
'roundabout_exit_count': 1,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 27,
'instruction': 'Exit the roundabout onto Station Road/B3181.',
'verbal_succinct_transition_instruction': 'Exit the roundabout.',
'verbal_pre_transition_instruction': 'Exit the roundabout onto Station Road, B3181.',
'verbal_post_transition_instruction': 'Continue for 400 feet.',
'street_names': ['Station Road', 'B3181'],
'bearing_before': 39,
'bearing_after': 19,
'time': 9.096,
'length': 0.0671,
'cost': 14.64,
'begin_shape_index': 68,
'end_shape_index': 80,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 26,
'instruction': 'Enter the roundabout and take the 2nd exit onto Station Road/B3181.',
'verbal_transition_alert_instruction': 'Enter the roundabout and take the 2nd exit onto Station Road.',
'verbal_succinct_transition_instruction': 'Enter the roundabout and take the 2nd exit.',
'verbal_pre_transition_instruction': 'Enter the roundabout and take the 2nd exit onto Station Road, B3181.',
'bearing_before': 57,
'bearing_after': 345,
'time': 9.91,
'length': 0.0223,
'cost': 9.038,
'begin_shape_index': 80,
'end_shape_index': 91,
'roundabout_exit_count': 2,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 27,
'instruction': 'Exit the roundabout onto Station Road/B3181.',
'verbal_succinct_transition_instruction': 'Exit the roundabout.',
'verbal_pre_transition_instruction': 'Exit the roundabout onto Station Road, B3181.',
'verbal_post_transition_instruction': 'Continue for 700 feet.',
'street_names': ['Station Road', 'B3181'],
'bearing_before': 143,
'bearing_after': 100,
'time': 17.397,
'length': 0.1273,
'cost': 27.233,
'begin_shape_index': 91,
'end_shape_index': 105,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 26,
'instruction': 'Enter the roundabout and take the 3rd exit onto Station Road/A373.',
'verbal_transition_alert_instruction': 'Enter the roundabout and take the 3rd exit onto Station Road.',
'verbal_succinct_transition_instruction': 'Enter the roundabout and take the 3rd exit.',
'verbal_pre_transition_instruction': 'Enter the roundabout and take the 3rd exit onto Station Road, A373.',
'bearing_before': 55,
'bearing_after': 47,
'time': 3.722,
'length': 0.0223,
'cost': 4.038,
'begin_shape_index': 105,
'end_shape_index': 114,
'roundabout_exit_count': 3,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 27,
'instruction': 'Exit the roundabout onto Station Road/A373. Continue on A373.',
'verbal_succinct_transition_instruction': 'Exit the roundabout. Then, in 200 feet, Turn right to take the M5 ramp.',
'verbal_pre_transition_instruction': 'Exit the roundabout onto Station Road, A373. Then, in 200 feet, Turn right to take the M5 ramp.',
'verbal_post_transition_instruction': 'Continue on A373 for 200 feet.',
'street_names': ['A373'],
'begin_street_names': ['Station Road', 'A373'],
'bearing_before': 146,
'bearing_after': 123,
'time': 6.367,
'length': 0.0466,
'cost': 6.013,
'begin_shape_index': 114,
'end_shape_index': 119,
'verbal_multi_cue': True,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 18,
'instruction': 'Turn right to take the M5 ramp.',
'verbal_transition_alert_instruction': 'Turn right to take the M5 ramp.',
'verbal_pre_transition_instruction': 'Turn right to take the M5 ramp.',
'verbal_post_transition_instruction': 'Continue for 15 miles.',
'street_names': ['M5'],
'bearing_before': 92,
'bearing_after': 167,
'time': 843.429,
'length': 14.6388,
'cost': 841.844,
'begin_shape_index': 119,
'end_shape_index': 396,
'highway': True,
'sign': {'exit_branch_elements': [{'text': 'M5'}]},
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 24,
'instruction': 'Keep left to take exit 31 onto A30.',
'verbal_transition_alert_instruction': 'Keep left to take exit 31.',
'verbal_pre_transition_instruction': 'Keep left to take exit 31 onto A30.',
'street_names': ['M5'],
'bearing_before': 227,
'bearing_after': 220,
'time': 54.772,
'length': 0.7083,
'cost': 53.393,
'begin_shape_index': 396,
'end_shape_index': 435,
'sign': {'exit_number_elements': [{'text': '31'}],
'exit_branch_elements': [{'text': 'A30', 'consecutive_count': 1}],
'exit_name_elements': [{'text': "Pearce's Hill"}]},
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 8,
'instruction': 'Continue on A30.',
'verbal_transition_alert_instruction': 'Continue on A30.',
'verbal_pre_transition_instruction': 'Continue on A30.',
'verbal_post_transition_instruction': 'Continue for 27 miles.',
'street_names': ['A30'],
'bearing_before': 324,
'bearing_after': 324,
'time': 1525.255,
'length': 26.5816,
'cost': 1418.813,
'begin_shape_index': 435,
'end_shape_index': 1004,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 21,
'instruction': 'Take the Sourton Cross exit.',
'verbal_transition_alert_instruction': 'Take the Sourton Cross exit.',
'verbal_pre_transition_instruction': 'Take the Sourton Cross exit.',
'bearing_before': 234,
'bearing_after': 226,
'time': 13.947,
'length': 0.2429,
'cost': 12.194,
'begin_shape_index': 1004,
'end_shape_index': 1022,
'sign': {'exit_name_elements': [{'text': 'Sourton Cross'}]},
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 15,
'instruction': 'Turn left onto A386.',
'verbal_transition_alert_instruction': 'Turn left onto A386.',
'verbal_succinct_transition_instruction': 'Turn left.',
'verbal_pre_transition_instruction': 'Turn left onto A386.',
'verbal_post_transition_instruction': 'Continue for 12 miles.',
'street_names': ['A386'],
'bearing_before': 266,
'bearing_after': 190,
'time': 973.709,
'length': 11.8563,
'cost': 880.727,
'begin_shape_index': 1022,
'end_shape_index': 1510,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 16,
'instruction': 'Bear left onto A386/Dolvin Road. Continue on Dolvin Road.',
'verbal_transition_alert_instruction': 'Bear left onto A386.',
'verbal_succinct_transition_instruction': 'Bear left.',
'verbal_pre_transition_instruction': 'Bear left onto A386, Dolvin Road.',
'verbal_post_transition_instruction': 'Continue on Dolvin Road for a quarter mile.',
'street_names': ['Dolvin Road'],
'begin_street_names': ['A386', 'Dolvin Road'],
'bearing_before': 265,
'bearing_after': 229,
'time': 26.07,
'length': 0.1926,
'cost': 27.779,
'begin_shape_index': 1510,
'end_shape_index': 1522,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 26,
'instruction': 'Enter Whitchurch Road and take the 2nd exit onto A386/Abbey Place.',
'verbal_transition_alert_instruction': 'Enter Whitchurch Road and take the 2nd exit onto A386.',
'verbal_succinct_transition_instruction': 'Enter the roundabout and take the 2nd exit.',
'verbal_pre_transition_instruction': 'Enter Whitchurch Road and take the 2nd exit onto A386, Abbey Place.',
'street_names': ['Whitchurch Road'],
'bearing_before': 175,
'bearing_after': 194,
'time': 7.953,
'length': 0.0211,
'cost': 8.6,
'begin_shape_index': 1522,
'end_shape_index': 1534,
'roundabout_exit_count': 2,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 27,
'instruction': 'Exit the roundabout onto A386/Abbey Place.',
'verbal_succinct_transition_instruction': 'Exit the roundabout.',
'verbal_pre_transition_instruction': 'Exit the roundabout onto A386, Abbey Place.',
'verbal_post_transition_instruction': 'Continue for a quarter mile.',
'street_names': ['A386'],
'begin_street_names': ['A386', 'Abbey Place'],
'bearing_before': 325,
'bearing_after': 311,
'time': 33.781,
'length': 0.2352,
'cost': 55.038,
'begin_shape_index': 1534,
'end_shape_index': 1563,
'travel_mode': 'drive',
'travel_type': 'car'},
{'type': 4,
'instruction': 'You have arrived at your destination.',
'verbal_transition_alert_instruction': 'You will arrive at your destination.',
'verbal_pre_transition_instruction': 'You have arrived at your destination.',
'bearing_before': 335,
'time': 0.0,
'length': 0.0,
'cost': 0.0,
'begin_shape_index': 1563,
'end_shape_index': 1563,
'travel_mode': 'drive',
'travel_type': 'car'}],
'summary': {'has_time_restrictions': False,
'has_toll': False,
'has_highway': True,
'has_ferry': False,
'min_lat': 50.548826,
'min_lon': -4.146689,
'max_lat': 50.861101,
'max_lon': -3.38319,
'time': 3623.905,
'length': 55.4261,
'cost': 3504.635},
'shape': '}k}~_BhfinEWAqFWqG\\iBZyFpAeT|B{Cx@qB`CoExJsCjJcCfImEpJsBnByBz@wBTyEa@uNyDyWwHhBkT`AuUh@mQCk[EmDQmPy@ey@yAc~@wB{]k@}NImEyAImDO_KsAmDu@iDcAs@UuG_CmB_AqLoGyGqDsJ}HmDiBwDyBaCoAeF{ANmCc@kFaEaYeBiLgBiMiBgOuB}WoAuNeCeUIw@y@gHo@{BcB}E{BsEeCqDyEaFcEoDuAyBa@sBq@VeAOw@aAa@aB?mByASsDiB{DoCmBqBkAqBgBqDmAiDaCkGeCeH{C_Kw@cC{@qCs@d@y@Fw@Wm@w@_@kAKyAHaB^sAp@{@z@W|@L\\uB^eGBgGEoK_AgReAmWeAyUy@oRq@kHS}Hg@sPoA}GaB{EyAgDi@y@a@eA_@sBMuDPeA`@qBn@sAx@_AbAe@`A_EbDcJt@g]J_ED{HjBqApBu@pDIzWfD~d@zGfH`Ax^xFf_B~RzPrHdhCjPxo@rEdt@lIjm@~Lrf@dLpe@~Ox[tKr[xN|X`Nte@bWxIhFb}@rn@fk@jd@z]tVre@dW`WbLjUpItY`IhWtE~ThDrg@~DrsAnBnm@p@~i@jFte@lIxm@hQpf@lT|c@|Xrf@`_@v`@v_@|c@~i@``@rf@tgAxyA||@~jAja@de@`f@fe@xc@n^fe@n[rpAjr@`kAfn@bf@|Y`e@n\\te@pa@la@l`@tmA|rA|dAtiAzcA`iAndAviAbhAdmAnPlRbn@bs@xFtHx`@th@h`@~k@bRb]lc@hx@d_@xt@v]l{@d_@ldAvUdt@te@tyA~q@nkBno@z}A`v@z`B~y@|bBjbAhdBtTx^p]hj@rs@xlAbcAz`B|y@ztAh}@|xA`z@puAz~@l{A`y@ltAlx@frAbfA|dB|^jg@jZj`@v`@rd@t^na@ze@rb@|b@v]jc@hZxPhK|GfEzHxEfd@fU|g@hTta@nNrk@`Qtb@fJdf@lGbNpAfZ|Czp@lI`VxBpn@zI|ZzFhZbH`\\dJxg@lQzOrGv[hNh_@vRpk@f]~^xW`f@f`@p\\tYj_Axz@ty@nv@byAhsAbQ~OjIvHduAzoAzpBfiBfzAvsAvo@dg@zq@dc@np@f]zo@bXl`@tMr_@zJh[vHn`@~Gvg@fG`d@rDnv@lBhf@Qdj@kBt^oCp_@gEj^wF`a@{Hhw@{QvaBsa@`IoBtbFwnAnuAaYbvAsTjjAwLbjAeH|gAkCpdAa@t{@hBpPt@t]dBj`@pCj]|CtO|A|PbBv_A~Ljb@|HzJlBjnArWzhAv\\tw@rYn}@j]taD|xAxi@|T~MdGxPtFdNxD`fBde@zg@fLr}@rNz|@zKf_@tCn]tCxaAfFt`AnBdjBA~f@Of}@M`hBmA`p@sA`hGqCpb@DnxBkBd}@r@bZtAjm@~Dph@zGtt@tLnn@|Ndd@|OhR|GjU|K~a@fSrYzOdzAx{@noAtt@duAnx@bc@`W`h@~Xh[vNz`Avc@pN~FvhAn`@phBxi@x`C|~@bu@`^bz@tc@fdAvo@pcAzs@zkAjaA`kA~gAzmAbsAbXb\\fe@zk@tRtYt`@po@n\\rj@l[hm@fc@l}@r^|z@zOha@pOva@b_@rkArPzj@lJb]pTr}@tUxlA|Ifn@|Gtn@fAfOvA~RlAfSnAzWjA~Vf@pOd@vN\\dOZ~NLpNJpNHlNFxPGhRIdO]vSg@nRo@fOiDf}@cAbUqAjRcAnOuCfg@uCzh@eBn^eBje@yAhy@Gtd@Th\\p@dm@bCds@fCrd@~E|o@hHdo@vIpl@xLvr@pNxn@fNph@vRrm@bNp^bSdd@jN`YpOf[ve@pr@`W~^jO~S|NhRjIbJ`JjHjHxEjGlC|FnBhHbBbHhAxI\\fRQdRe@lIl@hHfAxGbCtGdFjEhGrDpHdCtIvB|JfAhKb@lKQ|Ku@zIuAvJmBhIeCvGeDtG_FfHkG~Gwz@|n@wt@th@eM|JgM|JwYlWeZ~Z}ObReHtI{IvKkC`Do]rf@cWpb@yIzPgMtU}Uvg@wQpc@yPre@aMz_@kIvXiLfa@eVfbA_c@dgBsXnlAuZxlA}YjnAcTx{@wKjb@wJv^gJpZeJjXgLtYeNn\\yHlPaHpNuGxMmLzSoTz]aUh[wIlKeHhIkTfUiRtQmTzQmN|J}QdLy_@dU_rB|cAemBlaAwt@n_@gb@lSwr@j`@iZlR}RfNuf@bb@cJzIgQpQmWl[aLlOmFjIqIfMkFdIoF|IwF`JmFjJiFvJkFfK_FzJcFlKeOp\\aHnP}A`EyClIg_@jiAsI~[{In]yIv`@eL|m@uJjm@yKp|@{I`_A_LhuA}K~rAgXv}CcLjdAsLhs@gGbZsEfTuDpO{C~LiC|ImQfj@aQfe@kWni@eNfWmXjb@eWv]{b@~c@oUnTyl@z_@aPrHiWvKuQfIaU`Km_@bSyUfOkVxPac@ba@mLtMaM~Nef@|s@}Yph@q]xm@}h@jy@o^tb@{~@lfA_e@dr@sOzYiUdk@kFrO}GhU}GvYgHx[aG|\\aE|[wDh^oCxd@{Aja@o@xf@Znf@RlYvBdg@jD|c@lHnw@xMhiAzSx{B`Fr~@|Ch~@`Ab|@eBhrAuA|z@_Ezz@gO|yAcUt_BmTjhAeXlfAeaAdfDeW|fAsUplAiErT{Lf{@{Hhi@mKz`AuGnt@gDpd@wFd~@sDr~@sCteAgA|hAPtcA|@ly@|Ax{@xCfz@lFjiBlEjzAzApu@Xbt@KbdAwAtmAuDliA}Ej`AeFvw@uI~`AwKjaAqJ`s@oJto@oQfjAuUd{AkNl|@cNjbA{LzbAuGjo@qIflA}FziAoDxkAaBroAQxj@Ldg@|AdkAfDhhAlNbsCrJzoB~Ad`@bBlf@HhDlBddA^ds@A|i@Axe@q@pn@{B~jA_FlkAiBz]eEvt@wIngA_Wb{BuRvoAwNxw@mOlr@}S`}@kf@tpBcK~b@cUncAcS|eAqStsAaNlcAgHps@kLzuAcH|lAcCvi@sBlu@wAnm@k@~u@]|v@\\~b@d@fh@fB||@pDleAtHvyApTjcDtVtaDxOfkBv\\`pDv_@~xDnb@tqDnPryApHzs@bJpaAnFht@xFx|@`Dvq@xCzv@jBzn@dCfjAz@|aAFjaBOvm@mAzgBqBxaCoA`eAyA~gAyBjnASzMKnIqFztBmGhhAcI~|@_Gdh@kD`YoMnw@uP`z@uNpm@}S`u@eXd{@}Utw@cYhdAwGn[}U~fAwNd`A{VdlBeLvgAwE`q@iMvaC_IfoCaBttCHzrAjA`tAvC|rAjHbuAxEfy@rGty@`S|`BjWf~Avm@puC||@duD~e@dwBle@nyB~fAdxFdFrVxg@ppCx\\fnBv^v{Br}@lwFdT`lAlWzmA`Obn@vO`o@`d@n}AxaAfcDr`@tsAj^`qArQrv@`Sb{@zOtv@rSzkAxQ~kAhNrbApOrwA`WbrCpGvbA|Eb}@pCxm@|DnxAvAtp@t@bk@d@jpB[rcAe@lfAgBldA}CrlAaIxyCyJtxCmKzlCsMzsCgeAtoOwD|p@wCfu@aAtUmCdbBoE`eEeCfdAwBl{@}Dh}@kFty@wEfp@gFdl@aBxO}Or~@eK`a@yIpZ{J|XwKjXgQr^yY~h@{{BjeDwu@hgAmt@`eAia@|l@q]xe@ke@|v@kPbXiFdKqTpd@uArCmRdf@{Uvw@eStv@cRnaA{Lju@{Jzv@yUlwBkRffBcS|wBwKnaBcGjlA}Bv{@oC~_B}Aj}@gCpn@_Dtf@sBjYmG~|@kMnlA_L`bAuqAdfLsRt_B}Rt`BiFt]yJxd@eUlz@uVdr@_Tnd@}Tdb@o_A`_BiYnk@c]~z@sOpd@mLv`@yNdk@eZd`BqMjeAmIzgAsE|eAkB~jAeGhbDgMp{HiE|jAgH|cAsOhtAmHfh@o\\hcCaKnaAwJvfAgOzcCgF`~AeEbiCDpaC^ve@p@xTpBhv@tI`yBpFfaAhIvdAjXdgCr`@~hDrKr~@`m@zeFpLtxAnHhvA~BtmBL|p@kAbs@eGbwAgItdAaJt{@uSr}AwHdi@aI~p@}H~v@oFbq@eGraA}B`r@eCjeAiBfsAHnnAp@zm@tApr@`Cfn@d@dUjEbx@`JhoAlKlfAbQbrAtRtlAnLdj@vKpd@~Mje@rSbn@d^f_Alk@|cAdObUbGjIxFfIlG~I`J`Njb@hk@tRlXxWhd@xJpQ`KbRhJjS`KxV|KpYzIdXnK|`@nLbg@|Hrd@nGla@hJlw@`Gvk@tFhi@fMztAjIpu@dLpfArJlz@xJr{@pH|p@xKr_AxKnt@jHnj@pKfs@jLxu@hMpq@rLhn@fKnd@lOxj@|Pxi@vSxi@zIvTbJlSjRh_@bYrh@vWde@fRd^xRtb@zM|ZxKlY~FjRhKz_@jGfXxD~QnC|NdDhSpEz\\~ChWfEra@bCjY`A|LjBzU`Dva@vDtc@dEle@|Ffn@pGfp@nFlh@hFtd@fDjYrEb_@nFz_@nE~[nHrg@tGrc@fHtd@~Gxa@|BzN`ExWhHta@~G~_@nNvs@~Gl]~Ipb@tL`h@|Jfd@rMxh@~Lng@fS`x@tXdlA~G`[j]~}AhR~|@pL~l@~Hd`@rN`t@xBfMbDvRbCvMtCtRxGrc@vIfj@lFd_@dSrwAtGhg@vDtZhJlz@|Kp{@xGtc@pLnq@nCtPdJne@|Hl_@nJ|`@zNti@lLpa@fSdk@bRvf@vV~k@nErJ`Sj`@nPnZ~Vbb@|Yrd@l{FnwIxjA|gBtSj^xO|ZbOd]|Lz\\zL`VzNhd@`Npd@`F`OzE|LfFhLjD~GrE`HzIvL|HnK~HhMdEpJjDpKjCvMnA|Gz@vJEhFIfChP~CpVbEdThDrVhEvPdEtOdErIfDxKbFhItEbQpLlQxNtVjWln@vr@ld@nh@fk@tn@xhA~nAzn@ds@lS~TzPn\\~d@xhAzQjd@dBfEzQzc@jKxUzInVrNfb@bNlb@zClJ~FdMfQ|Xd@`AbGdJbFtJnCzEhGjKhO~UvFtGxG|GfJlHpL`If@LhHhCrFvAzGdApLhAt^~Dvc@~DjHn@zT~@nOjAhOpC`JzCpBp@|LbHl|@zm@`RrL|MbGb[fN`h@lZ`MlHx@f@fF`DnGtEnMdM~LxMt]h^vM|Q|OzZtBxDh^pg@bc@fg@r]b`@~LvMhExCdKvFpXjGbZ|Ejs@nHbGn@pPh@pQIrCAxFIr@BdP|@~g@pDp]jA|It@nA`@|DnA`NtHlP`LtKzGbStJtGvD|FnEdUrQnNxHrObH|XtKjLbCnIh@hQYzAEzM[|K`AbPzClEfBdFtBfTtO|JhE~JnArBIl^kB|BEhDEtFG|HJtLz@|KbAhJP|J{@fP}DtWuGth@gPpQaI`P}IlOqHn@]zo@s[pV_MxHoBhIeA`UMvaAc@v_@D``@kAfK[fKHhG^pGnA|GzBbGzCzDvBjFrDtMzMjMfLnJzHpIvGhLrHfVzJfc@jPzN`Gvk@tTdNpFjChAxB`AlT`JvVfJpRhHjPbEtHxAvo@jN|g@rKn|@pRbDr@hAV`a@lJxOjDlJfBhFd@fKj@zYY`SYpNC`ABfz@|ChRr@leBlF`N`@pENnFRpEPzCLll@`CrI\\zBHpp@zBrVfBjLdCfNxFxVtNdCpBrD`Cli@~\\pGxEb[`RvQzMl`B~dAra@bX`aAtm@fGtDhEbBnCv@vF\\hHe@~L{CjNiFhi@wVhGwBtD_AhEQbFFvCFjAJbAH^Dr@HnA`@~CrAxCvCbDjGtD~KdDhNj@rCnG|[bNn|@|AtFjC|FrFjIvBtBlClBnDbBzChA~A`@`ATfDv@tFZrGDlZQlGMxEWnLeB|OwDrYcJzIc@lF?lD?dZpCfgBxRfg@tFzdAlLz|@|IjIlA|BZdOlBnf@tFbuAvNr`@jEdBR`AJjJbAbXnC`XlCnf@nFt^xDdWjFbFvBxDdBzBpAh@Z|LpIzVxXfRnWrQtVvVpYlT|OnbAro@heCf_B`q@zb@xeA~q@bb@xXrw@|f@ny@hh@xu@|e@vp@xa@tw@ng@~QhLvLjHhIlF`EjCbCzAtO`K`WpOvi@zYpjC`wAtzApx@ffCxtA~SlLld@tVnBfAps@f_@tq@|_@l~@dh@xe@tW~dAbd@zmAxi@pXrLxCp@lB`@rBd@hGRlIDhA?lCBtQEL?pe@aAho@sA~A@vCE|Zu@bMYnn@eAhJ]rQ_@jDSxCg@~FeCxBqAjZkQhJgE`MgEdYwJjNyEbq@gUjUwJbRyKfM_JpLqKnk@sn@lR_PxMgJjR}JhRqHbMoDlPwDdQ{BbTwBjQmAbTwAhSp@dZtCzVvCtOfClFpAlZnH`^fFls@tI`IhA~B\\b}AlShcAdMhOtBjQvCxUbH~IhC~LrArz@nDfk@rDbJbAjK|BlIfGdFbHd^ln@`HfKnErF`EdDfJ`Frg@lPnKxBvHZfl@gC`\\BbImAdOsHv_@sUdLeJjQ}HfLeDlS_GzNuCzLSfJr@x]vGvR~EfP`GxFnFhGdJ`O~UvKtXZt@lG`VdEpSrCdVhBlPzBlMhDjKlD~ErDdEdHhDlz@hXbRxJfNrJlEvDrGfHjv@xgAdLlQtGhMrCdGjNda@fTli@jNt[dObUlX~YbSfTzPxQhSrU`IxMrKpVjKrVfF|LbOn\\tOtWdLxOpJzLbHrHpIlFvGfB`E^lGL|Qf@hPl@df@tEzWrDfTnFf\\~Ij_@vK~X`KrZbK|F|B|L|ElLvG`P`L~B|BzG|GdVb^fCtDtTz\\rQ`XdJxP|GnLrK~NnQrRxWlUlZxVpW|WrQ`TdGtKxElKzBnHdErMrJ|\\bFfOtEpJdFnItFdJnGjMnGnOvYb~@pH`Uj@dDpClPlA`UX|u@Rl[B`FVdDbAtCdDfGlGzN`Rd^pRh`@fMrUfGdIpKdJnMpIpSzKhE?zBi@dAeAr@Mp@Ll@f@b@z@RjADrAMpAWx@]j@e@^i@Jm@nA[t@w@|CgDtHKTs@z@_GlJkCrEqBpCgH|J}BzDmDpAwKjJoMlLuBlA{BzBm\\~TsA|AcBlBk@`A_BrCyCbJyBtJuBhMiC|I}DbJsE`HuGrE_Ab@'}],
'summary': {'has_time_restrictions': False,
'has_toll': False,
'has_highway': True,
'has_ferry': False,
'min_lat': 50.548826,
'min_lon': -4.146689,
'max_lat': 50.861101,
'max_lon': -3.38319,
'time': 3623.905,
'length': 55.4261,
'cost': 3504.635},
'status_message': 'Found route between points',
'status': 0,
'units': 'miles',
'language': 'en-US'}}
summary{'total_time_s': 3623.905,
'total_dist': 55.4261,
'legs': [{'leg_index': 0,
'time_s': 3623.905,
'distance': 55.4261,
'speed': 55.06048309765294}]}
valhalla_audit_route_speeds(result)
=== ROUTE SUMMARY ===
Total time: 60.4 min
Total dist: 55.43 km
=== SPEED DISTRIBUTION ===
< 20 km/h (urban/stop-start) | time: 0.3 min ( 0.5%) | dist: 0.0 km ( 0.1%)
20–40 km/h (dense urban) | time: 3.2 min ( 5.4%) | dist: 1.4 km ( 2.4%)
40–60 km/h (suburban) | time: 17.1 min ( 28.4%) | dist: 12.6 km ( 22.7%)
60–90 km/h (A-road) | time: 39.7 min ( 65.7%) | dist: 41.5 km ( 74.8%)
90+ km/h (motorway-like) | time: 0.0 min ( 0.0%) | dist: 0.0 km ( 0.0%)
{'total_time_s': 3623.896,
'total_dist_km': 55.42519999999999,
'band_stats': {'20–40 km/h (dense urban)': {'time': 194.921, 'dist': 1.3539},
'< 20 km/h (urban/stop-start)': {'time': 17.863, 'dist': 0.0434},
'60–90 km/h (A-road)': {'time': 2382.6310000000003, 'dist': 41.4633},
'40–60 km/h (suburban)': {'time': 1028.481, 'dist': 12.564599999999999},
'90+ km/h (motorway-like)': {'time': 0.0, 'dist': 0.0}}}
result_gdf = valhalla_maneuvers_to_gdf(result)
ax = result_gdf.plot(column="speed_kmh", legend=True, figsize=(8,4))
cx.add_basemap(
ax, # the figure we created using our plot method
crs=result_gdf.crs.to_string(), # we can pull the CRS out of the geodataframe!
)
# Grab the auto-generated attribution object from matplotlib axes
txt = ax.texts[-1]
# Adjust its position to outside the map, just below the bottom edge
txt.set_position([0.5, -0.1])
txt.set_ha('center') # Center the text
txt.set_va('top')
If we are familiar with these routes, this might help us better understand where valhalla is overestimating or underestimating speeds.