From 2e815e1f6d0a3d12bab5841d5d3b42db16eeb803 Mon Sep 17 00:00:00 2001 From: songololo Date: Fri, 1 Dec 2023 18:19:43 +0100 Subject: [PATCH 1/2] accommodates changes to the OS Open Roads GPKG layer keys --- pyproject.toml | 2 +- pysrc/cityseer/tools/io.py | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 18606a69..611e8e5e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "cityseer" -version = '4.5.8' +version = '4.6.0' description = "Computational tools for network-based pedestrian-scale urban analysis" readme = "README.md" requires-python = ">=3.10, <3.12" diff --git a/pysrc/cityseer/tools/io.py b/pysrc/cityseer/tools/io.py index 2c8f533f..31809f14 100644 --- a/pysrc/cityseer/tools/io.py +++ b/pysrc/cityseer/tools/io.py @@ -608,6 +608,8 @@ def _process_node(nd_key: NodeKey) -> tuple[float, float]: def nx_from_open_roads( open_roads_path: str | Path, + road_node_layer_key: str = "road_node", + road_link_layer_key: str = "road_link", target_bbox: BboxType | None = None, ) -> nx.MultiGraph: """ @@ -620,7 +622,10 @@ def nx_from_open_roads( target_bbox: tuple[int] A tuple of integers or floats representing the `[s, w, n, e]` bounding box extents for which to load the dataset. Set to `None` for no bounding box. - + road_node_layer_key: str + The `GPKG` layer key for the OS Open Roads road nodes layer. This may change from time to time. + road_link_layer_key: str + The `GPKG` layer key for the OS Open Roads road links layer. This may change from time to time. Returns ------- nx.MultiGraph @@ -629,19 +634,17 @@ def nx_from_open_roads( """ # create a networkX multigraph g_multi = nx.MultiGraph() - # load the nodes - with fiona.open(open_roads_path, layer="RoadNode") as nodes: + with fiona.open(open_roads_path, layer=road_node_layer_key) as nodes: for node_data in nodes.values(bbox=target_bbox): node_id: str = node_data["properties"]["id"] x: float y: float x, y = node_data["geometry"]["coordinates"] g_multi.add_node(node_id, x=x, y=y) - # load the edges n_dropped = 0 - with fiona.open(open_roads_path, layer="RoadLink") as edges: + with fiona.open(open_roads_path, layer=road_link_layer_key) as edges: for edge_data in edges.values(bbox=target_bbox): # x, y = edge_data['geometry']['coordinates'] props: dict = edge_data["properties"] # type: ignore @@ -687,7 +690,6 @@ def nx_from_open_roads( g_multi.add_edge( start_nd, end_nd, names=list(names), routes=list(routes), highways=list(highways), geom=geom ) - logger.info(f"Nodes: {g_multi.number_of_nodes()}") logger.info(f"Edges: {g_multi.number_of_edges()}") logger.info(f"Dropped {n_dropped} edges where not both start and end nodes were present.") From bd6e97d7188d25526739869657560c46ed931904 Mon Sep 17 00:00:00 2001 From: songololo Date: Fri, 1 Dec 2023 18:50:27 +0100 Subject: [PATCH 2/2] updates to OS Open Roads and fiona structures --- pyproject.toml | 2 +- pysrc/cityseer/tools/io.py | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 611e8e5e..e25a0ed0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "cityseer" -version = '4.6.0' +version = '4.6.1' description = "Computational tools for network-based pedestrian-scale urban analysis" readme = "README.md" requires-python = ">=3.10, <3.12" diff --git a/pysrc/cityseer/tools/io.py b/pysrc/cityseer/tools/io.py index 31809f14..9282db63 100644 --- a/pysrc/cityseer/tools/io.py +++ b/pysrc/cityseer/tools/io.py @@ -637,37 +637,37 @@ def nx_from_open_roads( # load the nodes with fiona.open(open_roads_path, layer=road_node_layer_key) as nodes: for node_data in nodes.values(bbox=target_bbox): - node_id: str = node_data["properties"]["id"] + node_id: str = node_data.properties["id"] x: float y: float - x, y = node_data["geometry"]["coordinates"] + x, y = node_data.geometry["coordinates"] g_multi.add_node(node_id, x=x, y=y) # load the edges n_dropped = 0 with fiona.open(open_roads_path, layer=road_link_layer_key) as edges: for edge_data in edges.values(bbox=target_bbox): # x, y = edge_data['geometry']['coordinates'] - props: dict = edge_data["properties"] # type: ignore - start_nd: str = props["startNode"] - end_nd: str = props["endNode"] + props: dict = edge_data.properties # type: ignore + start_nd: str = props["start_node"] + end_nd: str = props["end_node"] names: set[str] = set() - for name_key in ["name1", "name2"]: + for name_key in ["name_1", "name_2"]: name: str | None = props[name_key] if name is not None: names.add(name) routes: set[str] = set() - for ref_key in ["roadClassificationNumber"]: + for ref_key in ["road_classification_number"]: ref: str | None = props[ref_key] if ref is not None: routes.add(ref) highways: set[str] = set() - for highway_key in ["roadFunction", "roadClassification"]: # 'formOfWay' + for highway_key in ["road_function", "road_classification"]: # 'formOfWay' highway: str | None = props[highway_key] if highway is not None: highways.add(highway) - if props["trunkRoad"]: + if props["trunk_road"]: highways.add("Trunk Road") - if props["primaryRoute"]: + if props["primary_route"]: highways.add("Primary Road") # filter out unwanted highway tags highways.difference_update( @@ -681,7 +681,7 @@ def nx_from_open_roads( } ) # create the geometry - geom = geometry.LineString(edge_data["geometry"]["coordinates"]) + geom = geometry.LineString(edge_data.geometry["coordinates"]) geom: geometry.LineString = geom.simplify(5) # do not add edges to clipped extents if start_nd not in g_multi or end_nd not in g_multi: