Skip to content

Network

Road/rail-network-constrained distance: build a routable graph from Overture Maps transportation data, snap trajectory points to it, and query network (not straight-line) distance via a Rust contraction-hierarchy router.

Build a network

API Description Example
fetch_road_network Fetch and build a car-routable graph from Overture road segments. Trajectory and road network
build_road_graph Load a saved road graph from disk, or fetch it from Overture Maps and save it. Trajectory and road network
fetch_rail_network Fetch rail segments from Overture Maps and build a bidirectional rail graph. Rail network
build_rail_graph Load a saved rail graph from disk, or fetch it from Overture Maps and save it. Rail network
RoadNetwork A road (or rail) network prepared once (contraction hierarchy) and reused for many point-to-point physical-distance queries. Distances and routes on the network
RoadNetwork.batch_distances Batch route-length (metres) query for (from_node, to_node) pairs. Distances and routes on the network
RoadNetwork.batch_routes Batch route-geometry query for (from_node, to_node) pairs. Distances and routes on the network
RoadNetwork.build Prepare a contraction hierarchy from a road/rail graph's edges. Trajectory and road network

Snap, route and match

API Description Example
snap_locations_to_graph Snap each tessellation row to its nearest road/rail graph node. Snap points to the network
haversine_m_batch Compute distances in metres; prefer fastmob.utils.haversine.
match_trajectory Map-match a trajectory with a directed-edge HMM/Viterbi model. Match a GPS trace to roads
od_desire_lines Aggregate OD-pair flows onto the road/rail graph's edges (desire lines). Accumulate flows on roads

Measures along the road network

API Description Example
jump_lengths_road Jump lengths (km) measured along the road network. Road distance versus straight line
radius_of_gyration_road Radius of gyration (km) per user, measured along the road network. Road distance versus straight line

fetch_road_network and fetch_rail_network require DuckDB: install it with pip install duckdb. Snapping uses Fastkit-Mobility's native Rust spatial index and has no additional Python dependency.

For a worked walk-through (build a network, snap points, compare road and straight-line distances, accumulate flows, match a GPS trace) see Road networks: matching, routing and route flows and the concept page Roads, rails and map matching. Node ids passed to the distance, route and desire-line functions come from snap_locations_to_graph; an unsnapped node is -1.


fetch_road_network(min_lon, min_lat, max_lon, max_lat, overture_release)

Fetch and build a car-routable graph from Overture road segments.

Parameters:

Name Type Description Default
min_lon float

Western edge of the bounding box, in decimal degrees.

required
min_lat float

Southern edge of the bounding box, in decimal degrees.

required
max_lon float

Eastern edge of the bounding box, in decimal degrees.

required
max_lat float

Northern edge of the bounding box, in decimal degrees.

required
overture_release str

Overture Maps release to read, as listed in the public bucket, for example "2025-06-25.0". Overture removes old releases.

required

Returns:

Type Description
nodes_df

nodes_df: node_idx (dense, 0-based), connector_id, lat, lng. edges_df: from_node, to_node, length_m, speed_kmh, weight_ds, class.

edges_df

nodes_df: node_idx (dense, 0-based), connector_id, lat, lng. edges_df: from_node, to_node, length_m, speed_kmh, weight_ds, class.

Worked example: Trajectory and road network


build_road_graph(min_lon, min_lat, max_lon, max_lat, overture_release, nodes_output, edges_output)

Load a saved road graph from disk, or fetch it from Overture Maps and save it.

If both nodes_output and edges_output exist they are read (no download); otherwise the network is fetched with fetch_road_network and written there as Parquet.

Parameters:

Name Type Description Default
min_lon float

Bounding box in degrees (WGS 84).

required
min_lat float

Bounding box in degrees (WGS 84).

required
max_lon float

Bounding box in degrees (WGS 84).

required
max_lat float

Bounding box in degrees (WGS 84).

required
overture_release str

Overture Maps release id, for example "2026-10-21.0". Old releases are removed from the public bucket, so choose a current one.

