Accessibility analysis

knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 6.5, fig.height = 5.5)
library(osmnxr)

A central use of street networks is accessibility: who can reach a service, and how quickly (Foti 2014; Liu et al. 2022). The pattern is always the same — snap facilities to the network, then solve shortest paths or isochrones, weighted by distance or travel time. It underpins studies of urban mobility, green mobility ("Fluxo Verde"), and access to schools, hospitals and parks.

We use the bundled real network of central Olinda, Brazil, with travel times, so this runs offline.

g <- ox_add_edge_travel_times(ox_example("olinda"))

Travel-time service areas from a facility

Suppose a clinic sits near the centre. Its isochrones are the nested areas reachable within each time budget:

clinic <- ox_nearest_nodes(g, x = -34.8553, y = -8.0089)
iso <- ox_isochrone(g, clinic, cutoffs = c(60, 120, 180), weight = "travel_time")
iso[c("cutoff", "n_nodes")]
plot(g, col = "grey85", lwd = 0.6)
plot(sf::st_geometry(iso), add = TRUE, border = NA,
     col = grDevices::adjustcolor(c("#0d3b66", "#1f7a8c", "#2a9d8f"), 0.35))

Nearest facility for each origin

With several facilities and several demand points (homes), a distance matrix gives the travel time from every home to every facility; the row minimum is each home's nearest facility:

homes <- ox_nearest_nodes(g,
  x = c(-34.8505, -34.852, -34.8585),
  y = c(-8.0125, -8.006, -8.011))
facilities <- ox_nearest_nodes(g,
  x = c(-34.8553, -34.8500),
  y = c(-8.0089, -8.0140))

m <- ox_distance_matrix(g, from = homes, to = facilities, weight = "travel_time")
round(m)                 # seconds, homes x facilities
round(apply(m, 1, min))  # travel time to the nearest facility

On real data

With network access, the facilities come straight from OpenStreetMap via the features module, and the workflow is identical:

g <- ox_graph_from_place("Olinda, Brazil", network_type = "drive") |>
  ox_simplify() |>
  ox_add_edge_travel_times()

hospitals <- ox_features_from_place("Olinda, Brazil", tags = list(amenity = "hospital"))
xy <- sf::st_coordinates(hospitals)
origins <- ox_nearest_nodes(g, xy[, 1], xy[, 2])

# 10- and 20-minute drive-time service areas across all hospitals
ox_isochrone(g, origins, cutoffs = c(600, 1200), weight = "travel_time")

Overlay population on those polygons and you can quantify how many people fall outside a 20-minute reach — the core question in accessibility and territorial planning.

References

Foti, F. (2014). Behavioral framework for measuring walkability. PhD thesis, UC Berkeley.

Liu, S. et al. (2022). A generalized framework for measuring pedestrian accessibility. Geographical Analysis 54.



Try the osmnxr package in your browser

Any scripts or data that you put into this service are public.

osmnxr documentation built on Oct. 20, 2026, 1:07 a.m.