aperta.routing_prep¶
Mode-aware preparation of a transport network for routing.
prepare_network is the entry point: it takes a freshly-loaded (typically consolidated) graph and produces a PreparedGraph that’s ready for trap-free routing under a specific transport mode. Two preparation axes:
Directedness: undirected (for walk / bike) or directed_scc-restricted (for car, where one-ways must be respected).
Cost-mask: per-edge cost_excluded_<mode> flags for highway-tag values that don’t apply to this mode (e.g. motorways for walk).
The output also carries the cost-masked largest connected (or strongly connected) component as the snap-eligible node set — passed to insert_projected_nodes and snap_to_network_nodes in aperta.network_snap to prevent points from being mapped to trapped-but-not-routable nodes.
Per-mode defaults live in MODE_DEFAULTS (walk / bike / car). Subtype labels (car_night, ebike25, etc.) work too — pass base_mode to inherit defaults and override individual flags.
- class aperta.routing_prep.PreparedGraph(graph, snap_eligible_nodes, snap_eligible_flag, cost_excluded_flag, mode, directedness, network_type)[source]¶
Bases:
objectRouting-ready graph plus the in-session metadata derived by prepare_network.
prepare_network decorates the underlying graph in place with two boolean attributes — one per node (snap_eligible_flag) and one per edge (cost_excluded_flag) — so the trap-fix information survives .graphml roundtripping and is available to downstream consumers that receive only the graph (e.g., Pandana). The PreparedGraph itself is a thin session-time wrapper that memoizes the snap-eligible node set for direct 1:1 hand-off to insert_projected_nodes (as eligible_node_ids=) and snap_to_network_nodes (same), and records the resolved-config metadata for introspection.
- Variables:
graph (networkx.classes.graph.Graph) – The routing graph. MultiGraph (undirected) when directedness=’undirected’, MultiDiGraph (directed) when directedness=’directed_scc’.
snap_eligible_nodes (frozenset) – Node IDs from which every node in the set is mutually reachable under the chosen directedness — the largest connected component for ‘undirected’, the largest strongly connected component for ‘directed_scc’. Pass as eligible_node_ids= to insert_projected_nodes and snap_to_network_nodes to prevent points from being mapped to trapped nodes. Memoized; the same set is also recoverable from the per-node snap_eligible_flag attribute on graph.
snap_eligible_flag (str) – Name of the per-node boolean attribute written onto graph (default f”is_snap_eligible_{mode}”).
cost_excluded_flag (str) – Name of the per-edge boolean attribute written onto graph (default f”cost_excluded_{mode}”). Mode-specific cost functions consult this flag to assign cost = ∞.
mode (str) – The user-supplied mode label (free-form string).
directedness (Literal['undirected', 'directed_scc']) – Resolved directedness setting.
network_type (str) – Resolved OSMnx network-type string (recorded for metadata / warnings; prepare_network does not re-fetch).
- Parameters:
- aperta.routing_prep.compute_snap_eligibility(graph, mode, *, base_mode=None, directedness=None, network_type=None, cost_excluded_tags=None, cost_excluded_flag=None, overwrite_cost_excluded='always')[source]¶
Prep-stage entry point: write the per-edge cost-mask flag and return the snap-eligible node set, ready to hand to insert_projected_nodes and snap_to_network_nodes.
Step 3 of the canonical preparation pipeline (cf. the snap-across-barrier 7-step workflow). Operates on the ORIGINAL directed graph — does NOT apply the directedness transform — because the downstream node-insertion (insert_projected_nodes) needs the directed MultiDiGraph for two-way edge detection via split_two_way_edge_at_point. For walk / bike modes, eligibility is computed on an internal undirected view (graph.to_undirected(as_view=True)) without mutating the caller’s graph.
What this function DOES:
Resolves mode-aware defaults (directedness, network_type, cost_excluded_tags) the same way as prepare_network.
Writes cost_excluded_<mode> (bool) per edge on the input graph. With overwrite_cost_excluded=’always’ (the default), every edge is rewritten; with ‘if_missing’, edges that already carry the flag are preserved (matches the policy prepare_network uses when reloading a graph whose cost-mask was already persisted).
Computes the largest connected component (undirected) or strongly connected component (directed) of the cost-masked subgraph; returns it as a frozenset.
Emits _check_combination warnings for known-bad mode / config combinations.
What this function does NOT do (intentionally):
It does NOT call graph.to_undirected() as a transformation; the caller’s graph stays a MultiDiGraph.
It does NOT write is_snap_eligible_<mode> per node. That decoration belongs to the post-insertion consumer-side prepare_network call, which reclassifies any virtual nodes inserted by insert_projected_nodes in step 4.
It does NOT return a PreparedGraph. The caller wants only the two pieces insert_projected_nodes and snap_to_network_nodes consume (eligible_node_ids= and cost_excluded_flag=), and returning a PreparedGraph here would over-promise (the per-node flag isn’t written yet).
- Parameters:
graph (MultiDiGraph) – Routing graph, typically the output of fetch_network + consolidate_intersections. Must be directed (nx.MultiDiGraph).
mode (str) – Free-form mode label. If it matches a BaseMode (‘walk’/’bike’/’car’), pulls defaults from MODE_DEFAULTS.
base_mode (Literal['walk', 'bike', 'car'] | None) – same semantics as prepare_network.
directedness (Literal['undirected', 'directed_scc'] | None) – same semantics as prepare_network.
network_type (str | None) – same semantics as prepare_network.
cost_excluded_tags (Iterable[str] | None) – same semantics as prepare_network.
cost_excluded_flag (str | None) – same semantics as prepare_network.
overwrite_cost_excluded (Literal['always', 'if_missing']) – ‘always’ (default) rewrites cost_excluded_<mode> on every edge; ‘if_missing’ preserves existing values.
- Returns:
Tuple (snap_eligible_nodes, cost_excluded_flag). Pass directly as eligible_node_ids= and cost_excluded_flag= to insert_projected_nodes (and the same eligible_node_ids= to the subsequent snap_to_network_nodes call).
- Raises:
ValueError – same conditions as prepare_network (missing defaults, wrong directedness).
- Return type:
- aperta.routing_prep.prepare_network(graph, mode, *, base_mode=None, directedness=None, network_type=None, cost_excluded_tags=None, snap_eligible_flag=None, cost_excluded_flag=None)[source]¶
Apply mode-aware graph preparation: directedness + snap-eligibility + cost-exclusion flags.
Wraps an already-fetched (and typically already-consolidated) graph to produce a PreparedGraph ready for trap-free routing. The two axes — directedness and network_type — each have per-mode defaults (MODE_DEFAULTS) that callers can override. The trap-fix outputs (snap_eligible_flag per node, cost_excluded_flag per edge) are written onto the underlying graph in place so they survive .graphml roundtripping and are available to downstream consumers that don’t know about PreparedGraph.
The mode argument is a free-form string label used for default flag names and for warning-policy lookup. Common cases (‘walk’, ‘bike’, ‘car’) pick up defaults directly from MODE_DEFAULTS. Subtype / context labels (e.g., ‘car_night’, ‘ebike25’) work too; pass base_mode to inherit defaults from a known base, and override individual flags as needed. Default flag names embed mode, so multiple calls on the same graph with different mode labels accumulate independent decorations (is_snap_eligible_car_peak, is_snap_eligible_car_night, etc.) instead of overwriting each other.
- Parameters:
graph (MultiDiGraph) – Routing graph, typically the output of fetch_network + consolidate_intersections. Must be directed (nx.MultiDiGraph) when directedness=’directed_scc’ is chosen.
mode (str) – Free-form mode label. Used to derive default flag names and, if it matches a BaseMode (‘walk’/’bike’/’car’), to pull defaults from MODE_DEFAULTS.
base_mode (Literal['walk', 'bike', 'car'] | None) – Optional BaseMode for MODE_DEFAULTS lookup when mode itself is not a BaseMode (e.g., mode=’car_night’, base_mode=’car’). Resolution order: base_mode if given, else mode if in MODE_DEFAULTS, else no defaults available and all flags must be supplied explicitly.
directedness (Literal['undirected', 'directed_scc'] | None) – ‘undirected’ applies to_undirected() and snaps to the largest connected component. ‘directed_scc’ keeps the graph directed and snaps to the largest strongly connected component. None resolves from defaults.
network_type (str | None) – The OSMnx network_type used to fetch graph. Used only for warning-policy decisions and recorded as metadata; this function does not re-fetch. None resolves from defaults.
cost_excluded_tags (Iterable[str] | None) – Highway-tag values to mark for cost = ∞ downstream (e.g., {‘motorway’, ‘trunk’} for walk on network_type=’all’). None resolves from defaults; an empty iterable is a valid explicit override.
snap_eligible_flag (str | None) – Name of the per-node bool attribute to write. None defaults to f”is_snap_eligible_{mode}”.
cost_excluded_flag (str | None) – Name of the per-edge bool attribute to write. None defaults to f”cost_excluded_{mode}”.
- Returns:
A PreparedGraph carrying the (possibly transformed) routing graph, the snap-eligible node set (also written per-node onto the graph), and the resolved metadata.
- Warns:
`UserWarning` on combinations known to silently produce wrong
answers (e.g., `walk + network_type=’walk’` strips pedestrian
paths; `car + directedness=’undirected’` routes the wrong way down
one-way streets). Warnings are keyed by the resolved base mode, so
they fire for subtypes too (`’car_night’` with `base_mode=’car’`
still warns on `directedness=’undirected’`). Deviations from a
mode default that are not known-problematic do NOT warn.
- Raises:
ValueError – if mode has no defaults available (neither base_mode nor mode in MODE_DEFAULTS) and any of directedness / network_type / cost_excluded_tags is unspecified; or if directedness=’directed_scc’ is requested on an already-undirected graph.
- Return type:
- aperta.routing_prep.compute_snap_eligible_nodes(graph, directedness, cost_excluded_flag)[source]¶
Largest CC (undirected) or SCC (directed) of the cost-masked subgraph.
Pure compute — does NOT mutate graph. Companion to compute_snap_eligibility (which writes the per-edge cost-mask AND computes the SCC in one call); use this directly when you’ve already written the cost-mask elsewhere (e.g., a post-insertion recompute after insert_projected_nodes that needs the updated SCC without rewriting the cost-mask).
The cost-masked subgraph contains only edges where the per-edge attribute cost_excluded_flag is absent or False. Computing eligibility on this subgraph (rather than on the raw topology) is what distinguishes “topologically reachable” from “reachable at finite routing cost.” A node connected to the rest of the largest CC only via cost-excluded edges (e.g., a pedestrian-network node at a motorway interchange) is in the largest topological CC but practically unreachable at routing time — the cost-masked subgraph correctly identifies it as ineligible.
When cost_excluded_tags is empty (the default for bike + car), no edges carry cost_excluded_flag=True, so the cost-masked subgraph equals the full graph and the result matches plain topological analysis.