Identifies and delineates the contiguous urban extent surrounding a specified geographic location using GHS-WUP-DEGURBA (Degree of Urbanisation) data. The function extracts the urban patch that contains the input coordinates, providing a polygon boundary of the connected urban area.
Usage
urban_extent(
lon,
lat,
measurement_date,
urban_definition = c(21, 22, 23, 30),
max_extent = 1e+06
)Arguments
- lon
Numeric. Longitude of the location of interest (WGS84, decimal degrees).
- lat
Numeric. Latitude of the location of interest (WGS84, decimal degrees).
- measurement_date
Character. Date for which to extract urban extent, in format "YYYY-MM-DD" (e.g., "2020-12-31"). Must match one of the available dates in the GHS-WUP-DEGURBA dataset (typically at 5-year intervals: 1975, 1980, ..., 2030).
- urban_definition
Numeric vector of DEGURBA codes to classify as urban. Default is
c(21, 22, 23, 30)(suburban, semi-dense, dense, and urban centres). Valid codes are: 10, 11, 12, 13, 21, 22, 23, 30. See Details for code meanings.- max_extent
Numeric. Maximum search radius in meters around the input coordinates. Default is 1000000 (1000 km). This limits the area searched for connected urban patches and improves computational efficiency.
Value
An sf polygon object representing the contiguous urban extent
containing the input location. The polygon is returned in the coordinate
reference system specified by pgoptions$get_crs(). If the input
location is not classified as urban, the function may return an empty
polygon or fail.
Details
The function performs the following workflow:
Creates a circular buffer of radius
max_extentaround the input coordinatesExtracts GHS-WUP-DEGURBA data for the specified
measurement_dateCrops the raster to the buffer area for computational efficiency
Reclassifies cells to binary urban (1) or non-urban (0) based on
urban_definitionIdentifies all contiguous urban patches using 8-directional connectivity
Determines which patch contains the input coordinates
Extracts and dissolves the contiguous urban patch into a single polygon
The DEGURBA classification codes represent:
30: Urban centres (cities)
23: Dense urban cluster
22: Semi-dense urban cluster
21: Suburban or peri-urban
13: Rural cluster
12: Low density rural
11: Very low density rural
10: Water bodies or uninhabited areas
Contiguity: Urban patches are defined using 8-directional connectivity, meaning cells are considered connected if they share an edge or corner.
Note
The function requires the input coordinates to fall within an urban area
Larger
max_extentvalues increase computational time and memory usageThe urban definition significantly affects the resulting extent
Stricter definitions (e.g., only code 30) produce smaller extents
Broader definitions (e.g., codes 21-30) produce larger extents
Processing time varies with the size of the urban area
References
Schiavina M, Melchiorri M, Pesaresi M, Jacobs-Crisioni C, Dijkstra L (2025). “GHS-WUP-DEGURBA R2025A – GHS-WUP DEGURBA Settlement Layers, Application of the Degree of Urbanisation Methodology (Stage I) to GHS-WUP-POP R2025A, Multitemporal (1975-2100).” doi:10.2905/1c049178-ab00-4bbc-b638-3e3c19daaacb .
European Commission, Statistical Office of the European Union (2021). “Applying the Degree of Urbanisation — A Methodological Manual to Define Cities, Towns and Rural Areas for International Comparisons.” doi:10.2785/706535 .
See also
read_ghs_wup_degurba for reading the underlying DEGURBA data
ghs_wup_degurba for custom urban classification
Examples
if (FALSE) { # \dontrun{
# Extract urban extent for Oslo, Norway (2020)
oslo_extent <- urban_extent(
lon = 10.763063,
lat = 59.935320,
measurement_date = "2020-12-31"
)
# Plot the result
plot(sf::st_geometry(oslo_extent), main = "Oslo Urban Extent 2020")
# Extract urban extent for New Delhi, India (2020)
delhi_extent <- urban_extent(
lon = 77.231487,
lat = 28.612738,
measurement_date = "2020-12-31"
)
# Compare urban extent over time for the same location
paris_1975 <- urban_extent(
lon = 2.3522,
lat = 48.8566,
measurement_date = "1975-12-31"
)
paris_2020 <- urban_extent(
lon = 2.3522,
lat = 48.8566,
measurement_date = "2020-12-31"
)
# Calculate urban area expansion
area_1975 <- sf::st_area(paris_1975)
area_2020 <- sf::st_area(paris_2020)
expansion <- (area_2020 - area_1975) / area_1975 * 100
cat("Urban expansion:", round(expansion, 1), "%\n")
# Use stricter urban definition (only urban centres)
tokyo_core <- urban_extent(
lon = 139.6917,
lat = 35.6895,
measurement_date = "2020-12-31",
urban_definition = 30
)
# Use broader urban definition (including all urbanized areas)
tokyo_metro <- urban_extent(
lon = 139.6917,
lat = 35.6895,
measurement_date = "2020-12-31",
urban_definition = c(21, 22, 23, 30)
)
# Reduce search radius for smaller cities
kongsvinger <- urban_extent(
lon = 12.000669,
lat = 60.190700,
measurement_date = "2020-12-31",
max_extent = 50e3 # 50 km radius
)
# Extract multiple cities and compare
cities <- data.frame(
name = c("London", "Paris", "Berlin"),
lon = c(-0.1276, 2.3522, 13.4050),
lat = c(51.5074, 48.8566, 52.5200)
)
city_extents <- lapply(1:nrow(cities), function(i) {
urban_extent(
lon = cities$lon[i],
lat = cities$lat[i],
measurement_date = "2020-12-31"
)
})
# Calculate areas
city_areas <- sapply(city_extents, sf::st_area)
cities$area_km2 <- as.numeric(city_areas) / 1e6
print(cities)
} # }