library(osmdata)Data (c) OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright
library(sf)Linking to GEOS 3.10.2, GDAL 3.4.1, PROJ 8.2.1; sf_use_s2() is TRUE
Sometimes we have a list of place names (cities, regions, countries) and want to turn them into spatial objects we can map or analyze. One way to do this is by geocoding: looking up the geographic coordinates of a place by name.
This notebook shows how to:
sf geometry).We use two packages:
osmdata — to query OpenStreetMap and retrieve bounding boxes by place name.sf — to work with spatial (vector) data in R.library(osmdata)Data (c) OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright
library(sf)Linking to GEOS 3.10.2, GDAL 3.4.1, PROJ 8.2.1; sf_use_s2() is TRUE
getbb() from osmdata takes a place name like "Utrecht" and returns a 2×2 matrix with the minimum and maximum longitude (x) and latitude (y) of that place.
We then use those four corner coordinates to build a rectangular polygon with sf.
bbox_to_polygon <- function(location) {
# Look up the bounding box from OpenStreetMap
bbox <- getbb(location)
# Pull out the four corners
min_x <- bbox["x", "min"]
max_x <- bbox["x", "max"]
min_y <- bbox["y", "min"]
max_y <- bbox["y", "max"]
# Build a coordinate matrix tracing the rectangle (5 points: close the ring)
coords <- matrix(c(
min_x, min_y,
max_x, min_y,
max_x, max_y,
min_x, max_y,
min_x, min_y # back to start to close the polygon
), ncol = 2, byrow = TRUE)
# Create an sf polygon in WGS 84 (the standard GPS coordinate system)
polygon <- st_polygon(list(coords))
sf_polygon <- st_sfc(polygon, crs = 4326)
return(sf_polygon)
}Let’s test the function on Utrecht to make sure it works before applying it to a whole data frame.
polygon <- bbox_to_polygon("Utrecht")
polygonGeometry set for 1 feature
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: 4.970096 ymin: 52.02628 xmax: 5.195155 ymax: 52.14205
Geodetic CRS: WGS 84
POLYGON ((4.970096 52.02628, 5.195155 52.02628,...
Suppose we have a data frame with a column called location containing place names. We want to add a column polygon with the corresponding spatial polygon for each row.
We write a small helper that extracts the location from a single row, then use rowwise() + mutate() to apply it across all rows.
# Helper: geocode one row
polygon_from_row <- function(row) {
loc <- row$location
bbox_to_polygon(loc)
}
# Apply to all rows of df (replace df with your actual data frame)
df <- df |>
rowwise() |>
mutate(polygon = polygon_from_row(cur_data()))Note:
rowwise()makesmutate()operate one row at a time, andcur_data()gives access to the current row as a mini data frame. Each call topolygon_from_row()makes a live request to OpenStreetMap, so this may be slow for large data frames.