Skip to content

Commit

Permalink
Merge pull request #139 from benchmark-urbanism/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
songololo authored Dec 12, 2024
2 parents 4cd1a1b + 2ab23e6 commit 8dcf915
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 32 deletions.
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,8 @@
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"files.readonlyInclude": {
"**/.cargo/registry/src/**/*.rs": true,
"**/lib/rustlib/src/rust/library/**/*.rs": true,
}
}
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.17.1'
version = '4.17.3'
description = "Computational tools for network-based pedestrian-scale urban analysis"
readme = "README.md"
requires-python = ">=3.10, <3.14"
Expand Down
77 changes: 48 additions & 29 deletions pysrc/cityseer/tools/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import osmnx as ox
import pandas as pd
import requests
from osmnx._errors import InsufficientResponseError
from pyproj import CRS, Transformer
from shapely import geometry
from shapely.strtree import STRtree
Expand Down Expand Up @@ -259,37 +260,46 @@ def _auto_clean_network(
# deduplicate by hierarchy
G = graphs.nx_deduplicate_edges(G, dissolve_distance=20, max_ang_diff=20)
# parks
parks_gdf = ox.features_from_polygon(
geom_wgs,
tags={
"landuse": ["cemetery", "forest"],
"leisure": ["park", "garden", "sports_centre"],
},
)
park_area_gdf = _extract_gdf(parks_gdf)
park_area_gdf = park_area_gdf.to_crs(to_crs_code)
try:
parks_gdf = ox.features_from_polygon(
geom_wgs,
tags={
"landuse": ["cemetery", "forest"],
"leisure": ["park", "garden", "sports_centre"],
},
)
park_area_gdf = _extract_gdf(parks_gdf)
park_area_gdf = park_area_gdf.to_crs(to_crs_code)
except InsufficientResponseError:
park_area_gdf = gpd.GeoDataFrame(columns=["geometry"], geometry="geometry", crs=to_crs_code) # type: ignore
# plazas
plazas_gdf = ox.features_from_polygon(
geom_wgs,
tags={
"highway": ["pedestrian"],
},
)
plaza_area_gdf = _extract_gdf(plazas_gdf)
plaza_area_gdf = plaza_area_gdf.to_crs(to_crs_code)
try:
plazas_gdf = ox.features_from_polygon(
geom_wgs,
tags={
"highway": ["pedestrian"],
},
)
plaza_area_gdf = _extract_gdf(plazas_gdf)
plaza_area_gdf = plaza_area_gdf.to_crs(to_crs_code)
except InsufficientResponseError:
plaza_area_gdf = gpd.GeoDataFrame(columns=["geometry"], geometry="geometry", crs=to_crs_code) # type: ignore
# parking
parking_gdf = ox.features_from_polygon(
geom_wgs,
tags={
"amenity": ["parking"],
},
)
parking_area_gdf = _extract_gdf(parking_gdf)
parking_area_gdf = parking_area_gdf.to_crs(to_crs_code)
try:
parking_gdf = ox.features_from_polygon(
geom_wgs,
tags={
"amenity": ["parking"],
},
)
parking_area_gdf = _extract_gdf(parking_gdf)
parking_area_gdf = parking_area_gdf.to_crs(to_crs_code)
except InsufficientResponseError:
parking_area_gdf = gpd.GeoDataFrame(columns=["geometry"], geometry="geometry", crs=to_crs_code) # type: ignore
# use STR Tree for performance
parks_buff_str_tree = STRtree(park_area_gdf.buffer(5).geometry.to_list())
plaza_str_tree = STRtree(plaza_area_gdf.geometry.to_list())
parking_str_tree = STRtree(parking_area_gdf.geometry.to_list())
parks_buff_str_tree = STRtree(park_area_gdf.buffer(5).geometry.to_list()) # type: ignore
plaza_str_tree = STRtree(plaza_area_gdf.geometry.to_list()) # type: ignore
parking_str_tree = STRtree(parking_area_gdf.geometry.to_list()) # type: ignore
# iter edges to find edges for marking
remove_edges = []
for start_node_key, end_node_key, edge_key, edge_data in tqdm( # type: ignore
Expand Down Expand Up @@ -1069,7 +1079,8 @@ def network_structure_from_nx(
f"Expecting LineString geometry but found {line_geom.geom_type} geom for edge "
f"{start_node_key}-{end_node_key}."
)
# cannot have zero or negative length - division by zero
if line_geom.is_empty:
raise TypeError(f"Found empty geom for edge {start_node_key}-{end_node_key}.")
line_len = line_geom.length
if not np.isfinite(line_len) or line_len <= 0:
raise ValueError(
Expand Down Expand Up @@ -1419,6 +1430,14 @@ def _node_key(node_coords):
for edge_idx, edge_row in tqdm(gdf_network.iterrows(), total=len(gdf_network), disable=config.QUIET_MODE):
# generate start and ending nodes
edge_geom = edge_row[geom_key]
# drop empty edges
if edge_geom.is_empty:
logger.warning(f"Dropping empty edge at row index {edge_idx}")
continue
# drop zero length edges
if edge_geom.length == 0:
logger.warning(f"Dropping zero length edge at row index {edge_idx}")
continue
# round to 1cm - assumes 1m units
if len(edge_geom.coords[0]) == 3:
edge_geom = geometry.LineString(
Expand Down
2 changes: 1 addition & 1 deletion pysrc/cityseer/tools/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,4 +463,4 @@ def mock_species_data(
counts[idx] = (data == uniq).sum()
probs = counts / len(data)

yield counts.tolist(), probs.tolist()
yield counts.tolist(), probs.tolist() # type: ignore
3 changes: 2 additions & 1 deletion pysrc/cityseer/tools/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ def _plot_graph(
_edge_width: int | float | None,
) -> None:
if not len(_graph):
raise ValueError("Graph contains no nodes to plot.")
logger.warning("Graph contains no nodes to plot.")
return
if not isinstance(_node_size, int) or _node_size < 1:
raise ValueError("Node sizes should be a positive integer.")
if _node_colour is not None:
Expand Down

0 comments on commit 8dcf915

Please sign in to comment.