This document describes how a pollinator friendly map is created for germany: a landscape raster that can later be used for landscape metrics, maps, and statistical modelling regarding landscape structures that are important for pollinators.

The central methodological idea is a hierarchical overlay, using several data sources:

  1. CLC Backbone is the base layer. It provides complete spatial coverage.
  2. Thuenen agricultural land-use data is placed on top of CLC where available. It adds crop and other agricultural detail.
  3. Protected biotope data from the federal states is placed on top of both. It has the highest priority because it is the most detailed source for ecologically relevant habitat structures.

In short, the final raster is built as:

Protected biotopes > Thuenen agricultural land use > CLC Backbone

1. Packages

library(sf)
library(terra)
library(tidyverse)
library(stringr)
library(furrr)
library(progressr)
library(ggplot2)

2. Coordinate Reference System

The workflow uses EPSG:3035 as the shared working CRS. This is important because the raster layers and the state/PLZ vector layers need to align before cropping, rasterizing, and overlaying.

target_crs <- "EPSG:3035"

Vector data is transformed with sf::st_transform(), while raster and terra vector objects are aligned with terra::project(), terra::resample(), and terra::rast().

3. Pollinator Friendly Classes

Expert and literature based research identified 10 pollinator friendly classes, from which 8 can be used for this spatial analysis. These classes are:

Code Class
1 Grassland
2 Hedgerows and landscape elements
3 Agroforestry and orchards
4 Flower strips and flower areas
5 Fallow and rotational fallow
6 Nesting structures and aids
7 Field margin strips
8 Other

4. CLC Backbone as the Base Layer

The CLC Backbone raster is used as the base layer because it provides broad land-cover information. The latest raster is classified Sentinel2 land cover images from 2023. For the pollinator-focused workflow, from its 11 classes, only relevant natural or semi-natural classes are retained and then reclassified to ‘pollinator friendly classes’. Water, Snow and urban surfaces are excluded

clc_de <- rast(clc_path)

clc_reclassify <- matrix(c(
  2, 8,  # Needle leaved trees -> Other
  3, 8,  # Broadleaved deciduous trees -> Other
  4, 8,  # Broadleaved evergreen trees -> Other
  5, 2,  # Bushes/shrubs -> Hedgerows and landscape elements
  6, 1,  # Permanent herbaceous -> Grassland
  7, 1,  # Periodically herbaceous -> Grassland
  9, 8   # Non-vegetated -> Other
), ncol = 2, byrow = TRUE)

clc_reclass <- classify(
  clc_de,
  clc_reclassify,
  filename = clc_out,
  overwrite = TRUE
)

This base layer is used to fill gaps after the more specific agricultural and protected-biotope layers have been added.

5. Thuenen Agricultural Land-Use Layer

The Thuenen raster adds agricultural detail that CLC cannot provide. It contains crop types and agricultural landscape structures such as permanent grassland and small woody features. The data is from 2024

The original workflow first prepared a Germany-wide Thuenen raster and then reclassified the codes into the pollinator friendly class system, excluding crop types. (crop diversity!!!)

thuenen_raster <- rast(thuenen_path)

thuenen_reclassify <- matrix(c(
  200,  1,  # Permanent grassland -> Grassland
  1101, 9,  # Winter wheat
  1102, 10, # Winter barley
  1103, 11, # Winter rye
  1201, 12, # Spring barley
  1202, 13, # Spring oat
  1300, 14, # Maize
  1401, 15, # Potato
  1402, 16, # Sugar beet
  1501, 17, # Winter rapeseed
  1502, 18, # Sunflower
  1602, 1,  # Grassland class -> Grassland
  1603, 19, # Vegetables
  1611, 20, # Peas
  1612, 21, # Broad bean
  1613, 22, # Lupin
  1614, 23, # Soy
  3001, 2,  # Small woody features -> Hedgerows and landscape elements
  3002, 8,  # Other
  3003, 5,  # Fallow/rotational fallow
  3004, 8,  # Other
  4001, 24, # Grapevine
  4002, 25, # Hops
  4003, 3   # Agroforestry/orchards
), ncol = 2, byrow = TRUE)

thuenen_reclass <- classify(
  thuenen_raster,
  thuenen_reclassify,
  filename = thuenen_out,
  overwrite = TRUE
)

At this stage, the Thuenen layer is more specific than CLC and will later be used to overwrite CLC wherever Thuenen has data.

6. Protected Biotopes from the Federal States

Protected biotope data is not distributed as one national product. Each federal state uses its own file structure and its own attribute names for biotope types. For this workflow, the relevant information is the biotope name, because the final classification is based on the ecological meaning of those biotopes.

The preparation step therefore has one goal: every state dataset should end up with the same data structure.

Column Meaning
biotop_name_gesamt Standardised biotope name used for classification
bundesland Federal state source
geom Geometry

6.1 Baden-Wuerttemberg Example

For Baden-Wuerttemberg, open-land and forest biotope datasets are read separately. The state-specific biotope-type field is renamed to the common name column and the two datasets are combined.

bw_offen <- st_read(bw_offen_path, layer = "offenlandkartierung_bw")

bw_wald <- st_read(bw_wald_path, layer = "waldbiotopkartierung_bw")

bw_biotopes <- bind_rows(
  bw_offen %>%
    transmute(
      biotop_name_gesamt = BIOTOPTY02,
      bundesland = "Baden-Wuerttemberg",
      geom = geom
    ),
  bw_wald %>%
    transmute(
      biotop_name_gesamt = BIOTOPTY02,
      bundesland = "Baden-Wuerttemberg",
      geom = geom
    )
)

The same idea is used for every state: identify the relevant biotope-name column, rename it to biotop_name_gesamt, keep the geometry, and add the federal-state label.

6.2 Combine State Biotope Layers

After the state datasets have been standardised, they can be combined into one protected-biotope layer for Germany.

biotope_state_layers <- list(
  bw_biotopes,
  bayern_biotopes,
  berlin_biotopes,
  brandenburg_biotopes,
  bremen_biotopes,
  hamburg_biotopes,
  hessen_biotopes,
  mv_biotopes,
  niedersachsen_biotopes,
  nrw_biotopes,
  rlp_biotopes,
  sachsen_anhalt_biotopes,
  sachsen_biotopes,
  sh_biotopes
)

biotope_gesamt <- bind_rows(biotope_state_layers) %>%
  mutate(
    biotop_name_gesamt = str_squish(as.character(biotop_name_gesamt)),
    bundesland = as.character(bundesland)
  )

biotope_gesamt %>%
  st_drop_geometry() %>%
  count(bundesland, sort = TRUE)

This produces one common protected-biotope vector layer. The important point is that classification remains name-based: the original state biotope names are preserved and used directly.

7. Reclassifying Biotopes into Pollinator-Relevant Classes

The protected biotopes are translated into pollinator friendly classes using regular expressions on biotop_name_gesamt. The classification is rule-based. Each regular expression captures terms that indicate a target habitat or landscape-structure class. The classification works like this:

biotope_de_filtered <- biotope_gesamt %>%
  mutate(biotop_name_gesamt = str_trim(biotop_name_gesamt)) %>%
  mutate(zielklasse = case_when(
    str_detect(
      biotop_name_gesamt,
      regex("Streuobst|Obstbestand|Obstwiese|Obstbaumreihe|Obstbaumgruppe|Extensivobst", ignore_case = TRUE)
    ) ~ "Agroforestry and orchards",

    str_detect(
      biotop_name_gesamt,
      regex("Feldhecke|Feldgehölz|Hecke|Knick|Wallhecke|Baumreihe|Baumgruppe|Einzelbaum|Gebüsch|Heide", ignore_case = TRUE)
    ) ~ "Hedgerows and landscape elements",

    str_detect(
      biotop_name_gesamt,
      regex("Ackerbrache|Grünlandbrache|Rebkulturbrache|Weinbergsbrache|Wildacker|Extensivacker", ignore_case = TRUE)
    ) ~ "Fallow and rotational fallow",

    str_detect(
      biotop_name_gesamt,
      regex("Ackerrandstreifen|Ackerrain|Feldrain|Saumstreifen", ignore_case = TRUE)
    ) ~ "Field margin strips",

    str_detect(
      biotop_name_gesamt,
      regex("Trockenmauer|Steinriegel|Steinwall|Totholz|Hohlweg|Binnendüne|Höhle|Fels|Blockhalden|Schutthalde", ignore_case = TRUE)
    ) ~ "Nesting structures and aids",

    str_detect(
      biotop_name_gesamt,
      regex("Wiese|Weide|Rasen|Grünland|Mähwiese|Magerrasen|Feuchtwiese|Nasswiese|Röhricht|Sumpf|Moor", ignore_case = TRUE)
    ) ~ "Grassland",

    TRUE ~ "Other"
  ))

The actual script contains a more extensive set of regular expressions. The shortened version above shows the methodology: protected biotopes are classified directly from their names, not through a separate habitat-code translation.

8. Quality Checks During Reclassification

After reclassification, the workflow checks which classes dominate and which biotope names are still falling into Other.

biotope_de_filtered %>%
  st_drop_geometry() %>%
  count(zielklasse, sort = TRUE)

biotope_de_filtered %>%
  st_drop_geometry() %>%
  filter(zielklasse == "Other") %>%
  count(biotop_name_gesamt, sort = TRUE)

This is an important iterative step. It was used to identify missing patterns and add corrections, for example for state-specific code systems such as Niedersachsen.

biotope_de_filtered <- biotope_de_filtered %>%
  mutate(zielklasse = case_when(
    bundesland == "Niedersachsen" &
      str_detect(biotop_name_gesamt, regex("^GM|^GT|^GY|^HC|^RN|^RS|^RH|^RK|^RM|^RY|^UR|^UA|^GF|^GN")) ~ "Grassland",
    bundesland == "Niedersachsen" &
      str_detect(biotop_name_gesamt, regex("^BF|^BT|^ZG")) ~ "Hedgerows and landscape elements",
    bundesland == "Niedersachsen" &
      str_detect(biotop_name_gesamt, regex("^RF|^RB|^XE|^XS|^XG|^XV|^ZH")) ~ "Nesting structures and aids",
    TRUE ~ zielklasse
  ))

9. Rasterizing the Biotope Layer

The protected biotopes are vector polygons, but the final overlay is raster-based. Therefore, the reclassified biotopes are converted to numeric codes and rasterized at 10 m resolution.

biotope_de_filtered <- biotope_de_filtered %>%
  mutate(zielklasse_num = case_when(
    zielklasse == "Grassland" ~ 1,
    zielklasse == "Hedgerows and landscape elements" ~ 2,
    zielklasse == "Agroforestry and orchards" ~ 3,
    zielklasse == "Flower strips and flower areas" ~ 4,
    zielklasse == "Fallow and rotational fallow" ~ 5,
    zielklasse == "Nesting structures and aids" ~ 6,
    zielklasse == "Field margin strips" ~ 7,
    zielklasse == "Other" ~ 8
  ))

biotope_vect <- vect(biotope_de_filtered)

ref_raster <- rast(
  biotope_vect,
  resolution = 10,
  crs = target_crs
)

biotope_raster <- rasterize(
  biotope_vect,
  ref_raster,
  field = "zielklasse_num",
  filename = biotope_out,
  overwrite = TRUE
)

The raster attribute table is attached so that numeric values remain interpretable.

pollinator_rat <- data.frame(
  value = 1:8,
  label = c(
    "Grassland",
    "Hedgerows and landscape elements",
    "Agroforestry and orchards",
    "Flower strips and flower areas",
    "Fallow and rotational fallow",
    "Nesting structures and aids",
    "Field margin strips",
    "Other"
  )
)

levels(biotope_raster) <- pollinator_rat

10 Combining Biotopes with Thuenen

Before overlaying, the biotope raster is resampled to the Thuenen grid. Nearest-neighbor resampling is used because these are categorical classes.

biotope_resampled <- resample(
  biotope_raster,
  thuenen_raster,
  method = "near",
  filename = biotope_res_out,
  overwrite = TRUE
)

The first overlay gives priority to protected biotopes. If a biotope value exists, it is used. Otherwise, the Thuenen class is used.

combined_biotope_thuenen <- ifel(
  !is.na(biotope_resampled),
  biotope_resampled,
  thuenen_reclass,
  filename = combined_out,
  overwrite = TRUE
)

This means that detailed protected habitat information overrides agricultural land-use information.

11. Adding CLC as the Base Layer

CLC is then aligned to the combined Thuenen/biotope grid and used only where neither biotope nor Thuenen data exists.

clc_resampled <- resample(
  clc_reclass,
  combined_biotope_thuenen,
  method = "near",
  filename = clc_res_out,
  overwrite = TRUE
)

combined_final <- ifel(
  !is.na(combined_biotope_thuenen),
  combined_biotope_thuenen,
  clc_resampled,
  filename = final_out,
  overwrite = TRUE
)

The resulting raster follows the hierarchy:

1. Protected biotopes if present
2. Else Thuenen agricultural land-use class if present
3. Else CLC Backbone class

12. Final Raster Attribute Table

The final raster includes the pollinator-relevant habitat classes and the detailed crop classes.

combined_rat <- data.frame(
  value = 1:25,
  label = c(
    "Grassland",
    "Hedgerows and landscape elements",
    "Agroforestry and orchards",
    "Flower strips and flower areas",
    "Fallow and rotational fallow",
    "Nesting structures and aids",
    "Field margin strips",
    "Other",
    "Winter wheat",
    "Winter barley",
    "Winter rye",
    "Spring barley",
    "Spring oat",
    "Maize",
    "Potato",
    "Sugar beet",
    "Winter rapeseed",
    "Sunflower",
    "Vegetables",
    "Peas",
    "Broad bean",
    "Lupin",
    "Soy",
    "Grapevine",
    "Hops"
  )
)

levels(combined_final) <- combined_rat

writeRaster(combined_final, final_out, overwrite = TRUE)

Figure 1: Pollinator-friendly landscape classification for Germany. The map shows the final combined raster with all 25 land-use classes displayed at national scale (CRS: ETRS89 / LAEA Europe).

13. Results

Figure 1: Pollinator-friendly landscape classification for Germany. The map shows the final combined raster with all 25 land-use classes displayed at national scale (CRS: ETRS89 / LAEA Europe).

The final Raster combines data from different sources to create a pollinator friendly landscape in Germany.

CLC provides broad spatial completeness but limited ecological detail. Thuenen data adds agricultural and crop-specific information. Protected biotope data adds the most specific habitat information and therefore takes priority over the other layers.

This is especially important for pollinator-related analysis. Small or legally protected structures may be too detailed for CLC and may not be represented in agricultural land-use products, but they can be highly relevant for pollinators. Giving biotopes top priority preserves these structures in the final analysis layer.

14. What Comes Next

The next steps are built on this combined raster:

  1. Landscape metrics per PLZ are calcualted from the pollinator friendly map.
  2. Compare metrics from separate source layers and the combined layer.
  3. Maps are created for case-study sites.
  4. Join landscape metrics with survey data and CHELSA climate data.
  5. Build the acceptance models and future scenario predictions per postal code.