momepy - cityseer

Last update

March 23, 2024

from future import annotations

import geopandas as gpd from osmnx import features

from cityseer.tools import io, graphs from cityseer.metrics import networks, layers

This example uses the momepy bubenec.gpkg GeoPandas GeoDataFrame as an example. Please download this file and place it in a locally accessible file. Update the filepaths in the next code block accordingly.

from pathlib import Path

import geopandas as gpd
from cityseer.tools import io, graphs
from cityseer.metrics import networks, layers
from osmnx import features

repo_path = Path.cwd()
if str(repo_path).endswith("examples"):
    repo_path = Path.cwd() / ".."
if not str(repo_path.resolve()).endswith("cityseer-examples"):
    raise ValueError(
        "Please check your notebook working directory relative to your project and data paths."
    )

bubenec_path = Path(repo_path / "temp/bubenec.gpkg")
print("data path:", bubenec_path)
print("path exists:", bubenec_path.exists())

df_streets: gpd.GeoDataFrame = gpd.read_file(bubenec_path, layer="streets")  # type: ignore
nx_momepy = io.nx_from_generic_geopandas(df_streets)
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 1.
100%|██████████| 35/35 [00:00<00:00, 17268.63it/s]
data path: /Users/gareth/dev/benchmark-urbanism/cityseer-examples/examples/../temp/bubenec.gpkg
path exists: True

At this point the input GeoPandas file has been converted to a networkX MultiGraph with geom attributes for the edges. This graph can now be fed to cityseer graph module methods if wanted. For running optimised network centrality or landuse accessibilities, use the io.network_structure_from_nx method to prepare the necessary structures.

nodes_gdf, edges_gdf, network_structure = io.network_structure_from_nx(
    nx_momepy, crs=df_streets.crs.to_epsg()
)
INFO:cityseer.tools.io:Preparing node and edge arrays from networkX graph.
100%|██████████| 29/29 [00:00<00:00, 14987.04it/s]
100%|██████████| 29/29 [00:00<00:00, 2427.94it/s]

The following block downloads some OSM data which will be used for demonstrating some landuse accessibility methods.

nodes_gdf.head()
ns_node_idx x y live weight geom
x1603585.64-y6464428.774 0 1.603586e+06 6.464429e+06 True 1 POINT (1603585.640 6464428.774)
x1603413.206-y6464228.73 1 1.603413e+06 6.464229e+06 True 1 POINT (1603413.206 6464228.730)
x1603268.502-y6464060.781 2 1.603269e+06 6.464061e+06 True 1 POINT (1603268.502 6464060.781)
x1603363.558-y6464031.885 3 1.603364e+06 6.464032e+06 True 1 POINT (1603363.558 6464031.885)
x1603607.303-y6464181.853 4 1.603607e+06 6.464182e+06 True 1 POINT (1603607.303 6464181.853)
edges_gdf.head(3)
ns_edge_idx start_ns_node_idx end_ns_node_idx edge_idx nx_start_node_key nx_end_node_key length angle_sum imp_factor in_bearing out_bearing total_bearing geom
x1603585.64-y6464428.774-x1603413.206-y6464228.73 0 0 1 0 x1603585.64-y6464428.774 x1603413.206-y6464228.73 264.103950 0.000000 1 -130.760729 -130.760729 -130.760729 LINESTRING (1603585.640 6464428.774, 1603413.2...
x1603585.64-y6464428.774-x1603561.74-y6464494.467 1 0 8 0 x1603585.64-y6464428.774 x1603561.74-y6464494.467 70.020202 8.483583 1 111.541453 103.057871 109.992304 LINESTRING (1603561.740 6464494.467, 1603564.6...
x1603585.64-y6464428.774-x1603650.45-y6464368.601 2 0 6 0 x1603585.64-y6464428.774 x1603650.45-y6464368.601 88.924305 19.246836 1 -42.077556 -55.845266 -42.875276 LINESTRING (1603585.640 6464428.774, 1603603.0...
data_gdf = features.features_from_point(
    (50.1029248, 14.4029967), tags={"amenity": ["pub", "restaurant"]}, dist=400
)
data_gdf.to_crs(3857, inplace=True)
data_gdf = data_gdf.loc["node"]
data_gdf = data_gdf.reset_index(level=0, drop=True)
data_gdf.index = data_gdf.index.astype(str)
data_gdf = data_gdf[["amenity", "geometry"]]
print(data_gdf.head())
      amenity                         geometry
0  restaurant  POINT (1602992.986 6463522.177)
1  restaurant  POINT (1602903.753 6463784.958)
2  restaurant  POINT (1603489.527 6463552.391)
3  restaurant  POINT (1602809.665 6464167.222)
4  restaurant  POINT (1603027.863 6464060.660)
# compute metrics
nodes_gdf = networks.node_centrality_shortest(
    network_structure, nodes_gdf, [250, 500, 1000]
)
nodes_gdf, data_gdf = layers.compute_accessibilities(
    data_gdf,
    landuse_column_label="amenity",
    accessibility_keys=["restaurant"],
    nodes_gdf=nodes_gdf,
    network_structure=network_structure,
    distances=[100, 200, 400],
)
nodes_gdf.head()
INFO:cityseer.metrics.networks:Computing shortest path node centrality.
100%|██████████| 29/29 [00:01<00:00, 28.86it/s]
INFO:cityseer.metrics.layers:Computing land-use accessibility for: restaurant
100%|██████████| 29/29 [00:01<00:00, 28.87it/s]
ns_node_idx x y live weight geom cc_beta_250 cc_beta_500 cc_beta_1000 cc_cycles_250 ... cc_betweenness_beta_250 cc_betweenness_beta_500 cc_betweenness_beta_1000 cc_restaurant_100_nw cc_restaurant_100_wt cc_restaurant_200_nw cc_restaurant_200_wt cc_restaurant_400_nw cc_restaurant_400_wt cc_restaurant_nearest_max_400
x1603585.64-y6464428.774 0 1.603586e+06 6.464429e+06 True 1 POINT (1603585.640 6464428.774) 0.716697 2.050036 4.991603 0.0 ... 0.105017 1.056299 6.454368 0.0 0.000000 0.0 0.000000 1.0 0.043205 314.179047
x1603413.206-y6464228.73 1 1.603413e+06 6.464229e+06 True 1 POINT (1603413.206 6464228.730) 0.121535 1.309901 5.305615 0.0 ... 0.000000 0.089877 5.084879 1.0 0.134929 1.0 0.367327 2.0 0.660077 50.075100
x1603268.502-y6464060.781 2 1.603269e+06 6.464061e+06 True 1 POINT (1603268.502 6464060.781) 0.434456 1.921538 5.837987 0.0 ... 0.036077 0.693734 4.369751 1.0 0.309082 1.0 0.555951 5.0 0.895136 29.353716
x1603363.558-y6464031.885 3 1.603364e+06 6.464032e+06 True 1 POINT (1603363.558 6464031.885) 0.390683 1.850008 6.036365 1.0 ... 0.000000 0.676959 6.886633 0.0 0.000000 1.0 0.075615 2.0 0.354570 129.104904
x1603607.303-y6464181.853 4 1.603607e+06 6.464182e+06 True 1 POINT (1603607.303 6464181.853) 0.284579 1.452106 4.887573 1.0 ... 0.000000 0.263284 3.326667 0.0 0.000000 0.0 0.000000 1.0 0.082232 249.821609

5 rows × 37 columns

# if using dual network
nx_dual = graphs.nx_to_dual(nx_momepy)
nodes_gdf_dual, _edges_gdf_dual, network_structure_dual = io.network_structure_from_nx(
    nx_dual, df_streets.crs.to_epsg()
)
nodes_gdf_dual = networks.node_centrality_simplest(
    network_structure_dual, nodes_gdf_dual, [500]
)
nodes_gdf_dual.head()
INFO:cityseer.tools.graphs:Converting graph to dual.
INFO:cityseer.tools.graphs:Preparing dual nodes
100%|██████████| 35/35 [00:00<00:00, 8927.85it/s]
INFO:cityseer.tools.graphs:Preparing dual edges (splitting and welding geoms)
100%|██████████| 35/35 [00:00<00:00, 397.32it/s]
INFO:cityseer.tools.io:Preparing node and edge arrays from networkX graph.
100%|██████████| 35/35 [00:00<00:00, 16494.45it/s]
100%|██████████| 35/35 [00:00<00:00, 1757.82it/s]
INFO:cityseer.metrics.networks:Computing simplest path node centrality.
100%|██████████| 35/35 [00:01<00:00, 34.94it/s]
ns_node_idx x y live weight geom primal_edge_node_a primal_edge_node_b primal_edge_idx cc_density_500_ang cc_harmonic_500_ang cc_hillier_500_ang cc_farness_500_ang cc_betweenness_500_ang
x1603413.206-y6464228.73_x1603585.64-y6464428.774_k0 0 1.603499e+06 6.464329e+06 True 1 POINT (1603499.423 6464328.752) x1603585.64-y6464428.774 x1603413.206-y6464228.73 0 18.0 11.511215 10.933968 29.632427 10.0
x1603561.74-y6464494.467_x1603585.64-y6464428.774_k0 1 1.603573e+06 6.464461e+06 True 1 POINT (1603572.785 6464461.339) x1603585.64-y6464428.774 x1603561.74-y6464494.467 0 13.0 8.308631 7.956708 21.239941 11.0
x1603585.64-y6464428.774_x1603650.45-y6464368.601_k0 2 1.603619e+06 6.464400e+06 True 1 POINT (1603619.295 6464399.737) x1603585.64-y6464428.774 x1603650.45-y6464368.601 0 13.0 8.324493 8.047422 21.000513 16.0
x1603413.206-y6464228.73_x1603607.303-y6464181.853_k0 3 1.603510e+06 6.464204e+06 True 1 POINT (1603510.094 6464204.494) x1603413.206-y6464228.73 x1603607.303-y6464181.853 0 21.0 13.298367 12.854933 34.305897 10.0
x1603363.558-y6464031.885_x1603413.206-y6464228.73_k0 4 1.603388e+06 6.464130e+06 True 1 POINT (1603388.005 6464130.401) x1603413.206-y6464228.73 x1603363.558-y6464031.885 0 24.0 15.826625 15.015126 38.361317 10.0