required
nodes_output str

Paths of the Parquet files for the graph nodes and edges.

required
edges_output str

Paths of the Parquet files for the graph nodes and edges.

required

Returns:

Type Description
(nodes, edges) : tuple of pyarrow.Table

As returned by fetch_road_network: nodes with node_idx, connector_id, lat, lng; edges with from_node, to_node, length_m, speed_kmh, weight_ds (travel time in deciseconds) and class.

Worked example: Trajectory and road network


fetch_rail_network(min_lon, min_lat, max_lon, max_lat, overture_release, classes=None, speed_kmh_by_class=None, default_speed_kmh=35.0)

Fetch rail segments from Overture Maps and build a bidirectional rail graph.

Parameters:

Name Type Description Default
min_lon float

Bounding box in degrees (WGS 84).

required
min_lat float

Bounding box in degrees (WGS 84).

required
max_lon float

Bounding box in degrees (WGS 84).

required
max_lat float

Bounding box in degrees (WGS 84).

required
overture_release str

Overture Maps release id, for example "2026-10-21.0". Old releases are removed from the public bucket, so choose a current one.

required
classes list of str

Overture rail classes to keep (default: light rail, standard gauge, subway and tram).

None
speed_kmh_by_class dict

Speed in km/h for each class, used to compute travel times.

None
default_speed_kmh float

Speed for a class not in speed_kmh_by_class. Default 35.

35.0

Returns:

Type Description
(nodes, edges) : tuple of pyarrow.Table

Same columns as fetch_road_network; every segment appears in both directions. Rail and road graphs are separate and not connected.

Worked example: Rail network


build_rail_graph(min_lon, min_lat, max_lon, max_lat, overture_release, nodes_output, edges_output, classes=None, speed_kmh_by_class=None, default_speed_kmh=35.0)

Load a saved rail graph from disk, or fetch it from Overture Maps and save it.

Arguments are those of fetch_rail_network plus the two output paths. If both files exist they are read (no download); otherwise the graph is fetched and written there as Parquet.

Parameters:

Name Type Description Default
min_lon float

Bounding box in degrees (WGS 84).

required
min_lat float

Bounding box in degrees (WGS 84).

required
max_lon float

Bounding box in degrees (WGS 84).

required
max_lat float

Bounding box in degrees (WGS 84).

required
overture_release str

Overture Maps release id, for example "2026-10-21.0". Old releases are removed from the public bucket, so choose a current one.

required
nodes_output str

Paths of the Parquet files for the graph nodes and edges.

required
edges_output str

Paths of the Parquet files for the graph nodes and edges.

required
classes optional

As in fetch_rail_network.

None
speed_kmh_by_class optional

As in fetch_rail_network.

None
default_speed_kmh optional

As in fetch_rail_network.

35.0

Returns:

Type Description
(nodes, edges) : tuple of pyarrow.Table

As returned by fetch_rail_network.

Worked example: Rail network


RoadNetwork

A road (or rail) network prepared once (contraction hierarchy) and reused for many point-to-point physical-distance queries.

Bundles the snap-target nodes together with the routing handle (unlike a split handle + separate nodes_df pair), since a caller always needs both to go from raw lat/lng to a routed distance.

batch_distances(from_nodes, to_nodes)

Batch route-length (metres) query for (from_node, to_node) pairs.

The route is the fastest one (minimum travel time at the edge speeds), so the distance is the length of that route, which is not always the shortest possible distance.

Parameters:

Name Type Description Default
from_nodes array-like of int

Node indexes (node_idx) of the origins. Negative ids mean an unsnapped point.

required
to_nodes array-like of int

Node indexes of the destinations, one per origin.

required

Returns:

Name Type Description
distances_m Array

Route length in metres for each pair.

connected Array

Boolean array. False for negative or unsnapped node ids and for pairs in disconnected parts of the graph; fall back to the straight-line (Haversine) distance for those.

batch_routes(from_nodes, to_nodes, max_waypoints=50)

Batch route-geometry query for (from_node, to_node) pairs.

Returns a flat pyarrow.Table with one row per waypoint: columns query_id (0-based index into from_nodes/to_nodes), lat, lng, cum_weight_ds (cumulative travel-time weight from the route's start), following the same flat-output + boundary convention used by other variable-rows-per-group measures in this library (rather than one Python object per query). A query with connected == False (unsnapped/disconnected) contributes zero rows; join back on query_id against a connected array from batch_distances if you need to distinguish "no route" from "route with no waypoints" (the latter cannot happen: every connected route has at least its two endpoints).

Waypoints are decimated to at most max_waypoints per query (always keeping the first and last), so a caller wanting the full, undecimated node path should pass a large max_waypoints.

build(edges_df, nodes_df) classmethod

Prepare a contraction hierarchy from a road/rail graph's edges.

Parameters:

Name Type Description Default
edges_df

Columns from_node, to_node, weight_ds, length_m (as returned by fastmob.network.builder.fetch_road_network / fetch_rail_network); any Narwhals-compatible backend.

required
nodes_df

Columns node_idx, lat, lng -- used later for snapping via fastmob.network.snap.snap_locations_to_graph (stored as a pyarrow.Table here regardless of input backend, sorted by node_idx); any Narwhals-compatible backend.

required

Worked example: Distances and routes on the network ยท Trajectory and road network


snap_locations_to_graph(tessellation_df, nodes_df, max_distance_m, lat_col='lat', lng_col='lng')

Snap each tessellation row to its nearest road/rail graph node.

Parameters:

Name Type Description Default
tessellation_df

Rows with lat/lng columns to snap.

required
nodes_df

Graph nodes with columns node_idx, lat, lng (as returned by fastmob.network.builder.fetch_road_network / fetch_rail_network).

required
max_distance_m float

Maximum snap distance; farther rows are reported unsnapped.

required
lat_col str

Column names on tessellation_df.

'lat'
lng_col str

Column names on tessellation_df.

'lng'

Returns:

Type Description
Int64Array

int64 array aligned 1:1 with tessellation_df rows; -1 when the nearest node is farther than max_distance_m (unsnapped).

Worked example: Snap points to the network



haversine_m_batch(lat1, lng1, lat2, lng2)

Compute distances in metres; prefer fastmob.utils.haversine.


match_trajectory(traj, *, network, uid_col=None, datetime_col=None, lat_col=None, lng_col=None, candidate_radius_m=75.0, max_candidates=8, gps_sigma_m=20.0, gap_seconds=1800.0, max_transition_speed_kmh=180.0)

Map-match a trajectory with a directed-edge HMM/Viterbi model.

Chooses, for every GPS fix, the most likely road segment given the fix's distance to nearby segments and the route needed to travel between consecutive fixes. Results are Arrow-native and preserve input row order. Independent users are matched concurrently; one user's fixes are matched in sequence, and the sequence restarts after a time gap or an impossible move.

Parameters:

Name Type Description Default
traj DataFrame

Trajectory table (any eager dataframe) with latitude, longitude and datetime columns, and optionally a user column.

required
network RoadNetwork

A prepared road network (see RoadNetwork.build).

required
uid_col str

Column name; auto-detected when None.

None
datetime_col str

Column name; auto-detected when None.

None
lat_col str

Column name; auto-detected when None.

None
lng_col str

Column name; auto-detected when None.

None
candidate_radius_m float

Segments within this distance (metres) of a fix are candidates. Default 75.

75.0
max_candidates int

Most candidate segments kept per fix, nearest first. Default 8.

8
gps_sigma_m float

Assumed standard deviation of the GPS error, in metres: larger values trust the fix less and the route more. Default 20.

20.0
gap_seconds float

A time gap longer than this between consecutive fixes starts a new sequence. Default 1800 (30 minutes).

1800.0
max_transition_speed_kmh float

A move that would need a higher speed than this between consecutive fixes is not allowed. Default 180.

180.0

Returns:

Type Description
Table

The input columns plus matched_edge_from and matched_edge_to (node indexes of the matched segment), matched_fraction (position along the segment, 0 to 1), matched_lat and matched_lng (the projected point), distance_to_road_m (distance from the fix to the matched point), match_status ("matched", "gap_start" for the first fix of a sequence, or "unmatched" when no candidate was found) and match_score (the model's log score; larger is better).

Worked example: Match a GPS trace to roads


od_desire_lines(road_network, from_nodes, to_nodes, flows)

Aggregate OD-pair flows onto the road/rail graph's edges (desire lines).

The Overture-native analogue of stplanr's overline/overline2: for each (from_node, to_node, flow) triple, walks the time-optimal route between the two nodes and adds flow to every edge it crosses, so many overlapping OD pairs accumulate onto shared road segments instead of remaining one separate desire line per pair.

Parameters:

Name Type Description Default
road_network

A prepared network (see RoadNetwork.build); from_nodes/ to_nodes are node ids from that network's nodes_df (e.g. via fastmob.network.snap.snap_locations_to_graph).

required
from_nodes ndarray

Node ids per OD pair; a negative value marks an unsnapped origin or destination.

required
to_nodes ndarray

Node ids per OD pair; a negative value marks an unsnapped origin or destination.

required
flows

Flow volume (e.g. trip count) per OD pair.

required

Returns:

Type Description
(edges_df, dropped_flow)

edges_df has columns edge_from, edge_to, from_lat, from_lng, to_lat, to_lng, total_flow, one row per edge touched by at least one route. dropped_flow is the summed flow of OD pairs that were unsnapped or whose endpoints sit in disconnected graph components.

Worked example: Accumulate flows on roads


jump_lengths_road(traj, *, network, uid_col=None, lat_col=None, lng_col=None, datetime_col=None, snap_max_distance_m=750.0)

Jump lengths (km) measured along the road network.

As in jump_lengths, a jump is the distance between consecutive fixes of the same user, ordered by datetime, and zero-length jumps are kept. Here the distance is the length of the fastest route on network instead of the straight line, and a jump falls back to the straight-line (Haversine) distance when a fix is not snapped to the network or the two fixes are not connected.

Parameters:

Name Type Description Default
traj Any

Trajectory dataframe; any Narwhals-compatible eager backend.

required
network RoadNetwork

A prepared fastmob.network.RoadNetwork.

required
uid_col str | None

Explicit column name overrides; auto-detected when None.

None
lat_col str | None

Explicit column name overrides; auto-detected when None.

None
lng_col str | None

Explicit column name overrides; auto-detected when None.

None
datetime_col str | None

Explicit column name overrides; auto-detected when None.

None
snap_max_distance_m float

Maximum distance (metres) to snap a stop to the network; farther stops fall back to Haversine entirely for any jump touching them.

750.0

Returns:

Type Description
ndarray

One value per consecutive same-user pair (length: len(traj) - n_users).

Worked example: Road distance versus straight line


radius_of_gyration_road(traj, *, network, uid_col=None, lat_col=None, lng_col=None, snap_max_distance_m=750.0)

Radius of gyration (km) per user, measured along the road network.

The root-mean-square distance from each of a user's fixes to the arithmetic-mean centroid of their fixes, r_g(u) = sqrt(mean(d(r_i, r_cm)^2)) as in radius_of_gyration, with d the length of the fastest route on network instead of the straight line.

Parameters:

Name Type Description Default
traj Any

Trajectory dataframe; any Narwhals-compatible eager backend.

required
network RoadNetwork

A prepared fastmob.network.RoadNetwork.

required
uid_col str | None

Explicit column name overrides; auto-detected when None.

None
lat_col str | None

Explicit column name overrides; auto-detected when None.

None
lng_col str | None

Explicit column name overrides; auto-detected when None.

None
snap_max_distance_m float

Maximum distance (metres) to snap a stop to the network.

750.0

Returns:

Type Description
DataFrame

[uid_col, "radius_of_gyration"], one row per user, in the same backend as input.

Worked example: Road distance versus straight line