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})
Make this Notebook Trusted to load map: File -> Trust Notebook

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']
Make this Notebook Trusted to load map: File -> Trust Notebook

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})
Make this Notebook Trusted to load map: File -> Trust Notebook