# !pip install --upgrade cityseer
London Centralities
Install and update cityseer
if necessary.
Data Source
The following example uses the OS Open Roads dataset, which is available under the Open Government License.
Preparation
The following example assumes that the OS Open Roads dataset has been downloaded to temp/os_open_roads/oproad_gb.gpkg
relative to the root of the cityseer-examples
repository. Please edit the paths and path setup in this cell if you are using different directories.
from pathlib import Path
= Path.cwd()
repo_path if str(repo_path).endswith("examples"):
= Path.cwd() / ".."
repo_path if not str(repo_path.resolve()).endswith("cityseer-examples"):
raise ValueError(
"Please check your notebook working directory relative to your project and data paths."
)
= Path(repo_path / "temp/os_open_roads/oproad_gb.gpkg")
open_roads_path print("data path:", open_roads_path)
print("path exists:", open_roads_path.exists())
data path: /Users/gareth/dev/benchmark-urbanism/cityseer-examples/examples/../temp/os_open_roads/oproad_gb.gpkg
path exists: True
Extents
Instead of loading the entire dataset, we’ll use a bounding box to only load an area of interest.
from pyproj import Transformer
from shapely import geometry
from cityseer.tools import graphs, io
# bbox setup
= -0.13396079424572427, 51.51371088849723
lng, lat = 5000
buffer_dist = [250, 500, 1000, 2000]
distances = 1500
plot_buffer # transform from WGS to BNG
= Transformer.from_crs("EPSG:4326", "EPSG:27700")
transformer = transformer.transform(lat, lng)
easting, northing # calculate bbox relative to centroid
= geometry.Point(easting, northing)
centroid tuple[float, float, float, float] = centroid.buffer(buffer_dist).bounds # type: ignore
target_bbox: tuple[float, float, float, float] = centroid.buffer(plot_buffer).bounds # type: ignore plot_bbox:
Load
We can now load the OS Open Roads dataset and convert it to a format that can be used by cityseer for downstream calculations.
# load OS Open Roads data from downloaded geopackage
= io.nx_from_open_roads(open_roads_path, target_bbox=target_bbox)
G_open # decompose for higher resolution analysis
= graphs.nx_decompose(G_open, 25)
G_decomp # prepare the data structures
= io.network_structure_from_nx(
nodes_gdf, _edges_gdf, network_structure =27700
G_decomp, crs )
INFO:cityseer.tools.io:Nodes: 18193
INFO:cityseer.tools.io:Edges: 24189
INFO:cityseer.tools.io:Dropped 430 edges where not both start and end nodes were present.
INFO:cityseer.tools.io:Running basic graph cleaning
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 18193/18193 [00:00<00:00, 36376.39it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 10.
100%|██████████| 22578/22578 [00:00<00:00, 125918.80it/s]
INFO:cityseer.tools.graphs:Decomposing graph to maximum edge lengths of 25.
100%|██████████| 22516/22516 [00:13<00:00, 1718.67it/s]
INFO:cityseer.tools.io:Preparing node and edge arrays from networkX graph.
100%|██████████| 75794/75794 [00:00<00:00, 77741.04it/s]
100%|██████████| 75794/75794 [00:11<00:00, 6857.38it/s]
Calculate centralities
The centrality methods can now be computed.
from cityseer.metrics import networks
# if you want to compute wider area centralities, e.g. 20km, then use less decomposition to speed up the computation
= networks.node_centrality_shortest(
nodes_gdf =network_structure,
network_structure=nodes_gdf,
nodes_gdf=distances,
distances
)= nodes_gdf.copy(deep=True)
nodes_gdf_jitter = networks.node_centrality_shortest(
nodes_gdf_jitter =network_structure,
network_structure=nodes_gdf_jitter,
nodes_gdf=distances,
distances=10,
jitter_scale
)= networks.node_centrality_simplest(
nodes_gdf =network_structure,
network_structure=nodes_gdf,
nodes_gdf=distances,
distances )
INFO:cityseer.metrics.networks:Computing shortest path node centrality.
100%|██████████| 75794/75794 [03:18<00:00, 381.59it/s]
INFO:cityseer.metrics.networks:Computing shortest path node centrality.
100%|██████████| 75794/75794 [01:55<00:00, 657.37it/s]
INFO:cityseer.metrics.networks:Computing simplest path node centrality.
100%|██████████| 75794/75794 [01:42<00:00, 738.44it/s]
Plots
Let’s plot a selection of distance thresholds for each of the computed measures.
import matplotlib.pyplot as plt
from cityseer import rustalgos
from cityseer.tools import plot
= "#111"
bg_colour = rustalgos.betas_from_distances(distances)
betas = rustalgos.avg_distances_for_betas(betas)
avg_dists = "#111"
bg_colour = "#ddd"
text_colour = 5
font_size for d, b, avg_d in zip(distances, betas, avg_dists):
= plt.subplots(1, 3, figsize=(8, 4), dpi=200, facecolor=bg_colour)
fig, axes
fig.suptitle(f"Shortest and simplest path closeness centrality: {d}m",
=8,
fontsize=text_colour,
color
)
plot.plot_scatter(0],
axes[
network_structure.node_xs,
network_structure.node_ys,f"cc_beta_{d}"],
nodes_gdf[=plot_bbox,
bbox_extents="magma",
cmap_key=bg_colour,
face_colour
)0].set_title(
axes[f"Gravity index ({avg_d:.2f}m avg. toler.)",
=font_size,
fontsize=text_colour,
color
)
plot.plot_scatter(1],
axes[
network_structure.node_xs,
network_structure.node_ys,f"cc_beta_{d}"],
nodes_gdf_jitter[=plot_bbox,
bbox_extents="magma",
cmap_key=bg_colour,
face_colour
)1].set_title(f"Gravity index w. jitter", fontsize=font_size, color=text_colour)
axes[
plot.plot_scatter(2],
axes[
network_structure.node_xs,
network_structure.node_ys,f"cc_hillier_{d}_ang"],
nodes_gdf[=plot_bbox,
bbox_extents="magma",
cmap_key=bg_colour,
face_colour
)2].set_title(
axes[f"Simplest path hillier integration", fontsize=font_size, color=text_colour
)
plt.tight_layout()
plt.show()
for d, b, avg_d in zip(distances, betas, avg_dists):
= plt.subplots(1, 3, figsize=(8, 4), dpi=200, facecolor=bg_colour)
fig, axes
fig.suptitle(f"Shortest and simplest path betweenness centrality: {d}m",
=8,
fontsize=text_colour,
color
)
plot.plot_scatter(0],
axes[
network_structure.node_xs,
network_structure.node_ys,f"cc_betweenness_{d}"],
nodes_gdf[=plot_bbox,
bbox_extents="magma",
cmap_key=2,
s_max=bg_colour,
face_colour
)0].set_title(
axes[f"Dist. wtd. betw. ({avg_d:.2f}m avg. toler.)",
=font_size,
fontsize=text_colour,
color
)
plot.plot_scatter(1],
axes[
network_structure.node_xs,
network_structure.node_ys,f"cc_betweenness_{d}"],
nodes_gdf_jitter[=plot_bbox,
bbox_extents="magma",
cmap_key=2,
s_max=bg_colour,
face_colour
)1].set_title(
axes[f"Dist. wtd. betw. w. jitter", fontsize=font_size, color=text_colour
)
plot.plot_scatter(2],
axes[
network_structure.node_xs,
network_structure.node_ys,f"cc_betweenness_{d}_ang"],
nodes_gdf[=plot_bbox,
bbox_extents="magma",
cmap_key=2,
s_max=bg_colour,
face_colour
)2].set_title(
axes[f"Simplest path betweenness", fontsize=font_size, color=text_colour
)
plt.tight_layout() plt.show()