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, recalculate_links, clip_provision
import geopandas as gpd
import pandas as pd

1. Load Input Data

Load buildings, services, and an adjacency matrix of distances or travel times 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")
adjacency_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)
buildings_prov, services_prov, links_prov = get_service_provision(
    buildings=buildings,
    services=services,
    adjacency_matrix=adjacency_matrix,
    threshold=10
)
# This returns updated buildings, services, and links GeoDataFrames with provision status and metrics.

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
buildings_prov2, services_prov2, links_prov2 = recalculate_links(
    buildings_prov,
    services_prov,
    links_prov,
    new_max_dist=15
)

# 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})

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})