Created
January 19, 2026 19:44
-
-
Save jschoeley/8f1968f9797274ef1242fc6eaa4af636 to your computer and use it in GitHub Desktop.
Generate a basemap for Germany and combine it with travel distance data
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Generate a basemap for Germany and combine it with travel distance data | |
| # Init -------------------------------------------------------------------- | |
| library(tidyverse) | |
| library(sf) | |
| library(eurostat) | |
| # Constants --------------------------------------------------------------- | |
| # input and output paths | |
| paths <- list() | |
| paths$input <- list( | |
| distancedata.rds = "distancedata.rds" | |
| ) | |
| paths$output <- list( | |
| distanceplot.rds = "distanceplot.rds", | |
| distanceplot.png = "distanceplot.png" | |
| ) | |
| # list containers for analysis artifacts | |
| distanceplot <- list() | |
| # bounding box which crops to Germany and surrounding countries | |
| # coordinates of bounding box expressed in Pseudo-Mercator coordinates | |
| # https://epsg.io/3857 | |
| distanceplot$bounding_box <- c( | |
| xmin = 633500, ymin = 5944900, | |
| xmax = 1700000, ymax = 7399100 | |
| ) | |
| # the crs we transform all spatial data to | |
| # project to Pseudo Mercator as used by OSM or Google Maps | |
| # https://epsg.io/3857 | |
| distanceplot$target_crs <- 3857 | |
| # Create region layer --------------------------------------------- | |
| # district outlines in SF format | |
| distanceplot$regions <- | |
| # just to be explicit we state that the coordinates are expressed | |
| # in latitude-longitude format, i.e. https://epsg.io/4326 | |
| get_eurostat_geospatial( | |
| nuts_level = "1", # German Bundesländer | |
| crs = 4326, | |
| resolution = 03 | |
| ) |> | |
| # select only German regions | |
| filter( | |
| CNTR_CODE %in% "DE" | |
| ) |> | |
| # project to target CRS | |
| st_transform(crs = st_crs(distanceplot$target_crs)) |> | |
| # crop to Germany and surrounding countries | |
| # coordinates of bounding box expressed in Mercator coordinates | |
| st_crop(y = distanceplot$bounding_box) | |
| ggplot(distanceplot$regions) + | |
| geom_sf() | |
| # extract internal borders | |
| distanceplot$internal_borders <- | |
| distanceplot$regions |> | |
| st_boundary() |> | |
| st_union() |> | |
| st_difference( | |
| distanceplot$regions |> | |
| st_union() |> | |
| st_boundary() | |
| ) |> | |
| st_collection_extract("LINESTRING") | |
| ggplot(distanceplot$internal_borders) + | |
| geom_sf() | |
| # Create background layer for map of Germany ------------------------------ | |
| distanceplot$background <- | |
| get_eurostat_geospatial( | |
| nuts_level = "0", # nation states | |
| crs = 4326, | |
| resolution = 03 | |
| ) |> | |
| # project to target CRS | |
| st_transform(crs = st_crs(distanceplot$target_crs)) |> | |
| # crop to Germany and surrounding countries | |
| # coordinates of bounding box expressed in Mercator coordinates | |
| st_crop(y = distanceplot$bounding_box) | |
| ggplot(distanceplot$background) + | |
| geom_sf() | |
| # Create outline of Germany ----------------------------------------------- | |
| # make a union of all regions belonging to France and return | |
| # the outline of the resulting polygon | |
| distanceplot$outline <- | |
| distanceplot$regions |> | |
| summarise(id = "de") |> | |
| st_union() | |
| ggplot(distanceplot$outline) + | |
| geom_sf(fill = NA, lwd = 1, color = "black") + | |
| theme_void() | |
| # Merge basemap with actual data ------------------------------------------ | |
| # cut travel distances into intervals | |
| distanceplot$colorscale <- tribble( | |
| ~cut, ~color, ~label, | |
| 0, "#b6f9d9", "under 10", | |
| 10, "#a6e17c", "10 to <20", | |
| 20, "#cda149", "20 to <30", | |
| 30, "#da5b68", "30 to <40", | |
| 40, "#993a8f", "over 40" | |
| ) | |
| # travel time data | |
| distanceplot$distances <- | |
| readRDS(paths$input$distancedata.rds) |> | |
| # project to pseudo Mercator | |
| st_transform(crs = st_crs(distanceplot$target_crs)) |> | |
| select(distance = dist_2021) |> | |
| mutate( | |
| distance = cut(distance, c(distanceplot$colorscale$cut, Inf), right = FALSE) | |
| ) | |
| # plot travel distance | |
| distanceplot$fig <- | |
| ggplot() + | |
| # background | |
| geom_sf( | |
| data = distanceplot$background, | |
| color = "grey50" | |
| ) + | |
| # distance raster | |
| geom_sf( | |
| aes(fill = distance, color = distance), | |
| data = distanceplot$distances | |
| ) + | |
| # internal state borders only | |
| geom_sf( | |
| color = "black", lwd = 0.2, | |
| data = distanceplot$internal_borders | |
| ) + | |
| # germany outline | |
| geom_sf( | |
| fill = NA, lwd = 0.2, color = "black", | |
| data = distanceplot$outline | |
| ) + | |
| scale_color_manual( | |
| values = distanceplot$colorscale$color, | |
| labels = distanceplot$colorscale$label, | |
| aesthetics = c("colour", "fill") | |
| ) + | |
| theme_void() | |
| distanceplot$fig | |
| # Export ---------------------------------------------------------- | |
| saveRDS(distanceplot, paths$output$distanceplot.rds, compress = "xz") | |
| ggsave( | |
| filename = paths$output$distanceplot.png, | |
| plot = distanceplot$fig, | |
| device = "png", | |
| width = 175, | |
| dpi = 300, | |
| units = "mm", | |
| bg = "white" | |
| ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment