Street Network Analysis¶
This tutorial shows how to build a primal street network, inspect its attributes, compute centrality metrics, and visualise the results. Access shapefile here Shapefile
Setup¶
from urbanity import Map
from urbanity.visualisation import (
plot_street_network,
plot_network_centrality,
plot_node_attribute,
)
import geopandas as gpd
import matplotlib.pyplot as plt
m = Map(country='Singapore')
m.add_polygon_boundary('path_to_shapefile')
print("Boundary set:", m.polygon_bounds.geometry.iloc[0].geom_type)
Building the Street Network¶
get_street_network() works with no mandatory arguments once a boundary is set. Urbanity automatically:
- Queries Geofabrik and BBBike to find the smallest available OSM extract
- Downloads and caches it (subsequent calls skip the download)
- Constructs and enriches the NetworkX graph
G, nodes, edges = m.get_street_network(
bandwidth=100, # buffer (m) to capture context beyond boundary
network_type='driving',
graph_attr=True, # betweenness, closeness, degree centrality
building_attr=False, # set True to add building counts per node
pop_attr=False, # set True to add population counts per node
)
Returns:
G— NetworkXMultiDiGraphnodes— node attributeGeoDataFrame(intersections)edges— edge attributeGeoDataFrame(street segments)
print(f"Nodes: {len(nodes)}, Edges: {len(edges)}")
print("Node columns:", list(nodes.columns))
print("Edge columns:", list(edges.columns))
Inspecting the Output¶
Key edge columns include length, street_num_buildings, street_mean_building_bid_complexity, PopSum, Men, Women, Elderly, and street view indicator columns like street_mean_GreenView.
Static Visualisation¶
plot_street_network() produces a high-quality matplotlib figure using a dark-mode theme by default.
fig = plot_street_network(
nodes, edges,
title='Downtown Core Street Network',
dark_mode=True,
)
plt.show()
Colour edges by any numeric attribute:
fig = plot_street_network(
nodes, edges,
colname='length', # colour by street segment length
cmap='plasma',
title='Street Segments by Length',
dark_mode=True,
)
plt.show()
Dual Network¶
The dual (or edge) network — common in Space Syntax — treats street segments as nodes and shared intersections as edges:
dual_G, dual_nodes, dual_edges = m.get_street_network(
location='Singapore',
dual=True,
)
fig, ax = plt.subplots(figsize=(7, 7))
dual_nodes.plot(ax=ax, color='green', markersize=0.1)
dual_edges.plot(ax=ax, color='black', linewidth=0.1)
plt.show()
Network Centrality¶
When graph_attr=True, betweenness and closeness centrality are computed via NetworKit and stored in the node GeoDataFrame.
centrality_cols = [c for c in nodes.columns
if any(k in c for k in ['betweenness', 'closeness', 'degree'])]
print("Centrality columns:", centrality_cols)
fig = plot_network_centrality(
nodes, edges,
centrality_col=centrality_cols[0],
title='Betweenness Centrality',
dark_mode=True,
)
plt.show()
Colour nodes by any attribute:
fig, ax = plt.subplots(figsize=(12, 12))
nodes.plot(
column='Youth',
ax=ax,
cmap='turbo',
markersize=5,
legend=True,
legend_kwds={'label': 'Youth Population Count'},
)
plt.show()
Aggregate Statistics¶
Get area-level descriptive statistics without constructing a full network:
# Single bounding box
subzone_gdf = m.get_aggregate_stats("Seattle", get_svi=True)
print(subzone_gdf.columns.tolist())
For multiple subzones, pass a shapefile via add_polygon_boundary:
m4 = Map(country="United States", zoom=10)
m4.add_polygon_boundary('https://figshare.com/ndownloader/files/41053475')
# Aggregate for each of the 12 CRA subzones
aggregate_gdf = m4.get_aggregate_stats("Seattle", column='CRA_NAM', get_svi=True)
aggregate_gdf.head()
Saving the Network¶
nodes.to_file('output/tanjong_pagar_nodes.geojson', driver='GeoJSON')
edges.to_file('output/tanjong_pagar_edges.geojson', driver='GeoJSON')
Summary¶
| Task | Code |
|---|---|
| Build street network | G, nodes, edges = m.get_street_network() |
| Static map | plot_street_network(nodes, edges) |
| Colour by attribute | colname='length' |
| Centrality map | plot_network_centrality(nodes, edges, centrality_col=...) |
| Dual graph | get_street_network(dual=True) |
| Area statistics | m.get_aggregate_stats(location, column=...) |
→ Next: Urban Graphs