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:
Snaps each source object to its nearest graph node (or uses the provided
destination_nodes).Runs a multi-source Dijkstra search on the reversed graph, so every reachable node is labelled with its nearest source within
weight_value_cutoff.Builds Voronoi polygons around the graph nodes.
Dissolves the reachable Voronoi cells per source into one zone each.
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 containsgraph_node_columnthose node ids are used directly; otherwise each geometry is snapped to its nearest graph node. Pass either this ordestination_nodes.destination_nodes (
Iterable, optional) – Ready-made source node ids, used instead ofgdf_destinations.graph_node_column (
str) – Name of the column holding graph node ids ingdf_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 tozoneor 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_cutoffwhen set.weight_value_cutoff (
float, optional) – Maximum path cost, e.g. max travel time or distance. Units depend onweight_type.zone (
gpd.GeoDataFrame | gpd.GeoSeries, optional) – Boundary polygon to clip the resulting zones. IfNoneand nogeometry_typeis given, the concave hull of the reachable nodes is used.buffer_factor (
float) – Multiplier for the residual radius whengeometry_typeis set (default 0.7).road_buffer_size (
float) – Buffer applied to graph edges forgeometry_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 matchesgdf_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
GeoDataFrameis returned when nothing is reachable.
Coverage zones generated by travel time (10 minutes) on a transport graph.¶
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
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 widthstep. The function:Snaps each source object to its nearest graph node (or uses the provided
destination_nodes).Runs a multi-source Dijkstra search on the reversed graph, labelling every reachable node with the distance to its nearest source.
Buckets the nodes into steps and builds banded geometry with the selected
geometry_type.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 containsgraph_node_columnthose ids are used; otherwise geometries are snapped to nearest nodes. Pass either this ordestination_nodes.destination_nodes (
Iterable, optional) – Ready-made source node ids, used instead ofgdf_destinations.graph_node_column (
str) – Name of the graph node id column ingdf_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. IfNone, 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 ofweight_type. Defaults to 100 meters forlength_meterand 1 minute fortime_min.buffer_factor (
float) – Residual-radius multiplier for"radius","ways"and"separate"(default 0.7).road_buffer_size (
float) – Edge buffer forgeometry_type="ways", in meters (default 5.0).
- Returns:
Stepped coverage polygons with a
distcolumn (the upper bound of each step, in units ofweight_type) andgeometry, returned in the CRS ofgdf_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
GeoDataFrameis returned when nothing is reachable.
Stepped coverage zones displayed as separate intervals.¶
Stepped coverage zones merged using Voronoi partitioning.¶
Note
Coverage zones are a powerful tool for evaluating service accessibility, network efficiency, and urban reachability.