Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

only allow topological node consolidation to be run once on a graph #1273

Merged
merged 4 commits into from
Jan 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
## 2.0.2 (TBD)

- improve docstrings (#1272)
- fix bug where consolidate_intersections function would mutate the passed-in graph (#1273)
- provide user-friendly error message if consolidate_intersections is run more than once (#1273)

## 2.0.1 (2025-01-01)

Expand Down
5 changes: 4 additions & 1 deletion osmnx/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,10 @@ def load_graphml(
raise ValueError(msg)

# specify default graph/node/edge attribute values' data types
default_graph_dtypes = {"simplified": _convert_bool_string}
default_graph_dtypes = {
"consolidated": _convert_bool_string,
"simplified": _convert_bool_string,
}
default_node_dtypes = {
"elevation": float,
"elevation_res": float,
Expand Down
17 changes: 12 additions & 5 deletions osmnx/simplification.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ def simplify_graph( # noqa: C901, PLR0912

Returns
-------
G
Gs
Topologically simplified graph, with a new `geometry` attribute on
each simplified edge.
"""
Expand Down Expand Up @@ -513,19 +513,19 @@ def consolidate_intersections(

Returns
-------
G or gs
Gc or gs
If `rebuild_graph=True`, returns MultiDiGraph with consolidated
intersections and (optionally) reconnected edge geometries. If
`rebuild_graph=False`, returns GeoSeries of Points representing the
centroids of street intersections.
"""
# make a copy to not mutate original graph object caller passed in
G = G.copy()

# if dead_ends is False, discard dead-ends to retain only intersections
if not dead_ends:
spn = stats.streets_per_node(G)
dead_end_nodes = [node for node, count in spn.items() if count <= 1]

# make a copy to not mutate original graph object caller passed in
G = G.copy()
G.remove_nodes_from(dead_end_nodes)

if rebuild_graph:
Expand Down Expand Up @@ -630,6 +630,10 @@ def _consolidate_intersections_rebuild_graph( # noqa: C901,PLR0912,PLR0915
A rebuilt graph with consolidated intersections and (optionally)
reconnected edge geometries.
"""
if G.graph.get("consolidated"): # pragma: no cover
msg = "This graph has already been consolidated, cannot consolidate it again."
raise GraphSimplificationError(msg)

# default node attributes to aggregate upon consolidation
if node_attr_aggs is None:
node_attr_aggs = {"elevation": "mean"}
Expand Down Expand Up @@ -715,6 +719,9 @@ def _consolidate_intersections_rebuild_graph( # noqa: C901,PLR0912,PLR0915
node_attrs[col] = unique_vals
Gc.add_node(cluster_label, **node_attrs)

# mark the graph as having been consolidated
G.graph["consolidated"] = True

if len(G.edges) == 0 or not reconnect_edges:
# if reconnect_edges is False or there are no edges in original graph
# (after dead-end removed), then skip edges and return new graph as-is
Expand Down
Loading