Service Provision Analysis¶
This notebook demonstrates how to analyze service accessibility from buildings using precomputed distances:
Compute basic service provision
Adjust provision thresholds
Clip provision to specific subareas
# Import necessary libraries
from objectnat import (
get_service_provision,
get_provision_buildings,
get_provision_services,
get_provision_links,
recalculate_links,
clip_provision,
)
import geopandas as gpd
import pandas as pd
1. Load Input Data¶
Load buildings, services, and a distance matrix of travel costs between them. All layers are reprojected to UTM (EPSG:32636) for consistency.
# Load datasets
buildings = gpd.read_parquet("examples_data/buildings.parquet")
services = gpd.read_parquet("examples_data/services.parquet")
distance_matrix = pd.read_parquet("examples_data/matrix_time.parquet")
2. Compute Initial Service Provision¶
Compute how well buildings are served by nearby services using the get_service_provision() function.
The threshold parameter defines the maximum distance or time for service availability.
# Compute service provision using a threshold of 10 (e.g., minutes)
provision_result = get_service_provision(
buildings=buildings,
services=services,
distance_matrix=distance_matrix,
threshold=10
)
buildings_prov = get_provision_buildings(buildings, provision_result)
services_prov = get_provision_services(services, provision_result)
links_prov = get_provision_links(buildings, services, provision_result)
# The result stores sparse flows; helper functions attach metrics and build link geometries.
2026-07-10 13:12:07.291 | WARNING | buildings_gdf already contains provision columns that will be overwritten: ['demand']
2026-07-10 13:12:07.294 | WARNING | services_gdf already contains provision columns that will be overwritten: ['capacity']
3. Visualize Service Provision¶
Use an interactive map to inspect which buildings are well-served and which are underserved.
# Visualize provision by average distance to services
m = buildings_prov.reset_index().explore(column="avg_dist", cmap="RdYlGn_r", tiles="CartoDB positron")
# Overlay service locations (in red)
services_prov.explore(m=m, color="red")
# Uncomment to show service links (color-coded by service index)
# links_prov.explore(m=m, column='service_index', cmap='prism', style_kwds={'opacity': 0.5})
4. Recalculate Provision with New Threshold¶
Update the service provision based on a new threshold (e.g., longer acceptable walking or travel time).
# Determine color scaling from original results
vmax = buildings_prov['avg_dist'].max()
# Recompute provision using a threshold of 15
provision_result2 = recalculate_links(provision_result, new_max_dist=15)
buildings_prov2 = get_provision_buildings(buildings, provision_result2)
services_prov2 = get_provision_services(services, provision_result2)
links_prov2 = get_provision_links(buildings, services, provision_result2)
# Visualize updated provision with consistent color scale
m2 = buildings_prov2.reset_index().explore(column="avg_dist", cmap="RdYlGn_r", tiles="CartoDB positron", vmax=vmax)
services_prov2.explore(m=m2, color="red")
# Uncomment to show service links (color-coded by service index)
# links_prov2.explore(m=m2, column='service_index', cmap='prism', style_kwds={'opacity': 0.5})
2026-07-10 13:12:08.172 | WARNING | buildings_gdf already contains provision columns that will be overwritten: ['demand']
2026-07-10 13:12:08.176 | WARNING | services_gdf already contains provision columns that will be overwritten: ['capacity']
5. Clip Provision to a Subarea¶
Limit the analysis to a specific geographic region using any interested area.
# Select a few buildings and buffer them to define a clipping area
clip_area = buildings.iloc[500:503].copy()
clip_area["geometry"] = clip_area.geometry.buffer(500)
# Clip provision to selected subarea
buildings_prov_clipped, services_prov_clipped, links_prov_clipped = clip_provision(
buildings_prov2,
services_prov2,
links_prov2,
selection_zone=clip_area
)
# Visualize the clipped results
m3 = buildings_prov_clipped.reset_index().explore(column="avg_dist", cmap="RdYlGn_r", tiles="CartoDB positron",
vmax=vmax)
services_prov_clipped.explore(m=m3, color="red")
# Uncomment to show service links (color-coded by service index)
# links_prov_clipped.explore(m=m3, column='service_index', cmap='prism', style_kwds={'opacity': 0.5})