Note
Go to the end to download the full example code.
Analyzing traffic convergence#
On this example we show how to use analyze traffic convergence for different segments of the results
Imports#
from pathlib import Path
import geopandas as gpd
import matplotlib.pyplot as plt
from polaris.analyze.path_metrics import PathMetrics
from polaris.analyze.result_kpis import ResultKPIs
from polaris.network.data.data_table_cache import DataTableCache
from polaris.runs.convergence.convergence_iteration import ConvergenceIteration
from polaris.runs.scenario_compression import ScenarioCompression
from polaris.runs.scenario_utils import get_last_iteration
Data Sources#
Open the demand database for analysis
project_dir = Path("/tmp/Bloomington")
iteration_folder = get_last_iteration(project_dir)
supply_db = ScenarioCompression.maybe_extract(Path(iteration_folder) / "Bloomington-Supply.sqlite")
zones = DataTableCache(supply_db).plotting_layer("Zone")
links = DataTableCache(supply_db).plotting_layer("Link")
Data retrieval#
last_iter = ConvergenceIteration.from_dir(iteration_folder)
kpis = ResultKPIs.from_iteration(last_iter)
Plotting aggregate results#
def chart_metric(df, metric: str, axis=None):
df.plot.area(ax=axis)
axis.set(title=metric)
df = kpis.m_etric_traffic_cumulative_gap()
fig, axis = plt.subplots(2, 2)
all_axis = [axis[0, 0], axis[0, 1], axis[1, 0], axis[1, 1]]
for metric, ax in zip(df.metric.unique(), all_axis):
df_ = df[df.metric == metric]
df_ = df_.dropna(axis=1, how="any").sort_values(by="Trip end minute")
chart_metric(df_, metric, ax)
# Combine all the operations and display
plt.tight_layout()
plt.show()

