Service Area Planning and Coverage Optimization

Purpose

Service Area Planning and Coverage Optimization delineates areas reachable from facilities (ambulance stations, distribution centers, cell towers) within time, distance, or cost thresholds. Identifies coverage gaps, overlap, and optimization opportunities.

Use this tool for coverage diagnostics around an existing facility network. For candidate site generation/selection workflows (for example top-N new-site selection), use market_access_and_site_intelligence_workflow.

Typical Questions This Tool Helps Answer

  • Which neighborhoods are reachable from our current facilities within 5, 10, and 15 minutes?
  • Where are the uncovered demand gaps after applying realistic travel-time, turn, and impedance constraints?
  • If one or more facilities close, how much coverage do we lose and where?

Background

Service-area planning estimates reachability from facilities under impedance constraints, then uses demand overlays to evaluate coverage quality and candidate expansion strategies.

For a demand location $i$ and facility set $F$, a common reachability criterion is:

$$\min_{f\in F} c(i,f) \le \tau$$

Where $c(i,f)$ is network travel cost and $\tau$ is a service threshold (for example response-time target).

Coverage and Equity Framing

Coverage optimization can be represented as maximizing covered demand mass under budget/facility constraints:

$$\max \sum_i d_i z_i, \quad z_i\in{0,1}$$

With optional equity controls to prevent improvements that systematically bypass low-access populations.

Methodological Considerations

  • Validate impedance and turn restrictions before catchment construction.
  • Evaluate multiple threshold values ($\tau$) to expose sensitivity of underserved-area mapping.
  • Compare baseline and candidate-network states under disruption scenarios, not just normal operating conditions.

Practical Interpretation Pitfalls

Common mistakes include reading coverage gain without equity context, ignoring threshold sensitivity, and over-trusting edge-of-network catchments where data quality is weaker.

Inputs

ParameterTypeRequiredDescription
networkVector (LineString or MultiLineString)YesNetwork layer used to derive service areas
facilitiesVector (Point or MultiPoint)YesFacility origin points
demand_pointsVector (Point, MultiPoint, Polygon, or MultiPolygon)NoOptional demand layer used for uncovered-demand and KPI calculations. Polygon features are converted to interior representative points.
ring_costsArrayYesPositive cost thresholds, e.g., [5, 10, 15]
scenariosCSVNoOptional scenario variants for open/closed facilities
service_area_merge_originsBooleanNoIf true, dissolve overlapping origin polygons into merged coverage per ring in service_areas output. Default: false.
optimization_modeStringNoOne of existing (default) or expansion.
candidate_modeStringNoExpansion candidate source: generated (default) or user_supplied. Ignored in existing mode.
candidate_sitesVector (Point or MultiPoint)NoRequired when optimization_mode=expansion and candidate_mode=user_supplied.
num_sites_to_selectIntegerNoNumber of expansion sites to select (default 1).
selection_strategyStringNoExpansion selection strategy: single_best (default) or top_k_greedy.
min_new_site_separationNumberNoMinimum spacing between selected expansion sites (map units).
max_generated_candidatesIntegerNoCandidate cap used when candidate_mode=generated (default 250).
ranked_candidates_vectorString pathNoOptional output vector path for ranked candidate sites with coverage-gain metrics.
edge_cost_fieldStringNoNumeric line field used as impedance. If omitted, Euclidean arc length is used.
mode_fieldStringNoField identifying transport mode per edge (e.g. walk, bus, car).
default_mode_speedNumberNoDefault speed (km/h) for mode-speed conversion when no mode-specific override matches.
mode_speed_overridesStringNoComma-separated mode:speed overrides, e.g. walk:5,bus:30.
allowed_modesStringNoComma-separated list of permitted modes, e.g. "walk,bus".
one_way_fieldStringNoField encoding one-way restrictions; accepts FT/TF/B codes and legacy boolean values.
node_cost_pointsVector (Point or MultiPoint)NoOptional point layer containing node/intersection entry-cost observations.
node_cost_fieldStringNoNumeric field in node_cost_points containing non-negative node entry costs.
node_cost_snap_distanceNumberNoOptional max assignment distance from each node-cost point to the nearest network node.
turn_penaltyNumberNoCost added for each standard turn (use the same units as edge_cost_field).
u_turn_penaltyNumberNoAdditional cost for U-turns.
forbid_u_turnsBooleanNoIf true, U-turns are forbidden at all nodes.
forbid_left_turnsBooleanNoIf true, all left turns are forbidden.
forbid_right_turnsBooleanNoIf true, all right turns are forbidden.
turn_restrictions_csvCSVNoPer-turn transition table with columns prev_x,prev_y,node_x,node_y,next_x,next_y; optional forbidden and turn_cost (or penalty/cost/extra_cost).
temporal_cost_profileCSVNoTime-of-day speed profile CSV for scheduled routing.
temporal_edge_id_fieldStringNoNetwork edge ID field that matches profile keys.
departure_timeStringNoISO-8601 departure time for temporal routing, e.g. "2024-06-15T08:00:00Z".
temporal_modeStringNoOne of multiplier or absolute.
temporal_fallbackStringNoFallback when no matching profile entry exists: static_cost or error.

