Skip to content

Commit

Permalink
fixes ordering for dropping components; handles edge idx edge case
Browse files Browse the repository at this point in the history
  • Loading branch information
songololo committed Nov 29, 2024
1 parent 0cf130a commit f3c0152
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 20 deletions.
Binary file modified docs/public/images/graph_clean.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "cityseer"
version = '4.16.25'
version = '4.16.26'
description = "Computational tools for network-based pedestrian-scale urban analysis"
readme = "README.md"
requires-python = ">=3.10, <3.14"
Expand Down
56 changes: 37 additions & 19 deletions pysrc/cityseer/tools/graphs.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ def nx_remove_filler_nodes(nx_multigraph: MultiGraph) -> MultiGraph:
agg_geom: ListCoordsType = []
edge_info = util.EdgeInfo()
while True:
edge_data: EdgeData = nx_multigraph[trailing_nd][next_link_nd][0]
# cast to list and take first in cases where key at index 0 may have been deleted
edge_data: EdgeData = list(nx_multigraph[trailing_nd][next_link_nd].values())[0]
edge_info.gather_edge_info(edge_data)
# aggregate the geom
try:
Expand Down Expand Up @@ -263,31 +264,18 @@ def nx_remove_dangling_nodes(
f"specified by the remove_disconnected parameter, which is currently set to: {remove_disconnected}. "
"Decrease the remove_disconnected parameter or set to zero to retain graph components."
)
# finds connected components - this behaviour changed with networkx v2.4
connected_components: list[list[NodeKey]] = list(nx.algorithms.components.connected_components(nx_multigraph))
# keep connected components greater than remove_disconnected param
large_components = [component for component in connected_components if len(component) >= remove_disconnected]
large_subgraphs = [nx.MultiGraph(nx_multigraph.subgraph(component)) for component in large_components]
if not large_subgraphs:
logger.warning(
f"An empty graph will be returned because all graph components had fewer than {remove_disconnected} nodes. "
"Decrease the remove_disconnected parameter or set to zero to retain graph components."
)
# make a copy of the graph using the largest component
g_multi_copy = nx.MultiGraph()
for subgraph in large_subgraphs:
g_multi_copy.add_nodes_from(subgraph.nodes(data=True))
g_multi_copy.add_edges_from(subgraph.edges(data=True))
g_multi_copy = nx_multigraph.copy()

# remove danglers
if despine > 0:
remove_nodes = []
nd_key: NodeKey
for nd_key in tqdm(g_multi_copy.nodes(data=False), disable=config.QUIET_MODE):
if nx.degree(g_multi_copy, nd_key) == 1:
# only a single neighbour, so index-in directly and update at key = 0
# only a single neighbour, so index-in directly and update at first neighbour
nb_nd_key: NodeKey = list(nx.neighbors(g_multi_copy, nd_key))[0]
edge_data = g_multi_copy[nd_key][nb_nd_key][0]
# cast to list and take first in cases where key at index 0 may have been deleted
edge_data = list(g_multi_copy[nd_key][nb_nd_key].values())[0]
if (
edge_data["geom"].length <= despine
or ("is_tunnel" in edge_data and edge_data["is_tunnel"] is True)
Expand All @@ -296,8 +284,26 @@ def nx_remove_dangling_nodes(
remove_nodes.append(nd_key)
g_multi_copy.remove_nodes_from(remove_nodes)

# clean up nodes at ex-dangler intersections
g_multi_copy = nx_remove_filler_nodes(g_multi_copy)

# finds connected components - this behaviour changed with networkx v2.4
# do this after to prevent creation of new isolated components after dropping tunnels
connected_components: list[list[NodeKey]] = list(nx.algorithms.components.connected_components(g_multi_copy))
# keep connected components greater than remove_disconnected param
large_components = [component for component in connected_components if len(component) >= remove_disconnected]
large_subgraphs = [nx.MultiGraph(g_multi_copy.subgraph(component)) for component in large_components]
if not large_subgraphs:
logger.warning(
f"An empty graph will be returned because all graph components had fewer than {remove_disconnected} nodes. "
"Decrease the remove_disconnected parameter or set to zero to retain graph components."
)
# make a copy of the graph using the largest component
g_multi_copy = nx.MultiGraph()
for subgraph in large_subgraphs:
g_multi_copy.add_nodes_from(subgraph.nodes(data=True))
g_multi_copy.add_edges_from(subgraph.edges(data=True))

return g_multi_copy


Expand Down Expand Up @@ -654,7 +660,19 @@ def _squash_adjacent(
# find highest priority OSM highway tag
if prioritise_by_hwy_tag:
prioritise_tag = None
for osm_hwy_tag in ["motorway", "trunk", "primary", "secondary", "tertiary", "residential"]:
for osm_hwy_tag in [
"motorway",
"motorway_link",
"trunk",
"trunk_link",
"primary",
"primary_link",
"secondary",
"secondary_link",
"tertiary",
"tertiary_link",
"residential",
]:
for nd_key in node_group:
nb_hwy_tags = _gather_nb_tags(nx_multigraph, nd_key, "highways")
if osm_hwy_tag in nb_hwy_tags:
Expand Down
Binary file added test.gpkg
Binary file not shown.

0 comments on commit f3c0152

Please sign in to comment.