Street orientation

library(osmnxr)

How ordered is a city’s street grid? Following Boeing (2019, 2025), osmnxr measures this with the compass bearing of every street and the Shannon entropy of their distribution: low entropy for a rigid gridiron, high entropy for an organic, winding network.

A real first network

ox_example("olinda") loads a small real network (the historic centre of Olinda, Brazil) bundled with the package, so this runs without network access:

g <- ox_example("olinda")
ox_orientation_entropy(g)
#> [1] 3.486313
ox_plot_orientation(g, title = "Olinda")

Olinda’s colonial street pattern is irregular, so its rose plot points in many directions and its entropy is high.

Comparing cities

The package bundles the bearings of three cities that span the spectrum — the same comparison as Figure 2 of Boeing (2025). These are real bearings, sampled from each city’s drivable network:

cities <- readRDS(system.file("extdata", "city_orientations.rds", package = "osmnxr"))
ent <- tapply(cities$bearing, cities$city, ox_orientation_entropy)
round(ent, 3)
#>     Chicago New Orleans        Rome 
#>       2.473       3.272       3.550

Chicago’s relentless grid gives the lowest entropy; New Orleans, bending along the Mississippi, sits in the middle; Rome’s ancient organic core is highest — near the theoretical maximum of log(36) = 3.58.

library(ggplot2)

bins <- 36; bw <- 360 / bins
cities$sector <- (floor((cities$bearing %% 360) / bw) + 0.5) * bw
counts <- as.data.frame(table(city = cities$city, sector = cities$sector))
counts$sector <- as.numeric(as.character(counts$sector))

ggplot(counts, aes(sector, Freq)) +
  geom_col(width = bw, fill = "#0d3b66", colour = "white", linewidth = 0.1) +
  coord_polar(start = 0) +
  scale_x_continuous(limits = c(0, 360), breaks = seq(0, 315, 45),
                     labels = c("N", "NE", "E", "SE", "S", "SW", "W", "NW")) +
  facet_wrap(~ city) +
  labs(x = NULL, y = NULL,
       title = "Street orientation: ordered (Chicago) to organic (Rome)") +
  theme_minimal(base_size = 9) +
  theme(axis.text.y = element_blank(), panel.grid.minor = element_blank())

On your own city

With network access, compute this for any place straight from OpenStreetMap:

g <- ox_graph_from_place("Manhattan, New York, USA", network_type = "drive") |>
  ox_simplify()
ox_orientation_entropy(g) # low: a famous grid
ox_plot_orientation(g, title = "Manhattan")

References

Boeing, G. (2019). Urban spatial order: street network orientation, configuration, and entropy. Applied Network Science 4(1).

Boeing, G. (2025). Modeling and analyzing urban networks and amenities with OSMnx. Geographical Analysis.

mirror server hosted at Truenetwork, Russian Federation.