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:
In short, the final raster is built as:
Protected biotopes > Thuenen agricultural land use > CLC Backbone
library(sf)
library(terra)
library(tidyverse)
library(stringr)
library(furrr)
library(progressr)
library(ggplot2)
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().
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 |
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.
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.
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 |
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.
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.
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.
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
))
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
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.
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
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).
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.
The next steps are built on this combined raster: