Skip to content

Cut edge types before the isochrone reachability search - #229

Closed
yu-ta-sato wants to merge 1 commit into
c2g-dev:mainfrom
yu-ta-sato:fix/fix_isochrone_cut_edges
Closed

Cut edge types before the isochrone reachability search#229
yu-ta-sato wants to merge 1 commit into
c2g-dev:mainfrom
yu-ta-sato:fix/fix_isochrone_cut_edges

Conversation

@yu-ta-sato

Copy link
Copy Markdown
Collaborator

Summary

create_isochrone() applied cut_edge_types after the reachability search rather than before it. _compute_center_node_distances() and _build_reachable_subgraph() ran on the full graph, and _filter_edges_by_type() was applied only to the resulting subgraph, so the cut edges were still traversed and were merely removed from the geometry that got drawn. Nodes reachable only through a cut edge stayed inside the isochrone. For the hull-based methods, which build the polygon from node coordinates alone, the parameter had no effect whatsoever. The docstring already described the intended behaviour: "edge types to remove from the graph before processing".

The filtering now runs once on the prepared graph before the distance computation, covering both the scalar and the layered threshold paths, so cut_edge_types=[t] gives the same isochrone as never supplying t in edges.

This PR also fixes a second defect in _filter_edges_by_type(): parallel edges were collected as (u, v) pairs, and NetworkX removes an arbitrary parallel edge for such a pair, so on a multigraph a walking edge could be removed in place of the transit edge running alongside it. Parallel edges are now matched by key.

Reproduction, on a straight walking chain from x=0 to x=600 (4.8 km/h, so 75 s per 100 m) with two stops joined by one 30-second transit edge, 120-second threshold from x=0:

call area max x reached
everything 3000 600
cut_edge_types=[transit] (before) 500 600
cut_edge_types=[transit] (after) 250 100
transit omitted from edges 250 100

Cutting the transit type now agrees exactly with never supplying it.

Behaviour change. Isochrones computed with cut_edge_types on 1.0.0 and earlier will change: cutting a transit edge type now yields the area reachable without transit, rather than the transit-assisted area with the transit lines erased. This is released as 1.0.1, with pyproject.toml, CITATION.cff, and the CHANGELOG updated accordingly.

Related issues

Not applicable.

Testing

  • uv run --group dev --extra cpu pytest -q — 940 passed.
  • uv run --group dev --extra cpu pre-commit run --all-files — clean.

test_isochrone_disconnected_components asserted a MultiPolygon, which was the bug itself: cluster 2 was reached through the cut transit edge and only that edge's geometry was dropped. It is replaced by test_isochrone_cut_edges_are_not_traversed, which asserts cluster 2 is excluded when the type is cut and reached when it is not. Two tests are added: test_isochrone_cut_edge_types_matches_omitting_edge_type (the equivalence above) and test_isochrone_cut_edge_types_multigraph_keeps_parallel_edges. All three fail against the pre-fix source and pass after it.

Documentation

  • cut_edge_types in the create_isochrone() docstring now states that removal precedes the reachability search and that nodes reachable only through those edges fall outside the isochrone.
  • Removed cut_edge_types from the walk-plus-transit isochrone cell of docs/examples/gtfs.ipynb. That cell computes a multimodal isochrone but cut the transit edge type. The parameter had no effect on its concave_hull_knn output before this change and would now remove the transit reach the section exists to demonstrate. The stored outputs remain correct, because concave_hull_knn builds its hull from node coordinates only.
  • CHANGELOG entries under a new 1.0.1 section.

Reviewer notes

Worth a second opinion on the release framing: this is a bug fix, so it is filed as a patch, but it does change the output of existing cut_edge_types calls. If that warrants a minor bump instead, the version metadata is the only thing to adjust.

create_isochrone() applied cut_edge_types after the shortest-path
computation, so the cut edges were still traversed and were merely
dropped from the geometry that was drawn. Nodes reachable only through
a cut edge stayed inside the isochrone, and for the hull-based methods,
which build the polygon from node coordinates alone, the parameter had
no effect at all.

The listed edge types are now removed from the graph before the
distance computation, in both the scalar and the layered threshold
paths, so cut_edge_types=[t] matches never supplying t in edges.

Also match parallel edges by key when filtering a multigraph. Edges
were collected as (u, v) pairs, and NetworkX removes an arbitrary
parallel edge for such a pair, so a walking edge could be removed in
place of the transit edge running alongside it.

Prepare v1.0.1 and drop cut_edge_types from the walk-plus-transit cell
of the GTFS example, which cut the transit edges it means to show.
@yu-ta-sato yu-ta-sato closed this Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant