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: [ 4.2327241e+05 3.4863277e-09 4.2327241e+05 9.6612530e-07
1.8112996e-09 -4.9127165e+35 9.5677206e-07 1.5960790e-42
4.2327241e+05 1.8455101e-42 -4.9127165e+35 1.0551777e-42
9.5054656e-07 9.7080192e-07 4.2327241e+05 0.0000000e+00
4.2327241e+05 0.0000000e+00 1.6605387e-42 1.6614031e-06
1.3650824e-06 4.2327241e+05 3.8255448e-43 1.8076750e-43
4.6242849e-44 4.6242849e-44 4.6242849e-44 4.6242849e-44
4.6242849e-44 4.6242849e-44 4.6242849e-44 4.6242849e-44
6.0676224e-43 1.5834673e-43 1.3592595e-43 3.3398674e-13
3.4926302e-09 4.3361084e-09 4.1773376e-09 -4.9127229e+35
-4.9127165e+35]
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.788 seconds)