Input Requirements

  • network must contain line geometries.
  • facilities must contain point geometries.
  • If CRS is known, projected CRS is required.
  • ring_costs must be numeric and strictly greater than zero.
  • scenarios file path must exist when provided.
  • candidate_sites is required when optimization_mode=expansion and candidate_mode=user_supplied.

scenarios CSV Schema (Authoritative)

Expected columns (in order):

scenario_id,facility_id,is_open,capacity

capacity is optional.

Accepted truthy values for is_open: 1, true, yes, y, open.

Example:

scenario_id,facility_id,is_open,capacity
all_open,1,true,100
all_open,2,true,100
one_open,1,true,100
one_open,2,false,0

Temporal Profile CSV Schema (Time-of-Day Routing)

The temporal_cost_profile CSV uses one row per edge and time window.

Expected columns:

edge_id,dow,start_minute,end_minute,value

Column definitions:

  • edge_id: Edge key matching temporal_edge_id_field in the network layer.
  • dow: Day of week (1..7, Monday=1).
  • start_minute: Inclusive minute-of-day (0..1439).
  • end_minute: Exclusive minute-of-day (1..1440, must be greater than start_minute).
  • value: Positive temporal modifier.

temporal_mode determines how value is interpreted:

  • multiplier: applies value as a multiplier to static edge cost.
  • absolute: treats value as the full edge cost for that time window.

Example (weekday AM peak slowdown on selected edges):

edge_id,dow,start_minute,end_minute,value
A_B,1,420,600,1.8
B_C,1,420,600,1.6
A_B,2,420,600,1.8
B_C,2,420,600,1.6

Set temporal_fallback to:

  • static_cost to use non-temporal impedance when no matching row exists.
  • error to fail fast when a temporal row is missing.

Parameters

ParameterTypeRequiredDescription
service_areasString pathYesOutput vector path for service area polygons
uncovered_demandString pathYesOutput vector path for uncovered demand points
scenario_summary_csvString pathYesOutput CSV path for scenario KPIs
ranked_candidates_csvString pathYesOutput CSV path for candidate ranking
html_reportString pathNoOptional HTML summary report output

Output Path Behavior

  • Vector format is inferred from extension for service_areas and uncovered_demand.
  • Unsupported vector extensions fail validation.
  • html_report is emitted only when path is provided.

Outputs

Output artifact keys below are runtime outputs, not input parameters.