Totals per zone and link#
pm = PathMetrics(demand_file=last_iter.files.demand_db, h5_file=last_iter.files.result_h5)
traces = pm.data
zlayer = gpd.GeoDataFrame(zones, geometry=gpd.GeoSeries.from_wkt(zones.geo, crs=4326)).reset_index()
llayer = gpd.GeoDataFrame(links, geometry=gpd.GeoSeries.from_wkt(links.geo, crs=4326)).reset_index()
gdf = llayer.sjoin_nearest(zlayer, how="inner")[["link", "zone"]]
gap_per_zone = (
traces.merge(gdf, left_on="link_id", right_on="link").groupby(["zone"]).sum()[["absolute_gap"]].reset_index()
)
plot_zone_layer = zlayer.merge(gap_per_zone, on="zone").drop(columns=["geo"])
gap_per_link = traces.groupby(["link_id"]).sum()[["absolute_gap"]].reset_index()
plot_link_layer = llayer.merge(gap_per_link, left_on="link", right_on="link_id", how="left").drop(columns=["geo"])
map_center = (zlayer.geometry.centroid.x.mean(), zlayer.geometry.centroid.y.mean())
# Fill in any NaN to avoid kepler GL treating it as a string
plot_link_layer.absolute_gap = plot_link_layer.absolute_gap.fillna(0.0)
plot_zone_layer.absolute_gap = plot_zone_layer.absolute_gap.fillna(0.0)
/home/jamie/git/anl/polarislib/venv/lib/python3.12/site-packages/geopandas/array.py:403: UserWarning: Geometry is in a geographic CRS. Results from 'sjoin_nearest' are likely incorrect. Use 'GeoSeries.to_crs()' to re-project geometries to a projected CRS before this operation.
warnings.warn(
/home/jamie/git/anl/polarislib/docs/examples/result_analysis/plot_convergence_analysis.py:111: UserWarning: Geometry is in a geographic CRS. Results from 'centroid' are likely incorrect. Use 'GeoSeries.to_crs()' to re-project geometries to a projected CRS before this operation.
map_center = (zlayer.geometry.centroid.x.mean(), zlayer.geometry.centroid.y.mean())
Cummulative charts#
import seaborn as sns
import matplotlib.pyplot as plt
cumm_links = gap_per_link.sort_values(by=["absolute_gap"], ascending=False).reset_index(drop=True)
cumm_links = cumm_links.assign(cummulative_relative_gap=cumm_links.absolute_gap.cumsum())
cumm_links.cummulative_relative_gap /= cumm_links.cummulative_relative_gap.max()
sns.lineplot(data=cumm_links["cummulative_relative_gap"])
plt.xlabel("link count")

Text(0.5, 23.52222222222222, 'link count')
And map them#
print(
"REFERENCE: And below we map links and zones according to gaps. The maps should look like this, "
"but will need formatting"
)
REFERENCE: And below we map links and zones according to gaps. The maps should look like this, but will need formatting
map_zone_config = {
"version": "v1",
"config": {
"visState": {
"filters": [],
"layers": [
{
"id": "z0w117",
"type": "geojson",
"config": {
"dataId": "Total gaps",
"label": "Total gaps",
"color": [34, 63, 154],
"highlightColor": [252, 242, 26, 255],
"columns": {"geojson": "geometry"},
"isVisible": True,
"visConfig": {
"opacity": 0.8,
"strokeOpacity": 0.8,
"thickness": 0.1,
"strokeColor": [221, 212, 205],
"colorRange": {
"name": "Uber Viz Diverging 1.5",
"type": "diverging",
"category": "Uber",
"colors": ["#00939C", "#5DBABF", "#BAE1E2", "#F8C0AA", "#DD7755", "#C22E00"],
},
"strokeColorRange": {
"name": "Global Warming",
"type": "sequential",
"category": "Uber",
"colors": ["#5A1846", "#900C3F", "#C70039", "#E3611C", "#F1920E", "#FFC300"],
},
"radius": 10,
"sizeRange": [0, 10],
"radiusRange": [0, 50],
"heightRange": [0, 500],
"elevationScale": 27.8,
"enableElevationZoomFactor": True,
"stroked": True,
"filled": True,
"enable3d": True,
"wireframe": False,
},
"hidden": False,
"textLabel": [
{
"field": None,
"color": [255, 255, 255],
"size": 18,
"offset": [0, 0],
"anchor": "start",
"alignment": "center",
}
],
},
"visualChannels": {
"colorField": {"name": "absolute_gap", "type": "integer"},
"colorScale": "quantile",
"strokeColorField": None,
"strokeColorScale": "quantile",
"sizeField": None,
"sizeScale": "linear",
"heightField": {"name": "relative_gap", "type": "real"},
"heightScale": "linear",
"radiusField": None,
"radiusScale": "linear",
},
}
],
"interactionConfig": {
"tooltip": {
"fieldsToShow": {
"Total gaps": [
{"name": "zone", "format": None},
{"name": "absolute_gap", "format": None},
{"name": "relative_gap", "format": ".1%"},
]
},
"compareMode": False,
"compareType": "absolute",
"enabled": True,
},
"brush": {"size": 0.5, "enabled": False},
"geocoder": {"enabled": False},
"coordinate": {"enabled": False},
},
"layerBlending": "normal",
"splitMaps": [],
"animationConfig": {"currentTime": None, "speed": 1},
},
"mapState": {
"bearing": 24,
"dragRotate": True,
"latitude": map_center[1],
"longitude": map_center[0],
"pitch": 50,
"zoom": 9.096117833833905,
"isSplit": False,
},
"mapStyle": {
"styleType": "muted",
"topLayerGroups": {},
"visibleLayerGroups": {
"label": True,
"road": False,
"border": False,
"building": True,
"water": True,
"land": True,
"3d building": False,
},
"threeDBuildingColor": [224.4071295378559, 224.4071295378559, 224.4071295378559],
"mapStyles": {},
},
},
}
from keplergl import KeplerGl
map1 = KeplerGl(height=900, data={"Total gaps": plot_zone_layer}, config=map_zone_config)
map1
User Guide: https://docs.kepler.gl/docs/keplergl-jupyter
KeplerGl(config={'version': 'v1', 'config': {'visState': {'filters': [], 'layers': [{'id': 'z0w117', 'type': 'geojson', 'config': {'dataId': 'Total gaps', 'label': 'Total gaps', 'color': [34, 63, 154], 'highlightColor': [252, 242, 26, 255], 'columns': {'geojson': 'geometry'}, 'isVisible': True, 'visConfig': {'opacity': 0.8, 'strokeOpacity': 0.8, 'thickness': 0.1, 'strokeColor': [221, 212, 205], 'colorRange': {'name': 'Uber Viz Diverging 1.5', 'type': 'diverging', 'category': 'Uber', 'colors': ['#00939C', '#5DBABF', '#BAE1E2', '#F8C0AA', '#DD7755', '#C22E00']}, 'strokeColorRange': {'name': 'Global Warming', 'type': 'sequential', 'category': 'Uber', 'colors': ['#5A1846', '#900C3F', '#C70039', '#E3611C', '#F1920E', '#FFC300']}, 'radius': 10, 'sizeRange': [0, 10], 'radiusRange': [0, 50], 'heightRange': [0, 500], 'elevationScale': 27.8, 'enableElevationZoomFactor': True, 'stroked': True, 'filled': True, 'enable3d': True, 'wireframe': False}, 'hidden': False, 'textLabel': [{'field': None, 'color': [255, 255, 255], 'size': 18, 'offset': [0, 0], 'anchor': 'start', 'alignment': 'center'}]}, 'visualChannels': {'colorField': {'name': 'absolute_gap', 'type': 'integer'}, 'colorScale': 'quantile', 'strokeColorField': None, 'strokeColorScale': 'quantile', 'sizeField': None, 'sizeScale': 'linear', 'heightField': {'name': 'relative_gap', 'type': 'real'}, 'heightScale': 'linear', 'radiusField': None, 'radiusScale': 'linear'}}], 'interactionConfig': {'tooltip': {'fieldsToShow': {'Total gaps': [{'name': 'zone', 'format': None}, {'name': 'absolute_gap', 'format': None}, {'name': 'relative_gap', 'format': '.1%'}]}, 'compareMode': False, 'compareType': 'absolute', 'enabled': True}, 'brush': {'size': 0.5, 'enabled': False}, 'geocoder': {'enabled': False}, 'coordinate': {'enabled': False}}, 'layerBlending': 'normal', 'splitMaps': [], 'animationConfig': {'currentTime': None, 'speed': 1}}, 'mapState': {'bearing': 24, 'dragRotate': True, 'latitude': 40.49083374959828, 'longitude': -88.97889575473327, 'pitch': 50, 'zoom': 9.096117833833905, 'isSplit': False}, 'mapStyle': {'styleType': 'muted', 'topLayerGroups': {}, 'visibleLayerGroups': {'label': True, 'road': False, 'border': False, 'building': True, 'water': True, 'land': True, '3d building': False}, 'threeDBuildingColor': [224.4071295378559, 224.4071295378559, 224.4071295378559], 'mapStyles': {}}}}, data={'Total gaps': zone x ... geometry absolute_gap
0 11 338069.883058 ... MULTIPOLYGON (((-88.90316 40.56121, -88.90311 ... 507.184
1 22 330707.164759 ... MULTIPOLYGON (((-88.99536 40.539, -88.99605 40... 118.618
2 25 335148.199834 ... MULTIPOLYGON (((-88.94809 40.54702, -88.94557 ... 122.993
3 27 336338.870581 ... MULTIPOLYGON (((-88.92499 40.54679, -88.92497 ... 458.232
4 28 335236.733507 ... MULTIPOLYGON (((-88.94796 40.53218, -88.94844 ... 217.770
.. ... ... ... ... ...
179 287 333970.675141 ... MULTIPOLYGON (((-88.9639 40.45445, -88.96297 4... 2639.468
180 292 331511.223925 ... MULTIPOLYGON (((-88.98178 40.46666, -88.98176 ... 1995.777
181 293 330481.680006 ... MULTIPOLYGON (((-89.00495 40.48432, -89.00542 ... 2744.297
182 296 328692.674180 ... MULTIPOLYGON (((-89.02329 40.47078, -89.02377 ... 548.725
183 297 328861.007192 ... MULTIPOLYGON (((-89.0225 40.47905, -89.02391 4... 981.063
[184 rows x 32 columns]}, height=900)
link_config = {
"version": "v1",
"config": {
"visState": {
"filters": [],
"layers": [
{
"id": "xiykhj",
"type": "geojson",
"config": {
"dataId": "Total gaps",
"label": "Total gaps",
"color": [248, 149, 112],
"highlightColor": [252, 242, 26, 255],
"columns": {"geojson": "geometry"},
"isVisible": True,
"visConfig": {
"opacity": 0.8,
"strokeOpacity": 1,
"thickness": 0.5,
"strokeColor": None,
"colorRange": {
"name": "Global Warming",
"type": "sequential",
"category": "Uber",
"colors": ["#5A1846", "#900C3F", "#C70039", "#E3611C", "#F1920E", "#FFC300"],
},
"strokeColorRange": {
"name": "Uber Viz Diverging 3.5",
"type": "diverging",
"category": "Uber",
"colors": [
"#00939C",
"#2FA7AE",
"#5DBABF",
"#8CCED1",
"#BAE1E2",
"#F8C0AA",
"#EB9C80",
"#DD7755",
"#D0532B",
"#C22E00",
],
},
"radius": 10,
"sizeRange": [0.2, 20],
"radiusRange": [0, 50],
"heightRange": [0, 500],
"elevationScale": 5,
"enableElevationZoomFactor": True,
"stroked": True,
"filled": False,
"enable3d": False,
"wireframe": False,
},
"hidden": False,
"textLabel": [
{
"field": None,
"color": [255, 255, 255],
"size": 18,
"offset": [0, 0],
"anchor": "start",
"alignment": "center",
}
],
},
"visualChannels": {
"colorField": None,
"colorScale": "quantile",
"strokeColorField": {"name": "absolute_gap", "type": "integer"},
"strokeColorScale": "quantile",
"sizeField": {"name": "absolute_gap", "type": "integer"},
"sizeScale": "linear",
"heightField": None,
"heightScale": "linear",
"radiusField": None,
"radiusScale": "linear",
},
}
],
"interactionConfig": {
"tooltip": {
"fieldsToShow": {
"Total gaps": [{"name": "link", "format": None}, {"name": "absolute_gap", "format": None}]
},
"compareMode": False,
"compareType": "absolute",
"enabled": True,
},
"brush": {"size": 0.5, "enabled": False},
"geocoder": {"enabled": False},
"coordinate": {"enabled": False},
},
"layerBlending": "normal",
"splitMaps": [],
"animationConfig": {"currentTime": None, "speed": 1},
},
"mapState": {
"bearing": 0,
"dragRotate": False,
"latitude": map_center[1],
"longitude": map_center[0],
"pitch": 0,
"zoom": 8.42575627208353,
"isSplit": False,
},
"mapStyle": {
"styleType": "muted",
"topLayerGroups": {},
"visibleLayerGroups": {
"label": False,
"road": False,
"border": False,
"building": True,
"water": True,
"land": True,
"3d building": False,
},
"threeDBuildingColor": [224.4071295378559, 224.4071295378559, 224.4071295378559],
"mapStyles": {},
},
},
}
from keplergl import KeplerGl
map2 = KeplerGl(height=900, data={"Total gaps": plot_link_layer}, config=link_config)
map2
User Guide: https://docs.kepler.gl/docs/keplergl-jupyter
KeplerGl(config={'version': 'v1', 'config': {'visState': {'filters': [], 'layers': [{'id': 'xiykhj', 'type': 'geojson', 'config': {'dataId': 'Total gaps', 'label': 'Total gaps', 'color': [248, 149, 112], 'highlightColor': [252, 242, 26, 255], 'columns': {'geojson': 'geometry'}, 'isVisible': True, 'visConfig': {'opacity': 0.8, 'strokeOpacity': 1, 'thickness': 0.5, 'strokeColor': None, 'colorRange': {'name': 'Global Warming', 'type': 'sequential', 'category': 'Uber', 'colors': ['#5A1846', '#900C3F', '#C70039', '#E3611C', '#F1920E', '#FFC300']}, 'strokeColorRange': {'name': 'Uber Viz Diverging 3.5', 'type': 'diverging', 'category': 'Uber', 'colors': ['#00939C', '#2FA7AE', '#5DBABF', '#8CCED1', '#BAE1E2', '#F8C0AA', '#EB9C80', '#DD7755', '#D0532B', '#C22E00']}, 'radius': 10, 'sizeRange': [0.2, 20], 'radiusRange': [0, 50], 'heightRange': [0, 500], 'elevationScale': 5, 'enableElevationZoomFactor': True, 'stroked': True, 'filled': False, 'enable3d': False, 'wireframe': False}, 'hidden': False, 'textLabel': [{'field': None, 'color': [255, 255, 255], 'size': 18, 'offset': [0, 0], 'anchor': 'start', 'alignment': 'center'}]}, 'visualChannels': {'colorField': None, 'colorScale': 'quantile', 'strokeColorField': {'name': 'absolute_gap', 'type': 'integer'}, 'strokeColorScale': 'quantile', 'sizeField': {'name': 'absolute_gap', 'type': 'integer'}, 'sizeScale': 'linear', 'heightField': None, 'heightScale': 'linear', 'radiusField': None, 'radiusScale': 'linear'}}], 'interactionConfig': {'tooltip': {'fieldsToShow': {'Total gaps': [{'name': 'link', 'format': None}, {'name': 'absolute_gap', 'format': None}]}, 'compareMode': False, 'compareType': 'absolute', 'enabled': True}, 'brush': {'size': 0.5, 'enabled': False}, 'geocoder': {'enabled': False}, 'coordinate': {'enabled': False}}, 'layerBlending': 'normal', 'splitMaps': [], 'animationConfig': {'currentTime': None, 'speed': 1}}, 'mapState': {'bearing': 0, 'dragRotate': False, 'latitude': 40.49083374959828, 'longitude': -88.97889575473327, 'pitch': 0, 'zoom': 8.42575627208353, 'isSplit': False}, 'mapStyle': {'styleType': 'muted', 'topLayerGroups': {}, 'visibleLayerGroups': {'label': False, 'road': False, 'border': False, 'building': True, 'water': True, 'land': True, '3d building': False}, 'threeDBuildingColor': [224.4071295378559, 224.4071295378559, 224.4071295378559], 'mapStyles': {}}}}, data={'Total gaps': link name node_a ... geometry link_id absolute_gap
0 4 Landmark Drive 6 ... LINESTRING (-88.95543 40.51243, -88.95539 40.5... 4.0 6.000
1 6 Landmark Drive 7 ... LINESTRING (-88.95539 40.51136, -88.95538 40.5... 6.0 6.000
2 10 Mecherle Drive 12 ... LINESTRING (-88.9607 40.49187, -88.96029 40.49... 10.0 7.000
3 11 Mecherle Drive 14 ... LINESTRING (-88.96336 40.49358, -88.96151 40.4... NaN 0.000
4 12 Mecherle Drive 13 ... LINESTRING (-88.96029 40.49126, -88.96007 40.4... NaN 0.000
... ... ... ... ... ... ... ...
4522 5993 Brigham School Road 3742 ... LINESTRING (-89.00205 40.44163, -89.00538 40.4... 5993.0 5.584
4523 5994 South Main Street 3151 ... LINESTRING (-88.99098 40.4416, -88.9912 40.44586) 5994.0 15.104
4524 5995 South Main Street 3743 ... LINESTRING (-88.9912 40.44586, -88.99125 40.44... 5995.0 7.000
4525 5996 South Main Street 3318 ... LINESTRING (-88.9921 40.45005, -88.99242 40.45... 5996.0 12.051
4526 5997 South Main Street 3744 ... LINESTRING (-88.99246 40.45429, -88.99247 40.4... 5997.0 26.483
[4527 rows x 23 columns]}, height=900)
Total running time of the script: (0 minutes 1.735 seconds)