library(tidyverse)
library(osmdata)
library(sf)
library(tigris)
# set different Overpass server
set_overpass_url("https://overpass.private.coffee/api/interpreter")
We obtain all tertiary roads in the greater Madison area, as well as the city boundaries for Madison:
madison_city_limits <- places(state = "WI") |> filter(NAME == "Madison") |> st_transform(crs = "EPSG:4326")
bb <- c(-89.594193, 42.997023, -89.202118, 43.166131)
x <- opq (bbox = bb) |>
add_osm_feature (key = "highway", value = "tertiary") |>
osmdata_sf ()
tertiaries <- x$osm_lines
Now we filter to only the highways that are within Madison or have at least a portion within Madison.
msn_tertiary <- tertiaries[madison_city_limits, , op = st_intersects]
msn_tertiary |>
mutate(maxspeed_numeric = as.numeric(str_remove(maxspeed, " mph")),
maxspeed_factor = as_factor(maxspeed)) |>
st_drop_geometry() |>
count(maxspeed_numeric) |>
gt::gt()
| maxspeed_numeric | n |
|---|---|
| 15 | 3 |
| 20 | 16 |
| 25 | 445 |
| 30 | 307 |
| 35 | 153 |
| 40 | 23 |
| 45 | 5 |
| 50 | 1 |
| NA | 940 |
We see that roughly half of tertiary highways have missing speed limit tags. But of the ones that do have it, many of them have limits lower than the 30 mph that the Brokenspoke analysis assumes. Note that this is based on OSM segments without taking their length into account.
We can also map this data to get a better sense of the spatial distribution. One may hypothesize that the lower speed limit roads are closer to the center of Madison.
library(tmap)
tmap_mode("plot")
msn_tertiary |>
mutate(maxspeed_numeric = as.numeric(str_remove(maxspeed, " mph")),
thirty_mph = case_when(maxspeed_numeric < 30 ~ "below 30 mph",
maxspeed_numeric == 30 ~ "30 mph",
maxspeed_numeric > 30 ~ "over 30 mph"
)) |>
tm_shape() +
tm_lines(col = "thirty_mph")
This seems to confirm that hypothesis: In central areas, a lot of tertiary roads have limits below 30 mph, whereas those with limits above 30 are in the peripheral areas.
Let’s repeat the analysis for Milwaukee.
milwaukee_city_limits <- places(state = "WI") |> filter(NAME == "Milwaukee") |> st_transform(crs = "EPSG:4326")
bb <- c(-88.205109, 42.845378, -87.782135, 43.219020)
x <- opq (bbox = bb) |>
add_osm_feature (key = "highway", value = "tertiary") |>
osmdata_sf ()
tertiaries <- x$osm_lines
mke_tertiary <- tertiaries[milwaukee_city_limits, , op = st_intersects]
mke_tertiary |>
mutate(maxspeed_numeric = as.numeric(str_remove(maxspeed, " mph")),
maxspeed_factor = as_factor(maxspeed)) |>
st_drop_geometry() |>
count(maxspeed_numeric) |>
gt::gt()
| maxspeed_numeric | n |
|---|---|
| 20 | 4 |
| 25 | 360 |
| 30 | 2021 |
| 35 | 175 |
| 40 | 22 |
| NA | 205 |
Speed limit data on Milwaukee streets is more completed, and a large majority of them indeed have a speed limit of 30 mph.
mke_tertiary |>
mutate(maxspeed_numeric = as.numeric(str_remove(maxspeed, " mph")),
thirty_mph = case_when(maxspeed_numeric < 30 ~ "below 30 mph",
maxspeed_numeric == 30 ~ "30 mph",
maxspeed_numeric > 30 ~ "over 30 mph"
)) |>
tm_shape() +
tm_lines(col = "thirty_mph")
The spatial distribution of 30 vs <30 mph streets is more even than in Madison. But streets with a speed limit above 30 mph are again at the edges of the city.