ArtifactRuntime Output KeyTypeDescription
Service areas layerservice_areasVector (Polygon/MultiPolygon)Network-derived multi-ring service areas
Uncovered demand layeruncovered_demandVector (Point)Demand points outside baseline service areas
Scenario summary reportscenario_summary_csvCSVScenario-level coverage/accessibility KPIs
Ranked candidates reportranked_candidates_csvCSVCandidate ranking by coverage gain and travel cost
Summary payloadsummaryJSON (result payload)Output path summary for orchestration
Optional reporthtml_reportHTMLOptional HTML summary report output when requested

uncovered_demand Schema

Geometry type: Point

Attributes:

  • demand_id

scenario_summary_csv Schema

scenario_id,total_demand_covered_pct,avg_accessibility,outlier_count

Notes:

  • Includes a baseline row.
  • total_demand_covered_pct is coverage percentage.
  • avg_accessibility is currently populated from the largest configured ring cost.

ranked_candidates_csv Schema

candidate_id,coverage_gain_pct,avg_network_travel_cost,rank

Result Payload Keys

  • service_areas
  • uncovered_demand
  • scenario_summary_csv
  • ranked_candidates_csv
  • summary
  • html_report (when requested)

Example

import whitebox_workflows as wbw

wbe = wbw.WbEnvironment()
wbe.service_area_planning_and_coverage_optimization(
        network="road_network.shp",
        facilities="fire_stations.shp",
        demand_points="residential_blocks.shp",
        ring_costs=[4.0, 8.0, 12.0],
        service_area_merge_origins=True,
        scenarios="coverage_scenarios.csv",
        service_areas="out/service_areas.geojson",
        uncovered_demand="out/uncovered_demand.geojson",
        scenario_summary_csv="out/scenario_summary.csv",
        ranked_candidates_csv="out/ranked_candidates.csv",
        html_report="out/service_area_report.html"
)

The example below adds time-of-day routing and turn penalties for a peak-hour coverage analysis.

wbe.service_area_planning_and_coverage_optimization(
        network="road_network.shp",
        facilities="fire_stations.shp",
        demand_points="residential_blocks.shp",
        ring_costs=[4.0, 8.0, 12.0],
        scenarios="coverage_scenarios.csv",
        edge_cost_field="MINUTES",
        one_way_field="ONEWAY",
        node_cost_points="intersection_delay_points.shp",
        node_cost_field="DELAY_MIN",
        node_cost_snap_distance=25.0,
        turn_penalty=0.3,
        u_turn_penalty=2.0,
        forbid_u_turns=True,
        temporal_cost_profile="am_peak_profiles.csv",
        temporal_edge_id_field="EDGE_ID",
        departure_time="2024-06-15T08:00:00Z",
        temporal_mode="multiplier",
        temporal_fallback="static_cost",
        service_areas="out/service_areas_am_peak.geojson",
        uncovered_demand="out/uncovered_demand_am_peak.geojson",
        scenario_summary_csv="out/scenario_summary_am_peak.csv",
        ranked_candidates_csv="out/ranked_candidates_am_peak.csv",
        html_report="out/service_area_report_am_peak.html"
)

Any WbEnvironment instance name is valid (wbe above is only an example).

Isochrone Map Recipe (Pro Tier)

To produce map-ready drive-time isochrones from facilities:

  1. Set ring_costs to your target bands (for example [5, 10, 15] minutes).
  2. Use a travel-time edge impedance field (for example edge_cost_field="MINUTES").
  3. Write service_areas to a polygon-capable output format (.gpkg, .geojson, .shp).
  4. Optionally add turn_penalty, u_turn_penalty, and node_cost_points for realistic intersection behavior.
  5. Optionally add temporal_cost_profile + departure_time for time-of-day isochrones.

Minimal multi-band isochrone example:

