Note
Go to the end to download the full example code.
Computing paths over the network#
In this example we show how to use the Router from the POLARIS API to compute paths over the network
Imports#
sphinx_gallery_thumbnail_path = “../../examples/working_with_models/routed_path.png”
from pathlib import Path
import folium
import numpy as np
from polaris import Polaris
from polaris.utils.database.db_utils import read_and_close
from polaris.utils.testing.temp_model import TempModel
Data Sources#
Open the demand database for analysis
model_fldr = TempModel("Grid")
project = Polaris.from_dir(Path(model_fldr))
# If you have a custom build batch_router.dll you can specify it via this command
# project.set_router_lib(Path('/home/user/bin/batch_router.so'))
router = project.router
We can first compute the path between two links The departure is in seconds, and we need to provide both the links and their directions (0 for AB and 1 for BA) If we don’t provide the link directions, they default to 0
path = router.route(origins=(678, 1), destinations=(656, 0), modes=0, departure_times=72000, ods_are="links")
# Then we can see the total travel time
print(path.travel_time)
# Then we can see the list of links (linkid/dir) that were traversed
print(path.links)
# And the cumulative travel time at each link
print(path.cumulative_time)
1686.0
[(678, 1), (677, 1), (426, 1), (425, 1), (127, 1), (498, 1), (497, 1), (496, 1), (495, 1), (494, 1), (35, 0), (36, 0), (38, 0), (297, 0), (298, 0), (299, 0), (300, 0), (301, 0), (302, 0), (303, 0), (304, 0), (305, 0), (59, 0), (57, 1), (356, 0), (357, 0), (358, 0), (625, 0), (626, 0), (627, 0), (628, 0), (629, 0), (630, 0), (640, 0), (641, 0), (642, 0), (643, 0), (655, 0), (656, 0)]
[ 52. 104. 160. 216. 265. 330. 395. 440. 485. 530. 568. 597.
626. 659. 692. 725. 758. 791. 824. 857. 890. 923. 984. 1000.
1045. 1090. 1135. 1177. 1219. 1261. 1301. 1341. 1381. 1444. 1507. 1570.
1633. 1686. 1739.]
We can also compute the path between two locations In this case, the link and direction associated with the locations will be used as Origin and destination If we don’t provide a departure time, 8AM (28800) is used If we don’t provide a mode, 0 (SOV car) is used
new_path = router.route(90, 740)
print(new_path)
Polaris Path:
Origin: 90
Destination: 740
Travel Time: 1632.0
Departure Time: 28800
Links: [(574, 0), (137, 0), (543, 0), (544, 0), (545, 0), (546, 0), (547, 0), (53, 1), (54, 0), (320, 0), (321, 0), (322, 0), (323, 0), (324, 0), (325, 0), (326, 0), (327, 0), (328, 0), (331, 0), (332, 0), (333, 0), (334, 0), (335, 0), (336, 0), (337, 0), (338, 0), (339, 0), (340, 0), (341, 0), (34, 0), (40, 0), (41, 0), (590, 0), (591, 0), (592, 0), (593, 0), (594, 0), (595, 0), (440, 0), (441, 0), (442, 0)]
Cumulative Time: [ 58. 106. 166. 226. 273. 320. 367. 413. 450. 483. 516. 549.
582. 615. 648. 681. 714. 747. 770. 793. 826. 859. 892. 925.
958. 991. 1024. 1057. 1090. 1121. 1148. 1193. 1246. 1299. 1352. 1406.
1460. 1514. 1573. 1632. 1691.]
We can compute the multi-modal travel time between two locations. We do need to input the mode, however
multimodal_path = router.route(90, 740, modes=1)
print(f"Multimodal travel time: {multimodal_path.travel_time}")
print(f"Car travel time: {new_path.travel_time}")
print(multimodal_path)
Multimodal travel time: 1632.0
Car travel time: 1632.0
Polaris Path:
Origin: 90
Destination: 740
Travel Time: 1632.0
Departure Time: 28800
Links: [(574, 0), (137, 0), (543, 0), (544, 0), (545, 0), (546, 0), (547, 0), (53, 1), (54, 0), (320, 0), (321, 0), (322, 0), (323, 0), (324, 0), (325, 0), (326, 0), (327, 0), (328, 0), (331, 0), (332, 0), (333, 0), (334, 0), (335, 0), (336, 0), (337, 0), (338, 0), (339, 0), (340, 0), (341, 0), (34, 0), (40, 0), (41, 0), (590, 0), (591, 0), (592, 0), (593, 0), (594, 0), (595, 0), (440, 0), (441, 0), (442, 0)]
Cumulative Time: [ 1.23120375e+05 -7.35426767e+15 1.86883500e+05 4.62489406e-36
4.62493639e-36 2.74622129e-39 -7.35426767e+15 -7.35426767e+15
0.00000000e+00 1.12339203e+02 0.00000000e+00 5.96087646e+02
2.10194770e-44 -7.35426767e+15 2.10194770e-44 2.10194770e-44
4.45251367e+03 3.15292154e-43 4.62428493e-44 4.62428493e-44
3.37712930e-43 6.29183010e-43 6.51603786e-43 4.62428493e-44
4.62428493e-44 6.29183010e-43 4.62428493e-44 6.29183010e-43
6.29183010e-43 1.99553250e+05 6.68367500e+04 9.37782000e+05
1.67026250e+05 2.45597750e+05 -1.02542649e-29 5.60007000e+05
1.24852250e+05 2.51579000e+05 1.23115500e+05 -1.02542770e-29
-1.02542529e-29]
And we can plot this path on the network
data = project.network.tables
with read_and_close(project.supply_file, spatial=True) as conn:
links_layer = data.get("Link", conn).to_crs(4326)
loc_layer = data.get("Location", conn).to_crs(4326)
loc_layer = loc_layer[loc_layer.location.isin([90, 740])]
path_layer = links_layer.query(f"link in @new_path.link_ids")
centr = path_layer.union_all().centroid
map = links_layer.explore(color="blue", style_kwds={"weight": 2}, tool_tip="link", name="links")
map = path_layer.explore(m=map, color="red", style_kwds={"weight": 5}, tool_tip="link", name="path")
map = loc_layer.explore(
m=map,
color="black",
tool_tip="location",
style_kwds={"radius": 6, "fillOpacity": 1.0, "fillColor": "black", "fill": True},
name="Locations",
)
folium.LayerControl().add_to(map) # Add a layer control button to our map
map
Total running time of the script: (0 minutes 1.939 seconds)