Graph Coverage Zones from Points

Coverage zones represent areas that can be reached from multiple source points within a certain time or distance limit using a transport network. They are built by calculating reachability per point, generating Voronoi polygons, and optionally clipping them to a defined boundary.


The library supports several methods for generating coverage zones, depending on whether you use a full transport graph or simplified geometric rules.


Coverage Using Transport Graph

Uses a full routing engine to determine reachable areas per point, then builds coverage zones based on actual network paths.

objectnat.get_graph_coverage(urban_graph, *, gdf_destinations=None, destination_nodes=None, graph_node_column='graph_node_id', weight_type='time_min', geometry_type=None, weight_value_cutoff=None, zone=None, buffer_factor=0.7, road_buffer_size=5.0)[source]

Calculate coverage zones from source objects through a graph network using Dijkstra reachability and Voronoi partitioning.

Coverage answers “which area is served by each source object”. The function:

  1. Snaps each source object to its nearest graph node (or uses the provided destination_nodes).

  2. Runs a multi-source Dijkstra search on the reversed graph, so every reachable node is labelled with its nearest source within weight_value_cutoff.

  3. Builds Voronoi polygons around the graph nodes.

  4. Dissolves the reachable Voronoi cells per source into one zone each.

  5. Clips the result to zone, to a residual-radius / road geometry (geometry_type), or to the concave hull of the reachable nodes.

Parameters:
  • urban_graph (UrbanGraph) – City graph with node (nodes_gdf) and edge (edges_gdf) tables.

  • gdf_destinations (geopandas.GeoDataFrame, optional) – Source objects the coverage is measured to. If the table already contains graph_node_column those node ids are used directly; otherwise each geometry is snapped to its nearest graph node. Pass either this or destination_nodes.

  • destination_nodes (Iterable, optional) – Ready-made source node ids, used instead of gdf_destinations.

  • graph_node_column (str) – Name of the column holding graph node ids in gdf_destinations.

  • weight_type (Literal['time_min', 'length_meter']) –

    Type of edge weight used for path calculation:

    • "time_min": edge travel time in minutes

    • "length_meter": edge length in meters

  • geometry_type (Optional[Literal['radius', 'ways']]) –

    Optional refinement of the coverage shape:

    • None: raw Voronoi cells clipped to zone or the concave hull

    • "radius": additionally clip to residual-radius buffers around reachable nodes (remaining budget converted to distance)

    • "ways": additionally clip to buffered road geometry inside the residual radii (walk edges only on intermodal/walk graphs)

    Requires weight_value_cutoff when set.

  • weight_value_cutoff (float, optional) – Maximum path cost, e.g. max travel time or distance. Units depend on weight_type.

  • zone (gpd.GeoDataFrame | gpd.GeoSeries, optional) – Boundary polygon to clip the resulting zones. If None and no geometry_type is given, the concave hull of the reachable nodes is used.

  • buffer_factor (float) – Multiplier for the residual radius when geometry_type is set (default 0.7).

  • road_buffer_size (float) – Buffer applied to graph edges for geometry_type="ways", in meters (default 5.0).

Returns:

One coverage polygon per source object, returned in the CRS of gdf_destinations (or the graph CRS when node ids are passed). The index matches gdf_destinations / destination_nodes.

Return type:

gpd.GeoDataFrame

Notes

  • For a directed graph the search runs on the reversed edges, so a zone describes the area from which its source can be reached.

  • An empty GeoDataFrame is returned when nothing is reachable.


coverage_zones_time_10min

Coverage zones generated by travel time (10 minutes) on a transport graph.


coverage_zones_distance_600m

Coverage zones generated by distance (600 meters) on a transport graph.


Coverage Using Radius Only

Generates fixed radius-based buffers per point without routing, then merges or clips them via Voronoi diagrams for cleaner borders.

objectnat.get_radius_coverage(gdf_from, radius, resolution=32)[source]

Calculate radius-based coverage zones using Voronoi polygons.

This is a graph-free coverage: zones are built purely from the source points, a fixed radius and a Voronoi partition, with no network involved.

Parameters:
  • gdf_from (geopandas.GeoDataFrame) – Source points for which coverage zones are calculated.

  • radius (float) – Maximum coverage radius in meters.

  • resolution (int) – Number of segments used to approximate quarter-circle in buffer (default=32).

Returns:

GeoDataFrame with smoothed coverage zone polygons in the same CRS as original gdf_from.

Return type:

gpd.GeoDataFrame

Notes

  • Automatically converts to local UTM CRS for accurate distance measurements

  • Final zones are slightly contracted then expanded for smoothing effect


coverage_zones_distance_radius_voronoi

Radius-based coverage zones (800 meters) with Voronoi clipping.


Stepped Graph Coverage

Creates multi-step coverage zones (e.g., 5, 10, 15 minutes) using the full transport graph for each source point.

objectnat.get_stepped_graph_coverage(urban_graph, *, gdf_destinations=None, destination_nodes=None, graph_node_column='graph_node_id', weight_type='time_min', geometry_type='radius', weight_value_cutoff=None, zone=None, step=None, buffer_factor=0.7, road_buffer_size=5.0)[source]

Calculate stepped coverage zones from source objects, combining graph reachability with banded (stepped) isochrone geometry.

Like get_graph_coverage(), but instead of one zone per source the reachable area is split into concentric bands of width step. The function:

  1. Snaps each source object to its nearest graph node (or uses the provided destination_nodes).

  2. Runs a multi-source Dijkstra search on the reversed graph, labelling every reachable node with the distance to its nearest source.

  3. Buckets the nodes into steps and builds banded geometry with the selected geometry_type.

  4. Optionally clips the bands to zone.

Parameters:
  • urban_graph (UrbanGraph) – City graph with node and edge tables.

  • gdf_destinations (geopandas.GeoDataFrame, optional) – Source objects the coverage is measured to. If the table contains graph_node_column those ids are used; otherwise geometries are snapped to nearest nodes. Pass either this or destination_nodes.

  • destination_nodes (Iterable, optional) – Ready-made source node ids, used instead of gdf_destinations.

  • graph_node_column (str) – Name of the graph node id column in gdf_destinations.

  • weight_type (Literal['time_min', 'length_meter']) –

    Type of edge weight used for path calculation:

    • "time_min": edge travel time in minutes

    • "length_meter": edge length in meters

  • geometry_type (Optional[Literal['radius', 'ways', 'separate']]) –

    Method used to build each step’s geometry:

    • None: Voronoi cells around graph nodes

    • "radius": Voronoi cells clipped to residual-radius buffers

    • "ways": Voronoi cells clipped to buffered road geometry (walk edges only on intermodal/walk graphs)

    • "separate": independent circular buffers per step

  • weight_value_cutoff (float, optional) – Maximum path cost limiting the coverage extent. If None, the farthest reachable node defines the extent.

  • zone (gpd.GeoDataFrame | gpd.GeoSeries, optional) – Boundary polygon to clip the resulting stepped zones.

  • step (float, optional) – Width of each step, in units of weight_type. Defaults to 100 meters for length_meter and 1 minute for time_min.

  • buffer_factor (float) – Residual-radius multiplier for "radius", "ways" and "separate" (default 0.7).

  • road_buffer_size (float) – Edge buffer for geometry_type="ways", in meters (default 5.0).

Returns:

Stepped coverage polygons with a dist column (the upper bound of each step, in units of weight_type) and geometry, returned in the CRS of gdf_destinations (or the graph CRS).

Return type:

gpd.GeoDataFrame

Notes

  • For a directed graph the search runs on the reversed edges; for an undirected graph on the original symmetric adjacency.

  • An empty GeoDataFrame is returned when nothing is reachable.

stepped_coverage_zones_separate

Stepped coverage zones displayed as separate intervals.


stepped_coverage_zones_voronoi

Stepped coverage zones merged using Voronoi partitioning.


Note

Coverage zones are a powerful tool for evaluating service accessibility, network efficiency, and urban reachability.


Example notebook

Graph Coverage Analysis for Service Points