---
title: "Urban metrics"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Urban metrics}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 6.5, fig.height = 5.5)
```
```{r setup}
library(osmnxr)
```
`osmnxr` summarises a street network with the geometric and topological
measures used in urban morphology (Boeing 2025). We use a bundled real network —
the centre of Olinda, Brazil — so everything here runs offline.
```{r}
g <- ox_example("olinda")
g
```
## Basic statistics
```{r}
ox_basic_stats(g)
```
The pieces of this summary are standard urban indicators:
- **`n_nodes` / `n_edges`** — intersections and street segments. Intersection
density (nodes per km²) is the most common measure of network "grain".
- **`mean_length`** — average street segment length, a proxy for block size.
- **`total_length`** — total street length; divide by area for street density.
- **`circuity`** — how much streets deviate from straight lines.
```{r}
area_km2 <- as.numeric(sf::st_area(sf::st_convex_hull(sf::st_union(g$nodes)))) / 1e6
n_intersections <- sum(g$nodes$osmid %in% c(g$edges$u, g$edges$v))
n_intersections / area_km2 # intersections per km^2
```
## Circuity
Circuity is total street length over straight-line distance between segment
endpoints. A value near `1` means straight streets; higher means more winding:
```{r}
ox_circuity(g)
```
## Centrality: finding chokepoints
Betweenness centrality counts the share of shortest paths passing through each
node. Its maximum highlights structural chokepoints — "a bridge connecting a
city's halves" (Boeing & Ha 2024) — that are single points of failure for
mobility and resilience.
```{r}
ct <- ox_centrality(g, type = "betweenness", normalized = TRUE)
ct[order(-ct$betweenness), ][1:5, ]
```
Map it: the darkest, largest nodes carry the most through-traffic.
```{r}
nodes <- g$nodes
nodes$betweenness <- ct$betweenness[match(nodes$osmid, ct$osmid)]
plot(g, col = "grey80", lwd = 0.6)
plot(nodes["betweenness"], pch = 19,
cex = 0.4 + 4 * nodes$betweenness / max(nodes$betweenness),
pal = function(n) hcl.colors(n, "YlOrRd", rev = TRUE), add = TRUE)
```
The high-betweenness nodes trace the through-routes that hold the network
together — exactly the junctions a planner would protect or reinforce.
## References
Boeing, G. (2025). Modeling and analyzing urban networks and amenities with
OSMnx. *Geographical Analysis*.
Boeing, G., & Ha, J. (2024). Resilient by design: simulating street network
disruptions across every urban area in the world. *Transportation Research
Part A*.