wbe.service_area_planning_and_coverage_optimization(
        network="road_network.gpkg",
        facilities="clinics.gpkg",
        ring_costs=[5.0, 10.0, 15.0],
        edge_cost_field="MINUTES",
        one_way_field="ONEWAY",
        service_areas="out/isochrones_5_10_15.gpkg",
        uncovered_demand="out/uncovered.gpkg",
        scenario_summary_csv="out/scenario_summary.csv",
        ranked_candidates_csv="out/ranked_candidates.csv"
)

References

  • Church, R., & ReVelle, C. (1974). "The Maximal Covering Location Problem." Papers and Proceedings of the Regional Science Association 32(1), 101–118.

Parameter Interaction Notes

For Service Area Planning and Coverage Optimization, output quality is most sensitive to parameter combinations rather than single values in isolation.

  • Wider ring_costs raise coverage but can reduce discriminative power in candidate ranking.
  • Sparse facilities can produce high uncovered-demand counts even with large rings when network topology is fragmented.
  • Scenario toggles in scenarios can shift rank ordering substantially; compare against baseline before acting.

QA and Acceptance Criteria

Use a staged acceptance approach for Service Area Planning and Coverage Optimization:

  1. Input integrity: validate projected CRS, network/facility geometry types, and positive ring costs.
  2. Method validity: verify baseline coverage against known served and unserved demand points.
  3. Output plausibility: confirm uncovered demand points are outside generated service polygons.
  4. Reproducibility: rerun with identical inputs and confirm stable scenario and ranking outputs.

Recommended acceptance checks:

  • All four required output artifacts are present and readable.
  • scenario_summary_csv includes baseline and any scenario IDs supplied.
  • ranked_candidates_csv ranks candidates from 1..N with no missing IDs.
  • uncovered_demand feature count aligns with expected coverage gaps.

Advanced Operational Guidance

For production deployment of Service Area Planning and Coverage Optimization:

  • Maintain fixed ring profiles (e.g., tactical, planning, policy) and avoid ad hoc threshold drift.
  • Store run metadata with input hashes, parameter JSON, and timestamp for auditability.
  • Use scenario IDs that map directly to planning decisions (for example, depot closure simulations).
  • Gate relocation recommendations on consistent baseline-vs-scenario deltas.

Implementation Patterns

Common implementation patterns with Service Area Planning and Coverage Optimization:

  • Baseline run: produce current-state service area and uncovered-demand diagnostics.
  • Scenario run: toggle facilities via scenarios CSV for closure/expansion analysis.
  • Candidate run: compare rank shifts using ranked_candidates_csv.
  • Release run: publish decision package with baseline + scenario evidence.

Use Service Area Planning and Coverage Optimization together with upstream conditioning and downstream validation tools in the same bundle to ensure end-to-end consistency and stronger decision confidence.

When To Use This Workflow

Service Area Planning and Coverage Optimization is most valuable when teams need defendable service-coverage decisions across baseline and what-if facility scenarios.

What this workflow helps you achieve:

  • Converts network accessibility into scenario-ready planning evidence.
  • Quantifies uncovered demand to support expansion or relocation decisions.
  • Creates a repeatable coverage governance workflow.

Results Delivery Checklist

Before sharing results with stakeholders:

  1. Validate network topology and impedance attributes for all served areas.
  2. Confirm ring-cost profile aligns with policy and service-level commitments.
  3. Document baseline and scenario assumptions in the deliverable package.
  4. Provide uncovered-demand deltas and candidate rank changes.
  5. Include at least one stress scenario (closure or demand shift).

Common Questions

Q: Why did candidate ranking change so much after a small ring-cost change?
A: Candidate ranking is sensitive to threshold cutoffs; small ring adjustments can move many demand points across covered/uncovered boundaries.

Q: What does avg_accessibility represent in the scenario summary?
A: In current implementation it is populated from the largest configured ring-cost threshold and should be interpreted as a planning proxy, not a per-demand mean travel-time statistic.

Q: Why do we still have uncovered demand with large service rings?
A: Uncovered points often indicate network disconnects or facility placement limitations, not just threshold selection.