Load packages to be used
# For data wrangling
library(tidyverse)
# for spatial data
library(terra)
library(sf)
# To download spatial data
library(geodata)
# for spatial plots
library(tidyterra)
# for reading excel files
library(readxl)
# for nice tables
library(kableExtra)
# For improving naming
library(janitor)
# For getting habitat proportion
library(SpatioTemporalCont)
# For download links
library(downloadthis)
# For the models
library(sdmTMB)
library(sdmTMBextra)
# For distance estimations
library(gdistance)
# For plots
library(ggplot2)
Fist step is to read in coordinates of sampled sites, the dataset actually has 3 different datasets in it so it will have to be wrangled, you can download the excel sheet in the following link
coordinates <- read_excel("ExampleData/All Fields GPS coordinates.xlsx", skip = 1)
Coordinates_a <- coordinates[, 1:3] |>
janitor::clean_names()
colnames(Coordinates_a) <- stringr::str_sub(colnames(Coordinates_a), end = -3)
Coordinates_a$type <- "Grassland"
Coordinates_b <- coordinates[, 5:7] |>
janitor::clean_names()
colnames(Coordinates_b) <- stringr::str_sub(colnames(Coordinates_b), end = -3)
Coordinates_b$type <- "Conservation agriculture"
Coordinates_c <- coordinates[, 9:11] |>
janitor::clean_names()
colnames(Coordinates_c)[1] <- stringr::str_sub(colnames(Coordinates_c)[1],
end = -3)
colnames(Coordinates_c)[2:3] <- stringr::str_sub(colnames(Coordinates_c)[2:3],
end = -4)
Coordinates_c$type <- "Conventional agriculture"
coordinates <- list(Coordinates_a, Coordinates_b, Coordinates_c) |>
purrr::reduce(dplyr::bind_rows) |>
tidyr::separate(coordinates_latitude_longitude, into = c("lat", "lon"),
sep = ",") |>
dplyr::mutate(lat = as.numeric(lat), lon = as.numeric(lon)) |>
dplyr::mutate(location_code = stringr::str_replace_all(location_code,
"Ø", "oe")) |>
dplyr::mutate(location_code = stringr::str_replace_all(location_code,
"Ã…", "aa")) |>
dplyr::mutate(location_code = stringr::str_replace_all(location_code,
"Æ", "ae")) |>
dplyr::mutate(location_code = janitor::make_clean_names(location_code,
allow_dupes = T)) |>
dplyr::mutate(location_code = stringr::str_remove_all(location_code, "ca_"),
location_code = stringr::str_remove_all(location_code, "k_"), location_code = stringr::str_remove_all(location_code,
"_"))
coordinates <- coordinates[complete.cases(coordinates), ]
the final dataset can be downloaded here
First we will read in the spatRaster used for the habitat proportion calculation, the full resolution map can be downloaded in this link
data("Landuse_DK")
Landuse <- terra::unwrap(Landuse_DK)
coordinates_sf <- terra::vect(coordinates, geom = c("lon", "lat"), crs = "epsg:4326") |>
terra::project(terra::crs(Landuse))
The landuse and points can be seen in the following figure
GrasslandProp <- SpatioTemporalCont::summarise_polygons(Rast = Landuse, Polygons = coordinates_sf,
Vars = "dry nature", dist = 2000, type = "Both")
dry nature |
---|
0.0312000 |
0.1876997 |
0.0043764 |
0.0000000 |
0.0175439 |
0.0276243 |
0.0306452 |
0.0079618 |
0.0192308 |
0.0087789 |
0.0091827 |
0.0520416 |
0.0116580 |
0.0335463 |
0.0240577 |
0.0176000 |
0.0076220 |
0.0098684 |
0.0127694 |
0.0333988 |
0.0069541 |
0.0179211 |
0.0240192 |
0.0971338 |
0.0122549 |
0.0207171 |
0.0713202 |
0.0192000 |
0.0341615 |
0.0511591 |
0.0000000 |
0.0087789 |
0.0059172 |
0.0287770 |
0.0064655 |
0.0120000 |
0.0422648 |
0.0311751 |
0.0255795 |
0.0664000 |
0.0486056 |
0.0447642 |
0.0641026 |
0.0535572 |
0.0047923 |
0.0638468 |
0.0215483 |
0.0307329 |
0.0087789 |
0.0239425 |
0.0120000 |
0.0112269 |
0.0160385 |
0.0275150 |
0.0645933 |
0.0368295 |
0.0247604 |
0.0000000 |
0.0023962 |
0.0024019 |
0.0000000 |
0.0000000 |
0.0000000 |
0.0020101 |
0.0000000 |
0.0016051 |
0.0000000 |
0.0000000 |
0.0000000 |
0.0111732 |
0.0281350 |
0.0056045 |
0.0055777 |
0.0088000 |
0.0023981 |
0.0000000 |
0.0079618 |
0.0000000 |
0.0962521 |
0.0056000 |
0.0000000 |
0.0084666 |
0.0128102 |
0.0008000 |
0.0016000 |
You can download the proportion table here
We will import the data diversity, you can download the raw file here
test_data_genetic_diversity_workshop2024 <- read_table("ExampleData/test_data_genetic_diversity_workshop2024.txt") |>
dplyr::mutate(Site = janitor::make_clean_names(Site, allow_dupes = T),
Site = stringr::str_remove_all(Site, "_"), Site = stringr::str_replace_all(Site,
"lss", "les")) |>
dplyr::select(Site, pi) |>
dplyr::rename(location_code = Site) |>
dplyr::full_join(coordinates)
Now we have joined most of the sites, and we will now filter to only sites with genetic diversity values, that are grasslands and have coordinates
clean_data <- test_data_genetic_diversity_workshop2024 |>
dplyr::filter(!is.na(pi), type == "Grassland", !is.na(lat))
Lets look at genetic diversity in the map
clean_data_sf <- terra::vect(clean_data, geom = c("lon", "lat"), crs = "epsg:4326") |>
terra::project(terra::crs(Landuse))
First we generate a table of ids for the site
SiteID <- data.frame(location_code = c("aaRJ", "BIJ", "DoeJ", "DSJ", "FUR",
"GEJ", "GUS", "HHJ", "JEJ", "JHJ", "KoeJ", "LVJ", "MSJ", "NOJ", "SBJ",
"SKJ", "ULJ", "UTJ", "VAJ"), ID = 1:19) |>
dplyr::mutate(location_code = stringr::str_to_lower(location_code)) |>
dplyr::left_join(clean_data)
We also build a spatial version of this to get the spatial distance
SiteID_sf <- terra::vect(SiteID, geom = c("lon", "lat"), crs = "epsg:4326") |>
terra::project(terra::crs(Landuse))
CoordSites <- terra::geom(SiteID_sf)[, c(3, 4)]
Now lets combine this with the actual Fst data
Fst <- read_table("ExampleData/EntNic_fst_data_old.tsv", col_names = FALSE) |>
tidyr::separate(X1, into = c("from", "to")) |>
dplyr::rename(Fst = X2) |>
dplyr::mutate_all(as.numeric) |>
dplyr::group_by(from, to) |>
dplyr::summarise(Fst = mean(Fst))
And now add the euclidean distance
euc_dist <- distance(SiteID_sf) |>
as.matrix() |>
GeNetIt::dmatrix.df() |>
right_join(Fst)
An now we can plot the distances among them
We will build transistion distances based on 2500 meters and 500 meters for grasslands.
Grassland500 <- SpatioTemporalCont::calculate_prop(Rast = Landuse, Radius = 500,
Vars = c("dry nature", "Forest", "wet nature", "Agriculture"))
Grassland500 <- Grassland500["dry nature"] * 2 + Grassland500["wet nature"] +
Grassland500["Forest"] * 0.8 + Grassland500["Agriculture"] * 0.2
Grassland500 <- Grassland500 + 0.001
Grassland500[is.na(Grassland500)] <- 0.001
Grassland500 <- terra::aggregate(Grassland500, fact = 5, cores = 4)
Grassland2500 <- SpatioTemporalCont::calculate_prop(Rast = Landuse, Radius = 2500,
Vars = c("dry nature", "Forest", "wet nature", "Agriculture"))
##
|---------|---------|---------|---------|
=========================================
Grassland2500 <- Grassland2500["dry nature"] * 2 + Grassland2500["wet nature"] +
Grassland2500["Forest"] * 0.8 + Grassland2500["Agriculture"] * 0.2
Grassland2500 <- Grassland2500 + 0.001
Grassland2500[is.na(Grassland2500)] <- 0.001
Grassland2500 <- terra::aggregate(Grassland2500, fact = 5, cores = 4)
We can plot both together
To build the conductivity layers we use gdistance
tr.cost500 <- gdistance::transition(raster::raster(Grassland500), transitionFunction = mean,
directions = 4)
tr.cost500 <- gdistance::geoCorrection(tr.cost500, type = "c", multpl = FALSE)
saveRDS(tr.cost500, "tr.cost500.rds")
tr.cost2500 <- gdistance::transition(raster::raster(Grassland2500), transitionFunction = mean,
directions = 4)
tr.cost2500 <- gdistance::geoCorrection(tr.cost2500, type = "c", multpl = FALSE)
saveRDS(tr.cost2500, "tr.cost2500.rds")
Check some fast graphical outputs first with euclidean distance
Neighbours <- terra::delaunay(clean_data_sf, as.lines = T)
terra::writeVector(Neighbours, "Neighbours.shp", overwrite = T)
and then with shortest paths
Lines500 <- list()
for (i in 1:nrow(Neighbours)) {
Temp <- as.matrix(as.data.frame(terra::intersect(clean_data_sf, Neighbours[i,
]), geom = "XY")[c("x", "y")])
Lines500[[i]] <- terra::vect(sf::st_as_sf(gdistance::shortestPath(tr.cost500,
origin = Temp[1, ], goal = Temp[2, ], output = "SpatialLines")))
terra::crs(Lines500[[i]]) <- terra::crs(Neighbours)
}
Lines2500 <- list()
for (i in 1:nrow(Neighbours)) {
Temp <- as.matrix(as.data.frame(terra::intersect(clean_data_sf, Neighbours[i,
]), geom = "XY")[c("x", "y")])
Lines2500[[i]] <- terra::vect(sf::st_as_sf(gdistance::shortestPath(tr.cost2500,
origin = Temp[1, ], goal = Temp[2, ], output = "SpatialLines")))
terra::crs(Lines2500[[i]]) <- terra::crs(Neighbours)
}
Lines500 <- Lines500 |>
purrr::reduce(rbind)
terra::writeVector(Lines500, "Lines500.shp", overwrite = T)
Lines2500 <- Lines2500 |>
purrr::reduce(rbind)
terra::writeVector(Lines2500, "Lines2500.shp", overwrite = T)
Now we plot the shortest path, vs euclidean
Landuse <- terra::unwrap(Landuse_DK)
Lines500 <- terra::vect("Lines500.shp")
Lines2500 <- terra::vect("Lines2500.shp")
Neighbours <- terra::vect("Neighbours.shp")
ggplot() + geom_spatraster(data = Landuse) + geom_spatvector(data = Neighbours) +
geom_spatvector(data = Lines500, color = "red") + geom_spatvector(data = Lines2500,
color = "blue")
Landuse <- terra::unwrap(Landuse_DK)
euc_dist$least_cost500 <- NA
euc_dist$least_cost2500 <- NA
for (i in 1:nrow(euc_dist)) {
Temp <- terra::vect(sf::st_as_sf(gdistance::shortestPath(tr.cost500, origin = CoordSites[euc_dist$from[i],
], goal = CoordSites[euc_dist$to[i], ], output = "SpatialLines")))
terra::crs(Temp) <- terra::crs(Landuse)
euc_dist$least_cost500[i] <- terra::perim(Temp)
Temp <- terra::vect(sf::st_as_sf(gdistance::shortestPath(tr.cost2500, origin = CoordSites[euc_dist$from[i],
], goal = CoordSites[euc_dist$to[i], ], output = "SpatialLines")))
terra::crs(Temp) <- terra::crs(Landuse)
euc_dist$least_cost2500[i] <- terra::perim(Temp)
}
all_dist <- euc_dist
Now we can show the plot of the different distances
First we will take a look at a first option of a mesh
Meshcoords <- terra::geom(clean_data_sf) |>
as.data.frame()
bnd <- INLA::inla.nonconvex.hull(cbind(Meshcoords$x, Meshcoords$y), convex = -0.1)
mesh_inla <- fmesher::fm_mesh_2d(boundary = bnd, max.edge = c(8000, 50000))
mesh <- sdmTMB::make_mesh(Meshcoords, c("x", "y"), mesh = mesh_inla)
We should add a barrier, since we have the sea, for that we will download a polygon of Denmark, reproject it and transform it in to an sf object
DK <- geodata::gadm("Denmark", level = 0, path = getwd()) |>
terra::project(Landuse) |>
sf::st_as_sf()
And now we add it to the mesh
bspde <- sdmTMBextra::add_barrier_mesh(mesh, DK, range_fraction = 0.1, plot = FALSE)