selected_models <- list(
Edge_Density = c("ag_1985", "wood_cov", "nearest_road_m",
"NDVI_pre_90d", "NDVI_pre_365d", "mean_hydro_dist_m", "mean_slope",
"mean_elevation", "soil_order_1", "vs_mea_3b_2a",
"vs_mea_30b_2a", "tmmn_max_3b_2a", "pr_max_3b_2a", "pr_max_10b_2a",
"pr_mea_60b_2a", "rmin_mea_60b_2a", "spi1y"),
Avg_Patch_Area = c("ag_1985", "wood_cov", "road_dens_km_km2", "nearest_road_m",
"NDVI_pre_90d", "NDVI_pre_365d",
"mean_hydro_dist_m", "mean_elevation", "soil_order_1", "vs_min_3b_2a",
"tmmn_mea_60b_2a", "tmmx_max_3b_2a", "pr_mea_10b_2a",
"pr_mea_3b_2a", "vpd_min_10b_2a", "spei1y", "spei14d")
)
selected_models
## $Edge_Density
## [1] "ag_1985" "wood_cov" "nearest_road_m"
## [4] "NDVI_pre_90d" "NDVI_pre_365d" "mean_hydro_dist_m"
## [7] "mean_slope" "mean_elevation" "soil_order_1"
## [10] "vs_mea_3b_2a" "vs_mea_30b_2a" "tmmn_max_3b_2a"
## [13] "pr_max_3b_2a" "pr_max_10b_2a" "pr_mea_60b_2a"
## [16] "rmin_mea_60b_2a" "spi1y"
##
## $Avg_Patch_Area
## [1] "ag_1985" "wood_cov" "road_dens_km_km2"
## [4] "nearest_road_m" "NDVI_pre_90d" "NDVI_pre_365d"
## [7] "mean_hydro_dist_m" "mean_elevation" "soil_order_1"
## [10] "vs_min_3b_2a" "tmmn_mea_60b_2a" "tmmx_max_3b_2a"
## [13] "pr_mea_10b_2a" "pr_mea_3b_2a" "vpd_min_10b_2a"
## [16] "spei1y" "spei14d"
Uses the lognormal mean correction
exp(fit + 0.5 * se^2).
make_baseline <- function(data) {
as.data.frame(lapply(data, function(x) {
if (is.numeric(x)) return(mean(x, na.rm = TRUE))
if (is.factor(x)) return(levels(x)[1])
if (is.character(x)) return(na.omit(x)[1])
return(x[1])
}))
}
# Marginal effect
get_effect <- function(model, data, var, n = 100) {
x <- data[[var]]
x <- x[is.finite(x)]
if (length(x) < 2) return(NULL)
x_seq <- seq(min(x), max(x), length.out = n)
newdat <- make_baseline(data)
newdat <- newdat[rep(1, n), ]
newdat[[var]] <- x_seq
pred <- predict(model, newdata = newdat, se.fit = TRUE, type = "link")
data.frame(
x = x_seq,
fit = exp(pred$fit + 0.5 * pred$se.fit^2),
upper = exp(pred$fit + 2 * pred$se.fit),
lower = exp(pred$fit - 2 * pred$se.fit),
variable = var
)
}
# Interaction
get_interaction_lines <- function(model, data, var1, var2,
probs = c(0.1, 0.25, 0.5, 0.75, 0.9), n = 100) {
x_seq <- seq(min(data[[var1]], na.rm = TRUE),
max(data[[var1]], na.rm = TRUE), length.out = n)
y_vals <- quantile(data[[var2]], probs = probs, na.rm = TRUE)
df_list <- lapply(seq_along(y_vals), function(i) {
newdat <- make_baseline(data)
newdat <- newdat[rep(1, n), ]
newdat[[var1]] <- x_seq
newdat[[var2]] <- y_vals[i]
pred <- predict(model, newdata = newdat, se.fit = TRUE, type = "link")
data.frame(
x = x_seq,
fit = exp(pred$fit + 0.5 * pred$se.fit^2),
upper = exp(pred$fit + 2 * pred$se.fit),
lower = exp(pred$fit - 2 * pred$se.fit),
group = paste0(names(y_vals)[i], " (", round(y_vals[i], 2), ")")
)
})
do.call(rbind, df_list)
}
# Back-transformed parametric / smooth summary tables
backtransform_tables <- function(model) {
param_df <- as.data.frame(summary(model)$p.table)
param_df$exp_estimate <- exp(param_df$Estimate)
param_df$percent_change <- (param_df$exp_estimate - 1) * 100
param_df <- param_df %>%
dplyr::mutate(
exp_estimate = round(exp_estimate, 3),
percent_change = round(percent_change, 1)
)
smooth_df <- as.data.frame(summary(model)$s.table) %>%
dplyr::mutate(
edf = round(edf, 2),
F = round(F, 2),
p_value = round(`p-value`, 4)
)
list(param = param_df, smooth = smooth_df)
}
Build a single faceted figure showing the fitted relationship for every one-dimensional term in a model, with significance stars taken from the model summary. Two-dimensional tensor interactions are excluded here; they appear in their own figures.
# Pretty axis labels, shared by both models
var_labels <- c(
ag_1985 = "Agricultural Land Use (1985, %)",
wood_cov = "Wood Cover (%)",
road_dens_km_km2 = "Road Density (km/km²)",
nearest_road_m = "Distance to Nearest Road (m)",
NDVI_pre_90d = "NDVI (90-day)",
NDVI_pre_365d = "NDVI (365-day)",
mean_hydro_dist_m = "Distance to Hydrologic Feature (m)",
mean_slope = "Slope",
mean_elevation = "Elevation (m)",
soil_order_1 = "Dominant Soil Order (code)",
vs_mea_3b_2a = "Mean Wind Speed (3-day, m/s)",
vs_mea_30b_2a = "Mean Wind Speed (30-day, m/s)",
vs_min_3b_2a = "Minimum Wind Speed (3-day, m/s)",
tmmn_max_3b_2a = "Max of Minimum Temperature (3-day, K)",
tmmn_mea_60b_2a = "Mean Minimum Temperature (60-day, K)",
tmmx_max_3b_2a = "Maximum Temperature (3-day, K)",
pr_max_3b_2a = "Maximum Precipitation (3-day, mm)",
pr_max_10b_2a = "Maximum Precipitation (10-day, mm)",
pr_mea_10b_2a = "Mean Precipitation (10-day, mm)",
pr_mea_60b_2a = "Mean Precipitation (60-day, mm)",
rmin_mea_60b_2a = "Mean Minimum Relative Humidity (60-day, %)",
vpd_min_10b_2a = "Minimum VPD (10-day, kPa)",
spi1y = "SPI (1 year)",
spei1y = "SPEI (1 year)",
spei14d = "SPEI (14 day)"
)
# p-value for every 1-D term, named by the underlying variable.
# Parametric terms use pTerms.pv, which gives one joint p-value per term - so a
# factor like soil_order_1 gets a single test rather than one row per level.
term_pvalues <- function(model) {
s <- summary(model)
p_par <- s$pTerms.pv
if (is.null(p_par)) { # fallback if no parametric terms
p_par <- numeric(0)
}
p_par <- p_par[!grepl(":", names(p_par))] # parametric interactions excluded
p_sm <- s$s.table[, "p-value"]
nm <- gsub("^(s|ti|te|t2)\\(|\\)$", "", names(p_sm))
keep <- !grepl(",", nm) # 2-D tensor terms excluded
p_sm <- p_sm[keep]
names(p_sm) <- nm[keep]
c(p_par, p_sm)
}
sig_stars <- function(p) {
ifelse(is.na(p), "",
ifelse(p < 0.001, "***",
ifelse(p < 0.01, "**",
ifelse(p < 0.05, "*",
ifelse(p < 0.10, ".", "")))))
}
# Panel title with significance stars
panel_title <- function(v, p, labels = var_labels) {
lab <- if (v %in% names(labels)) labels[[v]] else v
trimws(paste(lab, sig_stars(p)))
}
# Marginal effects for every continuous 1-D term, with starred panel titles
supplemental_effects <- function(model, data, labels = var_labels) {
pvals <- term_pvalues(model)
vars <- names(pvals)
vars <- vars[vars %in% names(data)]
vars <- vars[vapply(data[vars], is.numeric, logical(1))]
eff <- do.call(rbind, lapply(vars, function(v) get_effect(model, data, v)))
panel <- setNames(vapply(vars, function(v) panel_title(v, pvals[[v]], labels),
character(1)), vars)
eff$panel <- factor(panel[eff$variable], levels = panel[vars])
eff
}
# Fitted value at each level of a categorical predictor, other terms at baseline
get_factor_effect <- function(model, data, var) {
lv <- levels(data[[var]])
newdat <- make_baseline(data)
newdat <- newdat[rep(1, length(lv)), ]
newdat[[var]] <- factor(lv, levels = lv)
pred <- predict(model, newdata = newdat, se.fit = TRUE, type = "link")
data.frame(
level = factor(lv, levels = lv),
fit = exp(pred$fit + 0.5 * pred$se.fit^2),
upper = exp(pred$fit + 2 * pred$se.fit),
lower = exp(pred$fit - 2 * pred$se.fit),
variable = var
)
}
# All categorical terms in a model
supplemental_factor_effects <- function(model, data, labels = var_labels) {
pvals <- term_pvalues(model)
vars <- names(pvals)
vars <- vars[vars %in% names(data)]
vars <- vars[vapply(data[vars], is.factor, logical(1))]
if (length(vars) == 0) return(NULL)
eff <- do.call(rbind, lapply(vars, function(v) get_factor_effect(model, data, v)))
panel <- setNames(vapply(vars, function(v) panel_title(v, pvals[[v]], labels),
character(1)), vars)
eff$panel <- factor(panel[eff$variable], levels = panel[vars])
eff
}
plot_factor_effects <- function(eff, y_lab, colour = "#0072B2") {
ggplot(eff, aes(x = level, y = fit)) +
geom_errorbar(aes(ymin = lower, ymax = upper), width = 0.15, colour = colour) +
geom_point(size = 3, colour = colour) +
facet_wrap(~ panel, scales = "free") +
theme_classic(base_size = 12) +
theme(
strip.background = element_blank(),
strip.text = element_text(size = 11, face = "bold"),
axis.title = element_text(size = 13, face = "bold")
) +
labs(x = NULL, y = y_lab)
}
plot_supplemental <- function(eff, y_lab, ncol = 4, colour = "#0072B2") {
ggplot(eff, aes(x = x, y = fit)) +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.2, fill = colour) +
geom_line(linewidth = 1, colour = colour) +
facet_wrap(~ panel, scales = "free", ncol = ncol) +
theme_classic(base_size = 12) +
theme(
strip.background = element_blank(),
strip.text = element_text(size = 11, face = "bold"),
axis.title = element_text(size = 13, face = "bold")
) +
labs(x = NULL, y = y_lab)
}
cv_gam <- function(formula, data, K = 10, reps = 5, seed = 1) {
vars <- all.vars(formula)
d <- data[complete.cases(data[, vars, drop = FALSE]), , drop = FALSE]
y <- eval(formula[[2]], envir = d) # observed log response
set.seed(seed)
rep_stats <- lapply(seq_len(reps), function(r) {
folds <- sample(rep(seq_len(K), length.out = nrow(d)))
pred <- rep(NA_real_, nrow(d))
for (k in seq_len(K)) {
train <- d[folds != k, ]
test <- d[folds == k, ]
# A held-out row whose factor level is absent from the training fold cannot
# be predicted; drop those rows rather than losing the whole fold.
fac_vars <- vars[vapply(d[vars], is.factor, logical(1))]
ok_rows <- rep(TRUE, nrow(test))
for (fv in fac_vars) {
ok_rows <- ok_rows & test[[fv]] %in% unique(train[[fv]])
}
fit <- tryCatch(gam(formula, data = train, method = "REML"),
error = function(e) NULL)
if (is.null(fit) || !any(ok_rows)) next
idx <- which(folds == k)[ok_rows]
pred[idx] <- tryCatch(
as.numeric(predict(fit, newdata = test[ok_rows, , drop = FALSE], type = "link")),
error = function(e) NA_real_
)
}
ok <- is.finite(pred) & is.finite(y)
res <- y[ok] - pred[ok]
data.frame(
rep = r,
RMSE = sqrt(mean(res^2)),
MAE = mean(abs(res)),
R2 = 1 - sum(res^2) / sum((y[ok] - mean(y[ok]))^2),
n_pred = sum(ok)
)
})
do.call(rbind, rep_stats)
}
cv_compare <- function(model_list, data, K = 10, reps = 5, seed = 1) {
res <- lapply(names(model_list), function(nm) {
s <- cv_gam(formula(model_list[[nm]]), data, K = K, reps = reps, seed = seed)
data.frame(
model = nm,
CV_RMSE = mean(s$RMSE),
RMSE_SD = sd(s$RMSE),
CV_MAE = mean(s$MAE),
CV_R2 = mean(s$R2),
R2_SD = sd(s$R2)
)
})
res <- do.call(rbind, res)
res <- res[order(res$CV_RMSE), ]
res$delta_RMSE <- res$CV_RMSE - min(res$CV_RMSE)
rownames(res) <- NULL
res
}
mod_edge_ln <- gam(
log(edge_dens) ~
s(ag_1985) + wood_cov + nearest_road_m +
NDVI_pre_90d + s(NDVI_pre_365d) + s(mean_hydro_dist_m) +
s(mean_slope) + s(mean_elevation) + soil_order_1 +
vs_mea_3b_2a + vs_mea_30b_2a + tmmn_max_3b_2a +
pr_max_3b_2a + s(pr_max_10b_2a) + s(pr_mea_60b_2a) +
rmin_mea_60b_2a + s(spi1y),
data = landscape_data,
family = gaussian(),
method = "REML"
)
summary(mod_edge_ln)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## log(edge_dens) ~ s(ag_1985) + wood_cov + nearest_road_m + NDVI_pre_90d +
## s(NDVI_pre_365d) + s(mean_hydro_dist_m) + s(mean_slope) +
## s(mean_elevation) + soil_order_1 + vs_mea_3b_2a + vs_mea_30b_2a +
## tmmn_max_3b_2a + pr_max_3b_2a + s(pr_max_10b_2a) + s(pr_mea_60b_2a) +
## rmin_mea_60b_2a + s(spi1y)
##
## Parametric coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.058e+00 1.678e+00 2.418 0.015942 *
## wood_cov 9.226e-03 2.495e-03 3.698 0.000241 ***
## nearest_road_m 2.007e-04 8.627e-05 2.327 0.020372 *
## NDVI_pre_90d -6.439e-02 2.071e-01 -0.311 0.756004
## soil_order_11 3.891e-02 8.344e-02 0.466 0.641189
## soil_order_14 -2.332e-01 1.155e-01 -2.019 0.043994 *
## soil_order_19 1.694e-01 1.071e-01 1.582 0.114237
## soil_order_1Other 6.434e-03 1.174e-01 0.055 0.956325
## vs_mea_3b_2a -7.905e-03 4.073e-02 -0.194 0.846178
## vs_mea_30b_2a -1.251e-02 6.569e-02 -0.190 0.849015
## tmmn_max_3b_2a 7.596e-03 5.648e-03 1.345 0.179230
## pr_max_3b_2a 1.955e-03 1.459e-03 1.340 0.180980
## rmin_mea_60b_2a -4.650e-03 7.255e-03 -0.641 0.521797
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Approximate significance of smooth terms:
## edf Ref.df F p-value
## s(ag_1985) 2.056 2.549 5.465 0.00233 **
## s(NDVI_pre_365d) 2.232 2.839 1.162 0.27034
## s(mean_hydro_dist_m) 2.268 2.742 2.697 0.06220 .
## s(mean_slope) 1.800 2.295 0.394 0.64004
## s(mean_elevation) 6.371 7.481 8.277 < 2e-16 ***
## s(pr_max_10b_2a) 2.859 3.600 2.987 0.02205 *
## s(pr_mea_60b_2a) 1.170 1.318 0.134 0.73958
## s(spi1y) 2.756 3.451 2.055 0.09755 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## R-sq.(adj) = 0.294 Deviance explained = 33.8%
## -REML = 521.33 Scale est. = 0.31647 n = 538
performance::check_outliers(mod_edge_ln)
## OK: No outliers detected.
## - Based on the following method and threshold: cook (1).
## - For variable: (Whole model)
sim_res <- simulateResiduals(mod_edge_ln)
outlier_idx <- outliers(sim_res)
# Drops NA rows
rows_used_edge <- as.numeric(rownames(mod_edge_ln$model))
if (length(outlier_idx) > 0) {
landscape_data_clean <- landscape_data[-rows_used_edge[outlier_idx], ]
} else {
landscape_data_clean <- landscape_data
}
nrow(landscape_data) - nrow(landscape_data_clean) # n outliers dropped
## [1] 8
## Base model, outliers removed
mod_edge_clean <- gam(log(edge_dens) ~
s(ag_1985) + wood_cov + nearest_road_m +
NDVI_pre_90d + s(NDVI_pre_365d) + s(mean_hydro_dist_m) +
s(mean_slope) + s(mean_elevation) + soil_order_1 +
vs_mea_3b_2a + vs_mea_30b_2a + tmmn_max_3b_2a +
pr_max_3b_2a + s(pr_max_10b_2a) + pr_mea_60b_2a +
rmin_mea_60b_2a + s(spi1y),
data = landscape_data_clean,
method = "REML")
summary(mod_edge_clean)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## log(edge_dens) ~ s(ag_1985) + wood_cov + nearest_road_m + NDVI_pre_90d +
## s(NDVI_pre_365d) + s(mean_hydro_dist_m) + s(mean_slope) +
## s(mean_elevation) + soil_order_1 + vs_mea_3b_2a + vs_mea_30b_2a +
## tmmn_max_3b_2a + pr_max_3b_2a + s(pr_max_10b_2a) + pr_mea_60b_2a +
## rmin_mea_60b_2a + s(spi1y)
##
## Parametric coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.990e+00 1.536e+00 2.598 0.00967 **
## wood_cov 7.439e-03 2.325e-03 3.199 0.00147 **
## nearest_road_m 2.025e-04 7.981e-05 2.537 0.01147 *
## NDVI_pre_90d -8.212e-02 1.918e-01 -0.428 0.66872
## soil_order_11 6.812e-02 7.711e-02 0.883 0.37744
## soil_order_14 -2.872e-01 1.082e-01 -2.655 0.00818 **
## soil_order_19 1.785e-01 1.003e-01 1.780 0.07570 .
## soil_order_1Other 5.086e-02 1.087e-01 0.468 0.64015
## vs_mea_3b_2a -2.641e-03 3.777e-02 -0.070 0.94429
## vs_mea_30b_2a -7.508e-03 6.137e-02 -0.122 0.90268
## tmmn_max_3b_2a 7.114e-03 5.233e-03 1.360 0.17459
## pr_max_3b_2a 2.504e-03 1.348e-03 1.858 0.06372 .
## pr_mea_60b_2a -1.068e-02 1.869e-02 -0.572 0.56792
## rmin_mea_60b_2a 2.853e-03 6.793e-03 0.420 0.67468
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Approximate significance of smooth terms:
## edf Ref.df F p-value
## s(ag_1985) 2.110 2.612 5.803 0.00137 **
## s(NDVI_pre_365d) 2.590 3.284 2.225 0.07666 .
## s(mean_hydro_dist_m) 2.388 2.888 2.907 0.04126 *
## s(mean_slope) 2.085 2.672 0.877 0.41404
## s(mean_elevation) 6.244 7.360 9.853 < 2e-16 ***
## s(pr_max_10b_2a) 2.643 3.341 3.679 0.00846 **
## s(spi1y) 3.571 4.435 2.825 0.03417 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## R-sq.(adj) = 0.335 Deviance explained = 37.8%
## -REML = 474.65 Scale est. = 0.26859 n = 530
## NDVI x drought interaction
mod_edge_NDVI_Climate <- gam(log(edge_dens) ~
s(ag_1985) + wood_cov + nearest_road_m +
NDVI_pre_90d + s(NDVI_pre_365d) + s(mean_hydro_dist_m) +
s(mean_slope) + s(mean_elevation) + soil_order_1 +
vs_mea_3b_2a + vs_mea_30b_2a + tmmn_max_3b_2a +
pr_max_3b_2a + s(pr_max_10b_2a) + pr_mea_60b_2a +
rmin_mea_60b_2a + s(spi1y) +
ti(NDVI_pre_365d, spi1y),
data = landscape_data_clean,
method = "REML")
summary(mod_edge_NDVI_Climate)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## log(edge_dens) ~ s(ag_1985) + wood_cov + nearest_road_m + NDVI_pre_90d +
## s(NDVI_pre_365d) + s(mean_hydro_dist_m) + s(mean_slope) +
## s(mean_elevation) + soil_order_1 + vs_mea_3b_2a + vs_mea_30b_2a +
## tmmn_max_3b_2a + pr_max_3b_2a + s(pr_max_10b_2a) + pr_mea_60b_2a +
## rmin_mea_60b_2a + s(spi1y) + ti(NDVI_pre_365d, spi1y)
##
## Parametric coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.296e+00 1.528e+00 2.812 0.00513 **
## wood_cov 8.072e-03 2.327e-03 3.468 0.00057 ***
## nearest_road_m 2.045e-04 7.942e-05 2.575 0.01032 *
## NDVI_pre_90d -1.280e-01 1.907e-01 -0.671 0.50242
## soil_order_11 7.953e-02 7.673e-02 1.037 0.30044
## soil_order_14 -2.515e-01 1.072e-01 -2.347 0.01932 *
## soil_order_19 2.123e-01 9.967e-02 2.130 0.03365 *
## soil_order_1Other 6.301e-02 1.077e-01 0.585 0.55866
## vs_mea_3b_2a -1.571e-02 3.745e-02 -0.419 0.67507
## vs_mea_30b_2a 6.891e-03 6.178e-02 0.112 0.91124
## tmmn_max_3b_2a 6.056e-03 5.226e-03 1.159 0.24702
## pr_max_3b_2a 2.538e-03 1.331e-03 1.907 0.05708 .
## pr_mea_60b_2a -1.809e-02 1.947e-02 -0.929 0.35324
## rmin_mea_60b_2a 2.353e-03 6.772e-03 0.347 0.72839
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Approximate significance of smooth terms:
## edf Ref.df F p-value
## s(ag_1985) 2.002 2.482 6.355 0.000937 ***
## s(NDVI_pre_365d) 2.364 2.994 1.817 0.144227
## s(mean_hydro_dist_m) 2.167 2.617 2.004 0.139193
## s(mean_slope) 1.922 2.454 0.710 0.500594
## s(mean_elevation) 6.173 7.290 11.083 < 2e-16 ***
## s(pr_max_10b_2a) 2.546 3.227 3.105 0.021598 *
## s(spi1y) 2.384 2.984 1.047 0.353945
## ti(NDVI_pre_365d,spi1y) 7.621 9.640 2.325 0.011105 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## R-sq.(adj) = 0.356 Deviance explained = 40.5%
## -REML = 471.01 Scale est. = 0.25981 n = 530
## Land cover x topography interactions
mod_edge_LandCov_Slope <- gam(log(edge_dens) ~
s(ag_1985) + wood_cov + nearest_road_m +
NDVI_pre_90d + s(NDVI_pre_365d) + s(mean_hydro_dist_m) +
s(mean_slope) + s(mean_elevation) + soil_order_1 +
vs_mea_3b_2a + vs_mea_30b_2a + tmmn_max_3b_2a +
pr_max_3b_2a + s(pr_max_10b_2a) + pr_mea_60b_2a +
rmin_mea_60b_2a + s(spi1y) +
ti(wood_cov, mean_slope) +
ti(ag_1985, mean_slope),
data = landscape_data_clean,
method = "REML")
summary(mod_edge_LandCov_Slope)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## log(edge_dens) ~ s(ag_1985) + wood_cov + nearest_road_m + NDVI_pre_90d +
## s(NDVI_pre_365d) + s(mean_hydro_dist_m) + s(mean_slope) +
## s(mean_elevation) + soil_order_1 + vs_mea_3b_2a + vs_mea_30b_2a +
## tmmn_max_3b_2a + pr_max_3b_2a + s(pr_max_10b_2a) + pr_mea_60b_2a +
## rmin_mea_60b_2a + s(spi1y) + ti(wood_cov, mean_slope) + ti(ag_1985,
## mean_slope)
##
## Parametric coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.182e+00 1.528e+00 2.736 0.00644 **
## wood_cov 7.068e-03 2.341e-03 3.019 0.00266 **
## nearest_road_m 2.121e-04 7.916e-05 2.680 0.00761 **
## NDVI_pre_90d -2.795e-02 1.916e-01 -0.146 0.88406
## soil_order_11 5.130e-02 7.673e-02 0.669 0.50407
## soil_order_14 -2.596e-01 1.088e-01 -2.386 0.01739 *
## soil_order_19 1.559e-01 9.995e-02 1.560 0.11936
## soil_order_1Other 2.005e-02 1.085e-01 0.185 0.85351
## vs_mea_3b_2a -4.959e-03 3.745e-02 -0.132 0.89471
## vs_mea_30b_2a 3.100e-03 6.115e-02 0.051 0.95958
## tmmn_max_3b_2a 6.404e-03 5.200e-03 1.232 0.21871
## pr_max_3b_2a 2.697e-03 1.340e-03 2.013 0.04465 *
## pr_mea_60b_2a -8.444e-03 1.852e-02 -0.456 0.64865
## rmin_mea_60b_2a 2.789e-03 6.725e-03 0.415 0.67852
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Approximate significance of smooth terms:
## edf Ref.df F p-value
## s(ag_1985) 1.868 2.314 6.569 0.000949 ***
## s(NDVI_pre_365d) 2.471 3.133 1.982 0.112081
## s(mean_hydro_dist_m) 2.356 2.849 2.669 0.059373 .
## s(mean_slope) 1.152 1.281 0.103 0.766239
## s(mean_elevation) 6.215 7.329 11.243 < 2e-16 ***
## s(pr_max_10b_2a) 2.602 3.293 4.344 0.003523 **
## s(spi1y) 3.586 4.452 3.246 0.015804 *
## ti(wood_cov,mean_slope) 3.170 4.306 2.482 0.038955 *
## ti(ag_1985,mean_slope) 1.001 1.002 5.677 0.017537 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## R-sq.(adj) = 0.348 Deviance explained = 39.4%
## -REML = 467.08 Scale est. = 0.26317 n = 530
## Combined interaction model
mod_edge_Int <- gam(log(edge_dens) ~
s(ag_1985) + wood_cov + nearest_road_m +
NDVI_pre_90d + s(NDVI_pre_365d) + s(mean_hydro_dist_m) +
s(mean_slope) + s(mean_elevation) + soil_order_1 +
vs_mea_3b_2a + vs_mea_30b_2a + tmmn_max_3b_2a +
pr_max_3b_2a + s(pr_max_10b_2a) + pr_mea_60b_2a +
rmin_mea_60b_2a + s(spi1y) +
ti(NDVI_pre_365d, spi1y) +
ti(wood_cov, mean_slope) +
ag_1985:mean_slope,
data = landscape_data_clean,
method = "REML")
summary(mod_edge_Int)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## log(edge_dens) ~ s(ag_1985) + wood_cov + nearest_road_m + NDVI_pre_90d +
## s(NDVI_pre_365d) + s(mean_hydro_dist_m) + s(mean_slope) +
## s(mean_elevation) + soil_order_1 + vs_mea_3b_2a + vs_mea_30b_2a +
## tmmn_max_3b_2a + pr_max_3b_2a + s(pr_max_10b_2a) + pr_mea_60b_2a +
## rmin_mea_60b_2a + s(spi1y) + ti(NDVI_pre_365d, spi1y) + ti(wood_cov,
## mean_slope) + ag_1985:mean_slope
##
## Parametric coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.402e+00 1.523e+00 2.891 0.00402 **
## wood_cov 7.629e-03 2.347e-03 3.251 0.00123 **
## nearest_road_m 2.150e-04 7.889e-05 2.726 0.00664 **
## NDVI_pre_90d -6.404e-02 1.910e-01 -0.335 0.73761
## soil_order_11 6.686e-02 7.654e-02 0.873 0.38283
## soil_order_14 -2.426e-01 1.076e-01 -2.256 0.02454 *
## soil_order_19 1.813e-01 9.967e-02 1.819 0.06948 .
## soil_order_1Other 2.705e-02 1.077e-01 0.251 0.80188
## vs_mea_3b_2a -1.507e-02 3.725e-02 -0.405 0.68600
## vs_mea_30b_2a 1.344e-02 6.160e-02 0.218 0.82738
## tmmn_max_3b_2a 5.911e-03 5.198e-03 1.137 0.25608
## pr_max_3b_2a 2.743e-03 1.327e-03 2.067 0.03928 *
## pr_mea_60b_2a -1.958e-02 1.928e-02 -1.016 0.31023
## rmin_mea_60b_2a 2.223e-03 6.723e-03 0.331 0.74098
## ag_1985:mean_slope -1.338e+00 6.093e-01 -2.196 0.02855 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Approximate significance of smooth terms:
## edf Ref.df F p-value
## s(ag_1985) 1.765 2.183 5.963 0.00211 **
## s(NDVI_pre_365d) 2.289 2.892 1.485 0.20687
## s(mean_hydro_dist_m) 2.131 2.574 1.910 0.15955
## s(mean_slope) 1.005 1.010 0.904 0.33943
## s(mean_elevation) 6.097 7.212 12.595 < 2e-16 ***
## s(pr_max_10b_2a) 2.647 3.343 3.539 0.01112 *
## s(spi1y) 2.416 3.024 1.188 0.31117
## ti(NDVI_pre_365d,spi1y) 7.547 9.743 1.998 0.03592 *
## ti(wood_cov,mean_slope) 3.500 4.739 2.535 0.03026 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## R-sq.(adj) = 0.367 Deviance explained = 41.9%
## -REML = 464.79 Scale est. = 0.25545 n = 530
## Model Selection
mod_selection_edge <- model.sel(mod_edge_clean, mod_edge_NDVI_Climate,
mod_edge_LandCov_Slope, mod_edge_Int)
mod_selection_edge
## Model selection table
## (Int) NDV_pre_90d nrs_rod_m pr_max_3b_2a pr_mea_60b_2a
## mod_edge_Int 4.402 -0.06404 0.0002150 0.002743 -0.019580
## mod_edge_NDVI_Climate 4.296 -0.12800 0.0002045 0.002538 -0.018090
## mod_edge_LandCov_Slope 4.182 -0.02795 0.0002121 0.002697 -0.008444
## mod_edge_clean 3.990 -0.08212 0.0002025 0.002504 -0.010680
## rmn_mea_60b_2a s(ag_1985) s(men_elv) s(men_hyd_dst_m)
## mod_edge_Int 0.002223 + + +
## mod_edge_NDVI_Climate 0.002353 + + +
## mod_edge_LandCov_Slope 0.002789 + + +
## mod_edge_clean 0.002853 + + +
## s(men_slp) s(NDV_pre_365) s(pr_max_10b_2a) s(sp1)
## mod_edge_Int + + + +
## mod_edge_NDVI_Climate + + + +
## mod_edge_LandCov_Slope + + + +
## mod_edge_clean + + + +
## sol_ord_1 tmm_max_3b_2a vs_mea_30b_2a vs_mea_3b_2a
## mod_edge_Int + 0.005911 0.013440 -0.015070
## mod_edge_NDVI_Climate + 0.006056 0.006891 -0.015710
## mod_edge_LandCov_Slope + 0.006404 0.003100 -0.004959
## mod_edge_clean + 0.007114 -0.007508 -0.002641
## wod_cov ti(NDV_pre_365,sp1) ti(ag_1985,men_slp)
## mod_edge_Int 0.007629 +
## mod_edge_NDVI_Climate 0.008072 +
## mod_edge_LandCov_Slope 0.007068 +
## mod_edge_clean 0.007439
## ti(wod_cov,men_slp) ag_1985:men_slp df logLik AICc
## mod_edge_Int + -1.338 52 -367.205 851.7
## mod_edge_NDVI_Climate 48 -373.431 854.3
## mod_edge_LandCov_Slope + 44 -378.331 855.1
## mod_edge_clean 41 -385.239 860.9
## delta weight
## mod_edge_Int 0.00 0.679
## mod_edge_NDVI_Climate 2.57 0.188
## mod_edge_LandCov_Slope 3.37 0.126
## mod_edge_clean 9.19 0.007
## Models ranked by AICc(x)
## Selected model
mod_edge_best <- mod_edge_Int
summary(mod_edge_best)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## log(edge_dens) ~ s(ag_1985) + wood_cov + nearest_road_m + NDVI_pre_90d +
## s(NDVI_pre_365d) + s(mean_hydro_dist_m) + s(mean_slope) +
## s(mean_elevation) + soil_order_1 + vs_mea_3b_2a + vs_mea_30b_2a +
## tmmn_max_3b_2a + pr_max_3b_2a + s(pr_max_10b_2a) + pr_mea_60b_2a +
## rmin_mea_60b_2a + s(spi1y) + ti(NDVI_pre_365d, spi1y) + ti(wood_cov,
## mean_slope) + ag_1985:mean_slope
##
## Parametric coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.402e+00 1.523e+00 2.891 0.00402 **
## wood_cov 7.629e-03 2.347e-03 3.251 0.00123 **
## nearest_road_m 2.150e-04 7.889e-05 2.726 0.00664 **
## NDVI_pre_90d -6.404e-02 1.910e-01 -0.335 0.73761
## soil_order_11 6.686e-02 7.654e-02 0.873 0.38283
## soil_order_14 -2.426e-01 1.076e-01 -2.256 0.02454 *
## soil_order_19 1.813e-01 9.967e-02 1.819 0.06948 .
## soil_order_1Other 2.705e-02 1.077e-01 0.251 0.80188
## vs_mea_3b_2a -1.507e-02 3.725e-02 -0.405 0.68600
## vs_mea_30b_2a 1.344e-02 6.160e-02 0.218 0.82738
## tmmn_max_3b_2a 5.911e-03 5.198e-03 1.137 0.25608
## pr_max_3b_2a 2.743e-03 1.327e-03 2.067 0.03928 *
## pr_mea_60b_2a -1.958e-02 1.928e-02 -1.016 0.31023
## rmin_mea_60b_2a 2.223e-03 6.723e-03 0.331 0.74098
## ag_1985:mean_slope -1.338e+00 6.093e-01 -2.196 0.02855 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Approximate significance of smooth terms:
## edf Ref.df F p-value
## s(ag_1985) 1.765 2.183 5.963 0.00211 **
## s(NDVI_pre_365d) 2.289 2.892 1.485 0.20687
## s(mean_hydro_dist_m) 2.131 2.574 1.910 0.15955
## s(mean_slope) 1.005 1.010 0.904 0.33943
## s(mean_elevation) 6.097 7.212 12.595 < 2e-16 ***
## s(pr_max_10b_2a) 2.647 3.343 3.539 0.01112 *
## s(spi1y) 2.416 3.024 1.188 0.31117
## ti(NDVI_pre_365d,spi1y) 7.547 9.743 1.998 0.03592 *
## ti(wood_cov,mean_slope) 3.500 4.739 2.535 0.03026 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## R-sq.(adj) = 0.367 Deviance explained = 41.9%
## -REML = 464.79 Scale est. = 0.25545 n = 530
# Model Fit
performance::check_collinearity(mod_edge_best)
## Model has interaction terms. VIFs might be inflated.
## Try to center the variables used for the interaction, or check
## multicollinearity among predictors of a model without interaction terms.
## # Check for Multicollinearity
##
## Low Correlation
##
## Term VIF VIF 95% CI adj. VIF Tolerance Tolerance 95% CI
## nearest_road_m 1.17 [ 1.09, 1.32] 1.08 0.86 [0.76, 0.92]
## NDVI_pre_90d 1.63 [ 1.47, 1.84] 1.28 0.61 [0.54, 0.68]
## vs_mea_3b_2a 2.30 [ 2.04, 2.62] 1.52 0.44 [0.38, 0.49]
## vs_mea_30b_2a 2.57 [ 2.27, 2.94] 1.60 0.39 [0.34, 0.44]
## tmmn_max_3b_2a 1.56 [ 1.41, 1.76] 1.25 0.64 [0.57, 0.71]
## pr_max_3b_2a 1.48 [ 1.35, 1.67] 1.22 0.67 [0.60, 0.74]
## pr_mea_60b_2a 2.64 [ 2.33, 3.02] 1.62 0.38 [0.33, 0.43]
## rmin_mea_60b_2a 1.69 [ 1.52, 1.91] 1.30 0.59 [0.52, 0.66]
##
## Moderate Correlation
##
## Term VIF VIF 95% CI adj. VIF Tolerance Tolerance 95% CI
## s(ag_1985) 8.34 [ 7.18, 9.73] 2.89 0.12 [0.10, 0.14]
## s(mean_hydro_dist_m) 5.41 [ 4.69, 6.29] 2.33 0.18 [0.16, 0.21]
## soil_order_1 6.01 [ 5.19, 6.99] 1.25 0.17 [0.14, 0.19]
##
## High Correlation
##
## Term VIF VIF 95% CI adj. VIF Tolerance Tolerance 95% CI
## wood_cov 57.47 [ 48.97, 67.48] 7.58 0.02 [0.01, 0.02]
## s(NDVI_pre_365d) 190.45 [162.08, 223.81] 13.80 5.25e-03 [0.00, 0.01]
## s(mean_slope) 14.06 [ 12.04, 16.45] 3.75 0.07 [0.06, 0.08]
## s(mean_elevation) 34.63 [ 29.54, 40.63] 5.88 0.03 [0.02, 0.03]
## s(pr_max_10b_2a) 30.39 [ 25.93, 35.65] 5.51 0.03 [0.03, 0.04]
## s(spi1y) 149.23 [127.02, 175.36] 12.22 6.70e-03 [0.01, 0.01]
performance::check_outliers(mod_edge_best)
## OK: No outliers detected.
## - Based on the following method and threshold: cook (1).
## - For variable: (Whole model)
## Plot
plot(mod_edge_best, pages = 4, shade = TRUE, shade.col = "lightblue", all.terms = TRUE)
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in axis(1, at = seq_along(ll), labels = ll, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
edge_candidates <- list(
mod_edge_clean = mod_edge_clean,
mod_edge_NDVI_Climate = mod_edge_NDVI_Climate,
mod_edge_LandCov_Slope = mod_edge_LandCov_Slope,
mod_edge_Int = mod_edge_Int
)
cv_edge <- cv_compare(edge_candidates, landscape_data_clean,
K = 10, reps = 5, seed = 1)
cv_edge
## model CV_RMSE RMSE_SD CV_MAE CV_R2 R2_SD
## 1 mod_edge_NDVI_Climate 0.5428980 0.001507820 0.4323507 0.2684994 0.004064240
## 2 mod_edge_clean 0.5447582 0.002380710 0.4333763 0.2634712 0.006436699
## 3 mod_edge_Int 0.5461756 0.005574657 0.4358400 0.2595832 0.015179926
## 4 mod_edge_LandCov_Slope 0.5470742 0.003787106 0.4352183 0.2571783 0.010314839
## delta_RMSE
## 1 0.000000000
## 2 0.001860201
## 3 0.003277582
## 4 0.004176179
write.csv(cv_edge, "edge_density_cv_results.csv", row.names = FALSE)
edge_tables <- backtransform_tables(mod_edge_best)
edge_tables$param
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.4015533243 1.522628e+00 2.8907614 0.004015262
## wood_cov 0.0076291534 2.347053e-03 3.2505242 0.001231910
## nearest_road_m 0.0002150471 7.888781e-05 2.7259864 0.006642655
## NDVI_pre_90d -0.0640384530 1.910360e-01 -0.3352167 0.737606360
## soil_order_11 0.0668603091 7.654498e-02 0.8734774 0.382834645
## soil_order_14 -0.2426018234 1.075574e-01 -2.2555571 0.024542683
## soil_order_19 0.1813229694 9.966722e-02 1.8192839 0.069483796
## soil_order_1Other 0.0270504639 1.077487e-01 0.2510515 0.801880470
## vs_mea_3b_2a -0.0150668574 3.724572e-02 -0.4045258 0.686004189
## vs_mea_30b_2a 0.0134406572 6.160483e-02 0.2181754 0.827384120
## tmmn_max_3b_2a 0.0059107148 5.198286e-03 1.1370507 0.256077858
## pr_max_3b_2a 0.0027433480 1.327347e-03 2.0667903 0.039283392
## pr_mea_60b_2a -0.0195803530 1.927562e-02 -1.0158094 0.310225993
## rmin_mea_60b_2a 0.0022234833 6.722750e-03 0.3307401 0.740983436
## ag_1985:mean_slope -1.3380551876 6.092582e-01 -2.1962040 0.028549415
## exp_estimate percent_change
## (Intercept) 81.577 8057.7
## wood_cov 1.008 0.8
## nearest_road_m 1.000 0.0
## NDVI_pre_90d 0.938 -6.2
## soil_order_11 1.069 6.9
## soil_order_14 0.785 -21.5
## soil_order_19 1.199 19.9
## soil_order_1Other 1.027 2.7
## vs_mea_3b_2a 0.985 -1.5
## vs_mea_30b_2a 1.014 1.4
## tmmn_max_3b_2a 1.006 0.6
## pr_max_3b_2a 1.003 0.3
## pr_mea_60b_2a 0.981 -1.9
## rmin_mea_60b_2a 1.002 0.2
## ag_1985:mean_slope 0.262 -73.8
edge_tables$smooth
## edf Ref.df F p-value p_value
## s(ag_1985) 1.76 2.183396 5.96 0.002106984 0.0021
## s(NDVI_pre_365d) 2.29 2.892089 1.48 0.206872322 0.2069
## s(mean_hydro_dist_m) 2.13 2.573509 1.91 0.159546537 0.1595
## s(mean_slope) 1.01 1.010253 0.90 0.339428772 0.3394
## s(mean_elevation) 6.10 7.212241 12.60 0.000000000 0.0000
## s(pr_max_10b_2a) 2.65 3.343162 3.54 0.011118777 0.0111
## s(spi1y) 2.42 3.024152 1.19 0.311166937 0.3112
## ti(NDVI_pre_365d,spi1y) 7.55 9.743193 2.00 0.035921540 0.0359
## ti(wood_cov,mean_slope) 3.50 4.739282 2.54 0.030263742 0.0303
write.csv(edge_tables$param, "backtransformed_param_summary.csv", row.names = TRUE)
write.csv(edge_tables$smooth, "smooth_summary.csv", row.names = TRUE)
focus_vars <- c("wood_cov", "nearest_road_m")
effects_df <- do.call(rbind, lapply(focus_vars, function(v) {
get_effect(mod_edge_best, landscape_data_clean, v)
}))
x_labels <- c("wood_cov" = "Wood Cover (%)",
"nearest_road_m" = "Distance to Nearest Road (m)")
# Shared y-axis across panels
y_range_linear <- range(c(effects_df$lower, effects_df$upper), na.rm = TRUE)
plots <- lapply(focus_vars, function(var) {
df <- effects_df %>% filter(variable == var)
ggplot(df, aes(x = x, y = fit)) +
geom_line(linewidth = 1.2, color = "#D55E00") +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.2, fill = "#D55E00") +
coord_cartesian(ylim = y_range_linear) +
theme_classic(base_size = 14) +
theme(
axis.title = element_text(size = 16, face = "bold"),
axis.text = element_text(size = 14),
plot.tag = element_text(size = 18, face = "bold")
) +
labs(x = x_labels[var], y = "Predicted Edge Density")
})
combined_plot <- plots[[1]] + plots[[2]] +
plot_layout(ncol = 2) +
plot_annotation(tag_levels = "A")
combined_plot
ggsave(file.path(fig_dir, "Edge_Density_Effects.png"),
combined_plot, width = 12, height = 6)
smooth_vars <- c("ag_1985", "mean_hydro_dist_m", "mean_elevation")
smooth_effects <- do.call(rbind, lapply(smooth_vars, function(v) {
get_effect(mod_edge_best, landscape_data_clean, v)
}))
x_labels_smooth <- c(
"ag_1985" = "Agricultural Land Use (1985, %)",
"mean_hydro_dist_m" = "Distance to Hydrologic Feature (m)",
"mean_elevation" = "Elevation (m)"
)
# Shared y-axis across panels
y_range_smooth_edge <- range(c(smooth_effects$lower, smooth_effects$upper), na.rm = TRUE)
smooth_plots <- lapply(smooth_vars, function(var) {
df <- smooth_effects %>% filter(variable == var)
ggplot(df, aes(x = x, y = fit)) +
geom_line(linewidth = 1.2, color = "forestgreen") +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.2, fill = "lightgreen") +
coord_cartesian(ylim = y_range_smooth_edge) +
theme_classic(base_size = 14) +
theme(
axis.title = element_text(size = 16, face = "bold"),
axis.text = element_text(size = 14),
plot.tag = element_text(size = 18, face = "bold")
) +
labs(x = x_labels_smooth[var], y = "Predicted Edge Density")
})
combined_smooth_plot <- smooth_plots[[1]] + smooth_plots[[2]] + smooth_plots[[3]] +
plot_layout(ncol = 3) +
plot_annotation(tag_levels = "A")
combined_smooth_plot
ggsave(file.path(fig_dir, "Edge_Density_Smooth_Effects.png"),
combined_smooth_plot, width = 18, height = 6)
Significant terms that do NOT appear in the interaction figure. Distance to the nearest hydrologic feature is excluded because it is not significant in the retained model (p = 0.160); both precipitation terms are included because they are (p = 0.011 and 0.039). Woody cover and historic agriculture are significant but are shown in the interaction figure instead, so they are not repeated here.
smooth_vars_all <- c("mean_elevation", "nearest_road_m",
"pr_max_10b_2a", "pr_max_3b_2a")
smooth_effects_all <- do.call(rbind, lapply(smooth_vars_all, function(v) {
get_effect(mod_edge_best, landscape_data_clean, v)
}))
x_labels_all <- c(
"mean_elevation" = "Elevation (m)",
"nearest_road_m" = "Distance to Nearest Road (m)",
"pr_max_10b_2a" = "Maximum Precipitation (10-day, mm)",
"pr_max_3b_2a" = "Maximum Precipitation (3-day, mm)"
)
# Shared y-axis
y_range_smooth <- range(c(smooth_effects_all$lower, smooth_effects_all$upper), na.rm = TRUE)
all_plots <- lapply(smooth_vars_all, function(var) {
df <- smooth_effects_all %>% filter(variable == var)
ggplot(df, aes(x = x, y = fit)) +
geom_line(linewidth = 1.2, color = "#D55E00") +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.2, fill = "#D55E00") +
coord_cartesian(ylim = y_range_smooth) +
theme_classic(base_size = 14) +
theme(
axis.title = element_text(size = 16, face = "bold"),
axis.text = element_text(size = 14),
plot.tag = element_text(size = 18, face = "bold")
) +
labs(x = x_labels_all[var], y = "Edge Density")
})
combined_patchwork <- all_plots[[1]] + all_plots[[2]] +
all_plots[[3]] + all_plots[[4]] +
plot_layout(ncol = 2) +
plot_annotation(tag_levels = "A")
combined_patchwork
ggsave(file.path(fig_dir, "Edge_Density_Significant_Effects.png"),
combined_patchwork, width = 12, height = 10)
## Pastel palette for the five quantile groups, running cool (low) to warm (high)
## so the ordering of the quantiles reads intuitively. Change here to restyle all
## three panels at once.
pastel_pal <- c("#92C5DE", "#C5E0B4", "#F6D98A", "#F4A582", "#C994C7")
## 1. NDVI x SPI
ndvi_spi_lines <- get_interaction_lines(
mod_edge_best, landscape_data_clean, "NDVI_pre_365d", "spi1y"
)
ndvi_spi_plot <- ggplot(ndvi_spi_lines, aes(x = x, y = fit, color = group, fill = group)) +
geom_line(linewidth = 1.2) +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.15, color = NA) +
theme_classic(base_size = 14) +
theme(
axis.title = element_text(size = 16, face = "bold"),
axis.text = element_text(size = 14),
legend.title = element_text(size = 14),
legend.text = element_text(size = 12)
) +
scale_color_manual(values = pastel_pal) +
scale_fill_manual(values = pastel_pal) +
labs(x = "NDVI (365-day)", y = "Edge Density",
color = "SPI (quantiles)", fill = "SPI (quantiles)")
## 2. Wood Cover x Slope
wood_slope_df <- get_interaction_lines(
mod_edge_best, landscape_data_clean, "wood_cov", "mean_slope"
)
wood_slope_plot <- ggplot(wood_slope_df, aes(x = x, y = fit, color = group, fill = group)) +
geom_line(linewidth = 1.2) +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.15, color = NA) +
theme_classic(base_size = 14) +
theme(
axis.title = element_text(size = 16, face = "bold"),
axis.text = element_text(size = 14),
legend.title = element_text(size = 14),
legend.text = element_text(size = 12)
) +
scale_color_manual(values = pastel_pal) +
scale_fill_manual(values = pastel_pal) +
labs(x = "Wood Cover (%)", y = "Edge Density",
color = "Slope (quantiles)", fill = "Slope (quantiles)")
## 3. Agriculture x Slope
ag_slope_df <- get_interaction_lines(
mod_edge_best, landscape_data_clean, "ag_1985", "mean_slope"
)
ag_slope_plot <- ggplot(ag_slope_df, aes(x = x, y = fit, color = group, fill = group)) +
geom_line(linewidth = 1.2) +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.15, color = NA) +
theme_classic(base_size = 14) +
theme(
axis.title = element_text(size = 16, face = "bold"),
axis.text = element_text(size = 14),
legend.title = element_text(size = 14),
legend.text = element_text(size = 12)
) +
scale_color_manual(values = pastel_pal) +
scale_fill_manual(values = pastel_pal) +
labs(x = "Agricultural Land Use (1985, %)", y = "Edge Density",
color = "Slope (quantiles)", fill = "Slope (quantiles)")
## Shared y-axis scale
combined_int_data <- rbind(ndvi_spi_lines, wood_slope_df, ag_slope_df)
y_range_int <- range(c(combined_int_data$lower, combined_int_data$upper), na.rm = TRUE)
ndvi_spi_plot <- ndvi_spi_plot + coord_cartesian(ylim = y_range_int)
wood_slope_plot <- wood_slope_plot + coord_cartesian(ylim = y_range_int)
ag_slope_plot <- ag_slope_plot + coord_cartesian(ylim = y_range_int)
final_plot <- ndvi_spi_plot + wood_slope_plot + ag_slope_plot +
plot_layout(ncol = 1) +
plot_annotation(tag_levels = "A")
final_plot
ggsave(file.path(fig_dir, "Edge_Density_Interactions.png"),
final_plot, width = 10, height = 18)
Baseline model, all observations.
mod_pa_ln <- gam(
log(avg_patch_area) ~
ag_1985 +
wood_cov +
s(road_dens_km_km2) +
nearest_road_m +
NDVI_pre_90d +
NDVI_pre_365d +
s(mean_hydro_dist_m) +
mean_elevation +
soil_order_1 +
vs_min_3b_2a +
tmmn_mea_60b_2a +
tmmx_max_3b_2a +
pr_mea_10b_2a +
s(vpd_min_10b_2a) +
spei1y +
spei14d,
data = landscape_data,
method = "REML"
)
summary(mod_pa_ln)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## log(avg_patch_area) ~ ag_1985 + wood_cov + s(road_dens_km_km2) +
## nearest_road_m + NDVI_pre_90d + NDVI_pre_365d + s(mean_hydro_dist_m) +
## mean_elevation + soil_order_1 + vs_min_3b_2a + tmmn_mea_60b_2a +
## tmmx_max_3b_2a + pr_mea_10b_2a + s(vpd_min_10b_2a) + spei1y +
## spei14d
##
## Parametric coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.3506115 3.4469229 1.262 0.20746
## ag_1985 -1.2137005 1.2104532 -1.003 0.31649
## wood_cov -0.0097382 0.0033543 -2.903 0.00385 **
## nearest_road_m -0.0000426 0.0001298 -0.328 0.74288
## NDVI_pre_90d -0.2726924 0.2778005 -0.982 0.32675
## NDVI_pre_365d 0.4372282 0.5831493 0.750 0.45374
## mean_elevation -0.0013383 0.0005324 -2.514 0.01226 *
## soil_order_11 0.1766769 0.1108523 1.594 0.11159
## soil_order_14 0.0351500 0.1443108 0.244 0.80766
## soil_order_19 -0.1429263 0.1271527 -1.124 0.26152
## soil_order_1Other 0.3192304 0.1537520 2.076 0.03837 *
## vs_min_3b_2a -0.0885299 0.0479380 -1.847 0.06536 .
## tmmn_mea_60b_2a -0.0338649 0.0110683 -3.060 0.00233 **
## tmmx_max_3b_2a 0.0164805 0.0118824 1.387 0.16606
## pr_mea_10b_2a 0.0022377 0.0134478 0.166 0.86791
## spei1y 0.0710355 0.0391043 1.817 0.06987 .
## spei14d 0.0494428 0.0525899 0.940 0.34758
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Approximate significance of smooth terms:
## edf Ref.df F p-value
## s(road_dens_km_km2) 2.601 3.321 3.184 0.0198 *
## s(mean_hydro_dist_m) 2.011 2.461 1.460 0.2272
## s(vpd_min_10b_2a) 2.409 3.007 2.532 0.0562 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## R-sq.(adj) = 0.1 Deviance explained = 13.9%
## -REML = 664.27 Scale est. = 0.58606 n = 538
performance::check_outliers(mod_pa_ln)
## OK: No outliers detected.
## - Based on the following method and threshold: cook (1).
## - For variable: (Whole model)
## Plot
plot(mod_pa_ln, pages = 4, shade = TRUE, shade.col = "lightblue", all.terms = TRUE)
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in axis(1, at = seq_along(ll), labels = ll, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
sim_res_pa <- simulateResiduals(mod_pa_ln)
outlier_idx_pa <- outliers(sim_res_pa)
rows_used_pa <- as.numeric(rownames(mod_pa_ln$model))
if (length(outlier_idx_pa) > 0) {
landscape_data_pa_clean <- landscape_data[-rows_used_pa[outlier_idx_pa], ]
} else {
landscape_data_pa_clean <- landscape_data
}
nrow(landscape_data) - nrow(landscape_data_pa_clean) # n outliers dropped
## [1] 1
## Base model, outliers removed
mod_pa_clean <- gam(
log(avg_patch_area) ~
ag_1985 + wood_cov + s(road_dens_km_km2) + nearest_road_m +
NDVI_pre_90d + NDVI_pre_365d + s(mean_hydro_dist_m) +
mean_elevation + soil_order_1 +
vs_min_3b_2a + tmmn_mea_60b_2a + tmmx_max_3b_2a +
pr_mea_10b_2a + s(vpd_min_10b_2a) + spei1y + spei14d,
data = landscape_data_pa_clean,
method = "REML"
)
summary(mod_pa_clean)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## log(avg_patch_area) ~ ag_1985 + wood_cov + s(road_dens_km_km2) +
## nearest_road_m + NDVI_pre_90d + NDVI_pre_365d + s(mean_hydro_dist_m) +
## mean_elevation + soil_order_1 + vs_min_3b_2a + tmmn_mea_60b_2a +
## tmmx_max_3b_2a + pr_mea_10b_2a + s(vpd_min_10b_2a) + spei1y +
## spei14d
##
## Parametric coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.001e+00 3.432e+00 1.166 0.24422
## ag_1985 -1.205e+00 1.203e+00 -1.001 0.31715
## wood_cov -9.154e-03 3.342e-03 -2.739 0.00638 **
## nearest_road_m -5.139e-05 1.293e-04 -0.398 0.69113
## NDVI_pre_90d -3.066e-01 2.765e-01 -1.109 0.26799
## NDVI_pre_365d 4.259e-01 5.799e-01 0.734 0.46307
## mean_elevation -1.359e-03 5.295e-04 -2.567 0.01055 *
## soil_order_11 1.709e-01 1.102e-01 1.550 0.12167
## soil_order_14 -5.375e-03 1.443e-01 -0.037 0.97029
## soil_order_19 -1.444e-01 1.265e-01 -1.142 0.25419
## soil_order_1Other 3.177e-01 1.529e-01 2.078 0.03824 *
## vs_min_3b_2a -9.795e-02 4.778e-02 -2.050 0.04088 *
## tmmn_mea_60b_2a -3.348e-02 1.101e-02 -3.042 0.00247 **
## tmmx_max_3b_2a 1.728e-02 1.183e-02 1.461 0.14469
## pr_mea_10b_2a 3.443e-03 1.338e-02 0.257 0.79701
## spei1y 7.300e-02 3.888e-02 1.878 0.06101 .
## spei14d 4.183e-02 5.236e-02 0.799 0.42473
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Approximate significance of smooth terms:
## edf Ref.df F p-value
## s(road_dens_km_km2) 2.534 3.238 2.940 0.0292 *
## s(mean_hydro_dist_m) 2.062 2.523 1.629 0.1830
## s(vpd_min_10b_2a) 2.477 3.091 2.671 0.0452 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## R-sq.(adj) = 0.101 Deviance explained = 13.9%
## -REML = 660.1 Scale est. = 0.57918 n = 537
## NDVI x drought interaction
mod_pa_NDVI_Climate <- gam(
log(avg_patch_area) ~
ag_1985 + wood_cov + s(road_dens_km_km2) + nearest_road_m +
NDVI_pre_90d + NDVI_pre_365d + s(mean_hydro_dist_m) +
mean_elevation + soil_order_1 +
vs_min_3b_2a + tmmn_mea_60b_2a + tmmx_max_3b_2a +
pr_mea_10b_2a + s(vpd_min_10b_2a) + spei1y + spei14d +
ti(NDVI_pre_365d, spei1y),
data = landscape_data_pa_clean,
method = "REML"
)
summary(mod_pa_NDVI_Climate)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## log(avg_patch_area) ~ ag_1985 + wood_cov + s(road_dens_km_km2) +
## nearest_road_m + NDVI_pre_90d + NDVI_pre_365d + s(mean_hydro_dist_m) +
## mean_elevation + soil_order_1 + vs_min_3b_2a + tmmn_mea_60b_2a +
## tmmx_max_3b_2a + pr_mea_10b_2a + s(vpd_min_10b_2a) + spei1y +
## spei14d + ti(NDVI_pre_365d, spei1y)
##
## Parametric coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.394e+00 3.417e+00 1.286 0.19900
## ag_1985 -1.300e+00 1.197e+00 -1.087 0.27773
## wood_cov -8.983e-03 3.336e-03 -2.693 0.00732 **
## nearest_road_m -5.274e-05 1.301e-04 -0.405 0.68534
## NDVI_pre_90d -3.162e-01 2.769e-01 -1.142 0.25398
## NDVI_pre_365d 1.477e-01 6.135e-01 0.241 0.80986
## mean_elevation -1.366e-03 5.292e-04 -2.581 0.01013 *
## soil_order_11 1.631e-01 1.099e-01 1.484 0.13845
## soil_order_14 1.641e-03 1.432e-01 0.011 0.99086
## soil_order_19 -1.418e-01 1.274e-01 -1.113 0.26625
## soil_order_1Other 2.986e-01 1.521e-01 1.963 0.05020 .
## vs_min_3b_2a -9.924e-02 4.750e-02 -2.089 0.03717 *
## tmmn_mea_60b_2a -3.307e-02 1.097e-02 -3.014 0.00271 **
## tmmx_max_3b_2a 1.605e-02 1.181e-02 1.360 0.17456
## pr_mea_10b_2a 2.558e-03 1.331e-02 0.192 0.84768
## spei1y 7.543e-02 3.873e-02 1.948 0.05201 .
## spei14d 4.173e-02 5.215e-02 0.800 0.42402
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Approximate significance of smooth terms:
## edf Ref.df F p-value
## s(road_dens_km_km2) 2.633 3.360 3.206 0.0190 *
## s(mean_hydro_dist_m) 1.890 2.315 1.116 0.3254
## s(vpd_min_10b_2a) 2.651 3.309 3.112 0.0219 *
## ti(NDVI_pre_365d,spei1y) 2.772 3.294 2.145 0.0717 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## R-sq.(adj) = 0.112 Deviance explained = 15.5%
## -REML = 658.14 Scale est. = 0.57157 n = 537
## Land cover x topography interactions
mod_pa_LandCov_Elev <- gam(
log(avg_patch_area) ~
ag_1985 + wood_cov + s(road_dens_km_km2) + nearest_road_m +
NDVI_pre_90d + NDVI_pre_365d + s(mean_hydro_dist_m) +
mean_elevation + soil_order_1 +
vs_min_3b_2a + tmmn_mea_60b_2a + tmmx_max_3b_2a +
pr_mea_10b_2a + s(vpd_min_10b_2a) + spei1y + spei14d +
ti(wood_cov, mean_elevation) +
ti(ag_1985, mean_elevation),
data = landscape_data_pa_clean,
method = "REML"
)
summary(mod_pa_LandCov_Elev)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## log(avg_patch_area) ~ ag_1985 + wood_cov + s(road_dens_km_km2) +
## nearest_road_m + NDVI_pre_90d + NDVI_pre_365d + s(mean_hydro_dist_m) +
## mean_elevation + soil_order_1 + vs_min_3b_2a + tmmn_mea_60b_2a +
## tmmx_max_3b_2a + pr_mea_10b_2a + s(vpd_min_10b_2a) + spei1y +
## spei14d + ti(wood_cov, mean_elevation) + ti(ag_1985, mean_elevation)
##
## Parametric coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.449e+00 3.451e+00 1.000 0.31794
## ag_1985 -1.351e+00 1.288e+00 -1.049 0.29461
## wood_cov -9.905e-03 3.512e-03 -2.821 0.00498 **
## nearest_road_m -5.756e-05 1.294e-04 -0.445 0.65658
## NDVI_pre_90d -3.122e-01 2.764e-01 -1.130 0.25912
## NDVI_pre_365d 4.661e-01 5.848e-01 0.797 0.42579
## mean_elevation -8.599e-04 8.923e-04 -0.964 0.33571
## soil_order_11 1.759e-01 1.107e-01 1.590 0.11252
## soil_order_14 5.794e-02 1.504e-01 0.385 0.70021
## soil_order_19 -1.326e-01 1.274e-01 -1.041 0.29837
## soil_order_1Other 3.144e-01 1.527e-01 2.059 0.04002 *
## vs_min_3b_2a -1.039e-01 4.785e-02 -2.170 0.03044 *
## tmmn_mea_60b_2a -3.208e-02 1.111e-02 -2.888 0.00404 **
## tmmx_max_3b_2a 1.788e-02 1.188e-02 1.505 0.13303
## pr_mea_10b_2a 4.583e-03 1.341e-02 0.342 0.73261
## spei1y 7.849e-02 3.902e-02 2.011 0.04482 *
## spei14d 2.926e-02 5.290e-02 0.553 0.58042
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Approximate significance of smooth terms:
## edf Ref.df F p-value
## s(road_dens_km_km2) 2.450 3.131 2.361 0.0670 .
## s(mean_hydro_dist_m) 1.976 2.416 1.323 0.2512
## s(vpd_min_10b_2a) 2.513 3.134 2.818 0.0366 *
## ti(wood_cov,mean_elevation) 1.901 2.565 0.971 0.4085
## ti(ag_1985,mean_elevation) 1.386 1.669 0.358 0.5457
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## R-sq.(adj) = 0.103 Deviance explained = 14.7%
## -REML = 656.33 Scale est. = 0.57743 n = 537
## Combined interaction model
mod_pa_Int <- gam(
log(avg_patch_area) ~
ag_1985 + wood_cov + s(road_dens_km_km2) + nearest_road_m +
NDVI_pre_90d + NDVI_pre_365d + s(mean_hydro_dist_m) +
mean_elevation + soil_order_1 +
vs_min_3b_2a + tmmn_mea_60b_2a + tmmx_max_3b_2a +
pr_mea_10b_2a + s(vpd_min_10b_2a) + spei1y + spei14d +
ti(NDVI_pre_365d, spei1y) +
ti(wood_cov, mean_elevation) +
ag_1985:mean_elevation,
data = landscape_data_pa_clean,
method = "REML"
)
summary(mod_pa_Int)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## log(avg_patch_area) ~ ag_1985 + wood_cov + s(road_dens_km_km2) +
## nearest_road_m + NDVI_pre_90d + NDVI_pre_365d + s(mean_hydro_dist_m) +
## mean_elevation + soil_order_1 + vs_min_3b_2a + tmmn_mea_60b_2a +
## tmmx_max_3b_2a + pr_mea_10b_2a + s(vpd_min_10b_2a) + spei1y +
## spei14d + ti(NDVI_pre_365d, spei1y) + ti(wood_cov, mean_elevation) +
## ag_1985:mean_elevation
##
## Parametric coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.954e+00 3.439e+00 1.150 0.25076
## ag_1985 -3.943e-01 1.627e+00 -0.242 0.80865
## wood_cov -1.007e-02 3.488e-03 -2.887 0.00406 **
## nearest_road_m -6.027e-05 1.301e-04 -0.463 0.64344
## NDVI_pre_90d -3.134e-01 2.772e-01 -1.131 0.25879
## NDVI_pre_365d 1.360e-01 6.151e-01 0.221 0.82516
## mean_elevation -5.297e-04 8.860e-04 -0.598 0.55020
## soil_order_11 1.601e-01 1.100e-01 1.455 0.14631
## soil_order_14 4.973e-02 1.491e-01 0.333 0.73893
## soil_order_19 -1.285e-01 1.282e-01 -1.002 0.31660
## soil_order_1Other 2.998e-01 1.522e-01 1.970 0.04936 *
## vs_min_3b_2a -1.012e-01 4.756e-02 -2.127 0.03392 *
## tmmn_mea_60b_2a -3.190e-02 1.108e-02 -2.879 0.00416 **
## tmmx_max_3b_2a 1.655e-02 1.187e-02 1.395 0.16367
## pr_mea_10b_2a 2.813e-03 1.332e-02 0.211 0.83284
## spei1y 7.950e-02 3.890e-02 2.044 0.04149 *
## spei14d 3.593e-02 5.252e-02 0.684 0.49416
## ag_1985:mean_elevation -1.289e-02 1.846e-02 -0.699 0.48517
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Approximate significance of smooth terms:
## edf Ref.df F p-value
## s(road_dens_km_km2) 2.553 3.260 2.725 0.0387 *
## s(mean_hydro_dist_m) 1.825 2.237 0.954 0.3790
## s(vpd_min_10b_2a) 2.640 3.295 3.104 0.0226 *
## ti(NDVI_pre_365d,spei1y) 2.737 3.260 1.995 0.0894 .
## ti(wood_cov,mean_elevation) 1.009 1.017 1.252 0.2674
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## R-sq.(adj) = 0.111 Deviance explained = 15.7%
## -REML = 659.34 Scale est. = 0.57262 n = 537
## Model Selection
mod_selection_pa <- model.sel(mod_pa_clean, mod_pa_NDVI_Climate,
mod_pa_LandCov_Elev, mod_pa_Int)
mod_selection_pa
## Model selection table
## (Int) ag_1985 men_elv NDV_pre_365 NDV_pre_90d nrs_rod_m
## mod_pa_NDVI_Climate 4.394 -1.3000 -0.0013660 0.1477 -0.3162 -5.274e-05
## mod_pa_clean 4.001 -1.2050 -0.0013590 0.4259 -0.3066 -5.139e-05
## mod_pa_Int 3.954 -0.3943 -0.0005297 0.1360 -0.3134 -6.027e-05
## mod_pa_LandCov_Elev 3.449 -1.3510 -0.0008598 0.4661 -0.3122 -5.756e-05
## pr_mea_10b_2a s(men_hyd_dst_m) s(rod_dns_km_km2)
## mod_pa_NDVI_Climate 0.002558 + +
## mod_pa_clean 0.003443 + +
## mod_pa_Int 0.002813 + +
## mod_pa_LandCov_Elev 0.004583 + +
## s(vpd_min_10b_2a) sol_ord_1 s14 sp1 tmmn_mea_60b_2a
## mod_pa_NDVI_Climate + + 0.04173 0.07543 -0.03307
## mod_pa_clean + + 0.04183 0.07300 -0.03348
## mod_pa_Int + + 0.03593 0.07950 -0.03190
## mod_pa_LandCov_Elev + + 0.02926 0.07849 -0.03208
## tmmx_max_3b_2a vs_min_3b_2a wod_cov ti(NDV_pre_365,sp1)
## mod_pa_NDVI_Climate 0.01605 -0.09924 -0.008983 +
## mod_pa_clean 0.01728 -0.09795 -0.009154
## mod_pa_Int 0.01655 -0.10120 -0.010070 +
## mod_pa_LandCov_Elev 0.01788 -0.10390 -0.009905
## ti(ag_1985,men_elv) ti(wod_cov,men_elv) ag_1985:men_elv df
## mod_pa_NDVI_Climate 30
## mod_pa_clean 26
## mod_pa_Int + -0.01289 32
## mod_pa_LandCov_Elev + + 30
## logLik AICc delta weight
## mod_pa_NDVI_Climate -597.959 1260.2 0.00 0.649
## mod_pa_clean -603.016 1262.7 2.46 0.190
## mod_pa_Int -597.492 1263.3 3.11 0.137
## mod_pa_LandCov_Elev -600.548 1266.8 6.62 0.024
## Models ranked by AICc(x)
## Selected model: mod_pa_NDVI_Climate (lowest AICc, weight = 0.66;
## mod_pa_Int delta = 2.42, mod_pa_clean delta = 3.32)
mod_pa_best <- mod_pa_NDVI_Climate
summary(mod_pa_best)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## log(avg_patch_area) ~ ag_1985 + wood_cov + s(road_dens_km_km2) +
## nearest_road_m + NDVI_pre_90d + NDVI_pre_365d + s(mean_hydro_dist_m) +
## mean_elevation + soil_order_1 + vs_min_3b_2a + tmmn_mea_60b_2a +
## tmmx_max_3b_2a + pr_mea_10b_2a + s(vpd_min_10b_2a) + spei1y +
## spei14d + ti(NDVI_pre_365d, spei1y)
##
## Parametric coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.394e+00 3.417e+00 1.286 0.19900
## ag_1985 -1.300e+00 1.197e+00 -1.087 0.27773
## wood_cov -8.983e-03 3.336e-03 -2.693 0.00732 **
## nearest_road_m -5.274e-05 1.301e-04 -0.405 0.68534
## NDVI_pre_90d -3.162e-01 2.769e-01 -1.142 0.25398
## NDVI_pre_365d 1.477e-01 6.135e-01 0.241 0.80986
## mean_elevation -1.366e-03 5.292e-04 -2.581 0.01013 *
## soil_order_11 1.631e-01 1.099e-01 1.484 0.13845
## soil_order_14 1.641e-03 1.432e-01 0.011 0.99086
## soil_order_19 -1.418e-01 1.274e-01 -1.113 0.26625
## soil_order_1Other 2.986e-01 1.521e-01 1.963 0.05020 .
## vs_min_3b_2a -9.924e-02 4.750e-02 -2.089 0.03717 *
## tmmn_mea_60b_2a -3.307e-02 1.097e-02 -3.014 0.00271 **
## tmmx_max_3b_2a 1.605e-02 1.181e-02 1.360 0.17456
## pr_mea_10b_2a 2.558e-03 1.331e-02 0.192 0.84768
## spei1y 7.543e-02 3.873e-02 1.948 0.05201 .
## spei14d 4.173e-02 5.215e-02 0.800 0.42402
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Approximate significance of smooth terms:
## edf Ref.df F p-value
## s(road_dens_km_km2) 2.633 3.360 3.206 0.0190 *
## s(mean_hydro_dist_m) 1.890 2.315 1.116 0.3254
## s(vpd_min_10b_2a) 2.651 3.309 3.112 0.0219 *
## ti(NDVI_pre_365d,spei1y) 2.772 3.294 2.145 0.0717 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## R-sq.(adj) = 0.112 Deviance explained = 15.5%
## -REML = 658.14 Scale est. = 0.57157 n = 537
# Model Fit
performance::check_collinearity(mod_pa_best)
## # Check for Multicollinearity
##
## Low Correlation
##
## Term VIF VIF 95% CI adj. VIF Tolerance Tolerance 95% CI
## ag_1985 1.31 [ 1.21, 1.48] 1.15 0.76 [0.68, 0.83]
## wood_cov 2.70 [ 2.38, 3.10] 1.64 0.37 [0.32, 0.42]
## nearest_road_m 1.42 [ 1.30, 1.60] 1.19 0.70 [0.63, 0.77]
## NDVI_pre_90d 1.54 [ 1.40, 1.74] 1.24 0.65 [0.58, 0.72]
## mean_elevation 1.52 [ 1.38, 1.71] 1.23 0.66 [0.58, 0.73]
## soil_order_1 3.03 [ 2.66, 3.48] 1.15 0.33 [0.29, 0.38]
## vs_min_3b_2a 1.22 [ 1.13, 1.38] 1.11 0.82 [0.73, 0.88]
## tmmn_mea_60b_2a 3.20 [ 2.80, 3.68] 1.79 0.31 [0.27, 0.36]
## tmmx_max_3b_2a 2.45 [ 2.17, 2.80] 1.56 0.41 [0.36, 0.46]
## pr_mea_10b_2a 2.00 [ 1.79, 2.28] 1.41 0.50 [0.44, 0.56]
## s(vpd_min_10b_2a) 2.10 [ 1.87, 2.40] 1.45 0.48 [0.42, 0.53]
## spei1y 1.73 [ 1.56, 1.96] 1.32 0.58 [0.51, 0.64]
## spei14d 2.20 [ 1.96, 2.51] 1.48 0.45 [0.40, 0.51]
##
## Moderate Correlation
##
## Term VIF VIF 95% CI adj. VIF Tolerance Tolerance 95% CI
## s(road_dens_km_km2) 9.68 [ 8.32, 11.30] 3.11 0.10 [0.09, 0.12]
##
## High Correlation
##
## Term VIF VIF 95% CI adj. VIF Tolerance Tolerance 95% CI
## NDVI_pre_365d 31.44 [26.82, 36.88] 5.61 0.03 [0.03, 0.04]
## s(mean_hydro_dist_m) 19.83 [16.95, 23.23] 4.45 0.05 [0.04, 0.06]
performance::check_outliers(mod_pa_best)
## OK: No outliers detected.
## - Based on the following method and threshold: cook (1).
## - For variable: (Whole model)
## Plot
plot(mod_pa_best, pages = 4, shade = TRUE, shade.col = "lightblue", all.terms = TRUE)
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in axis(1, at = seq_along(ll), labels = ll, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.xy(xy.coords(x, y), type = type, ...): "shade" is not a
## graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
## Warning in plot.window(...): "shade" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "shade" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "shade" is not a
## graphical parameter
## Warning in box(...): "shade" is not a graphical parameter
## Warning in title(...): "shade" is not a graphical parameter
pa_candidates <- list(
mod_pa_clean = mod_pa_clean,
mod_pa_NDVI_Climate = mod_pa_NDVI_Climate,
mod_pa_LandCov_Elev = mod_pa_LandCov_Elev,
mod_pa_Int = mod_pa_Int
)
cv_pa <- cv_compare(pa_candidates, landscape_data_pa_clean,
K = 10, reps = 5, seed = 1)
cv_pa
## model CV_RMSE RMSE_SD CV_MAE CV_R2 R2_SD
## 1 mod_pa_NDVI_Climate 0.7784013 0.003916184 0.6332445 0.05732665 0.009489843
## 2 mod_pa_clean 0.7802679 0.003579629 0.6362259 0.05280350 0.008689951
## 3 mod_pa_Int 0.7837982 0.002965821 0.6385766 0.04421812 0.007224407
## 4 mod_pa_LandCov_Elev 0.7904865 0.008415075 0.6432290 0.02775978 0.020794498
## delta_RMSE
## 1 0.000000000
## 2 0.001866563
## 3 0.005396868
## 4 0.012085168
write.csv(cv_pa, "patch_area_cv_results.csv", row.names = FALSE)
pa_tables <- backtransform_tables(mod_pa_best)
pa_tables$param
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.394206e+00 3.4167789673 1.28606676 0.199003266
## ag_1985 -1.300224e+00 1.1966041358 -1.08659520 0.277728985
## wood_cov -8.982941e-03 0.0033359428 -2.69277423 0.007319141
## nearest_road_m -5.273982e-05 0.0001300853 -0.40542501 0.685335128
## NDVI_pre_90d -3.162450e-01 0.2769142817 -1.14203206 0.253976529
## NDVI_pre_365d 1.476800e-01 0.6134721547 0.24072815 0.809862554
## mean_elevation -1.365839e-03 0.0005291711 -2.58109108 0.010126993
## soil_order_11 1.630897e-01 0.1099042766 1.48392462 0.138446595
## soil_order_14 1.641478e-03 0.1431732303 0.01146498 0.990856952
## soil_order_19 -1.417560e-01 0.1273673081 -1.11297043 0.266245379
## soil_order_1Other 2.985893e-01 0.1521133339 1.96293978 0.050196203
## vs_min_3b_2a -9.923651e-02 0.0474969275 -2.08932483 0.037173434
## tmmn_mea_60b_2a -3.307292e-02 0.0109731143 -3.01399580 0.002706580
## tmmx_max_3b_2a 1.605444e-02 0.0118082028 1.35960021 0.174557202
## pr_mea_10b_2a 2.558378e-03 0.0133123791 0.19218036 0.847677421
## spei1y 7.543448e-02 0.0387322631 1.94758773 0.052012612
## spei14d 4.172972e-02 0.0521546480 0.80011503 0.424016643
## exp_estimate percent_change
## (Intercept) 80.980 7998.0
## ag_1985 0.272 -72.8
## wood_cov 0.991 -0.9
## nearest_road_m 1.000 0.0
## NDVI_pre_90d 0.729 -27.1
## NDVI_pre_365d 1.159 15.9
## mean_elevation 0.999 -0.1
## soil_order_11 1.177 17.7
## soil_order_14 1.002 0.2
## soil_order_19 0.868 -13.2
## soil_order_1Other 1.348 34.8
## vs_min_3b_2a 0.906 -9.4
## tmmn_mea_60b_2a 0.967 -3.3
## tmmx_max_3b_2a 1.016 1.6
## pr_mea_10b_2a 1.003 0.3
## spei1y 1.078 7.8
## spei14d 1.043 4.3
pa_tables$smooth
## edf Ref.df F p-value p_value
## s(road_dens_km_km2) 2.63 3.359672 3.21 0.01895920 0.0190
## s(mean_hydro_dist_m) 1.89 2.314991 1.12 0.32541785 0.3254
## s(vpd_min_10b_2a) 2.65 3.308568 3.11 0.02194575 0.0219
## ti(NDVI_pre_365d,spei1y) 2.77 3.293882 2.15 0.07173445 0.0717
write.csv(pa_tables$param, "patch_area_backtransformed_param_summary.csv", row.names = TRUE)
write.csv(pa_tables$smooth, "patch_area_smooth_summary.csv", row.names = TRUE)
All six significant terms in the retained patch area model on one figure, sharing a common y-axis so effect magnitudes are directly comparable. Distance to the nearest hydrologic feature is excluded (p = 0.325), as is the NDVI x SPEI interaction (p = 0.072).
pa_sig_vars <- c("tmmn_mea_60b_2a", "vs_min_3b_2a", "vpd_min_10b_2a",
"wood_cov", "mean_elevation", "road_dens_km_km2")
pa_sig_effects <- do.call(rbind, lapply(pa_sig_vars, function(v) {
get_effect(mod_pa_best, landscape_data_pa_clean, v)
}))
x_labels_pa <- c(
"tmmn_mea_60b_2a" = "Mean Minimum Temperature (60-day, K)",
"vs_min_3b_2a" = "Minimum Wind Speed (3-day, m/s)",
"vpd_min_10b_2a" = "Minimum VPD (10-day, kPa)",
"wood_cov" = "Wood Cover (%)",
"mean_elevation" = "Elevation (m)",
"road_dens_km_km2" = "Road Density (km/km\u00b2)"
)
# Shared y-axis across all six panels
y_range_pa <- range(c(pa_sig_effects$lower, pa_sig_effects$upper), na.rm = TRUE)
pa_plots <- lapply(pa_sig_vars, function(var) {
df <- pa_sig_effects %>% filter(variable == var)
ggplot(df, aes(x = x, y = fit)) +
geom_line(linewidth = 1.2, color = "#0072B2") +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.2, fill = "#0072B2") +
coord_cartesian(ylim = y_range_pa) +
theme_classic(base_size = 14) +
theme(
axis.title = element_text(size = 15, face = "bold"),
axis.text = element_text(size = 13),
plot.tag = element_text(size = 18, face = "bold")
) +
labs(x = x_labels_pa[var], y = "Predicted Patch Area (ha)")
})
combined_pa_plot <- pa_plots[[1]] + pa_plots[[2]] + pa_plots[[3]] +
pa_plots[[4]] + pa_plots[[5]] + pa_plots[[6]] +
plot_layout(ncol = 3) +
plot_annotation(tag_levels = "A")
combined_pa_plot
ggsave(file.path(fig_dir, "Patch_Area_Significant_Effects.png"),
combined_pa_plot, width = 15, height = 9, dpi = 300)
Every one-dimensional term in each retained model, on the back-transformed response scale, with all other predictors held at their mean (numeric) or first level (categorical). Shaded bands are ±2 SE. Stars in the panel titles are the term’s significance in the model summary: *** p < 0.001, ** p < 0.01, * p < 0.05, . p < 0.10.
supp_edge <- supplemental_effects(mod_edge_best, landscape_data_clean)
supp_edge_plot <- plot_supplemental(supp_edge,
y_lab = "Predicted Edge Density (m/ha)",
ncol = 4, colour = "#D55E00")
supp_edge_plot
ggsave(file.path(fig_dir, "FigS1_Edge_Density_All_Effects.png"),
supp_edge_plot, width = 16, height = 16, dpi = 300)
## Categorical predictors (soil order)
supp_edge_fac <- supplemental_factor_effects(mod_edge_best, landscape_data_clean)
if (!is.null(supp_edge_fac)) {
supp_edge_fac_plot <- plot_factor_effects(supp_edge_fac,
y_lab = "Predicted Edge Density (m/ha)",
colour = "#D55E00")
print(supp_edge_fac_plot)
ggsave(file.path(fig_dir, "FigS1b_Edge_Density_Factor_Effects.png"),
supp_edge_fac_plot, width = 7, height = 5, dpi = 300)
}
supp_pa <- supplemental_effects(mod_pa_best, landscape_data_pa_clean)
supp_pa_plot <- plot_supplemental(supp_pa,
y_lab = "Predicted Patch Area (ha)",
ncol = 4, colour = "#0072B2")
supp_pa_plot
ggsave(file.path(fig_dir, "FigS2_Patch_Area_All_Effects.png"),
supp_pa_plot, width = 16, height = 16, dpi = 300)
## Categorical predictors (soil order)
supp_pa_fac <- supplemental_factor_effects(mod_pa_best, landscape_data_pa_clean)
if (!is.null(supp_pa_fac)) {
supp_pa_fac_plot <- plot_factor_effects(supp_pa_fac,
y_lab = "Predicted Patch Area (ha)",
colour = "#0072B2")
print(supp_pa_fac_plot)
ggsave(file.path(fig_dir, "FigS2b_Patch_Area_Factor_Effects.png"),
supp_pa_fac_plot, width = 7, height = 5, dpi = 300)
}
A compact numeric summary of each panel — the fitted value at the low and high end of the observed range, and whether the relationship is monotonic — so the direction of every effect can be stated in the text without reading it off the figure by eye.
describe_direction <- function(eff) {
eff %>%
group_by(variable, panel) %>%
arrange(x, .by_group = TRUE) %>%
summarise(
fit_low = round(dplyr::first(fit), 3),
fit_high = round(dplyr::last(fit), 3),
fit_min = round(min(fit), 3),
fit_max = round(max(fit), 3),
x_at_max = round(x[which.max(fit)], 3),
x_at_min = round(x[which.min(fit)], 3),
shape = dplyr::case_when(
which.max(fit) == dplyr::n() & which.min(fit) == 1 ~ "increasing",
which.max(fit) == 1 & which.min(fit) == dplyr::n() ~ "decreasing",
which.max(fit) > 1 & which.max(fit) < dplyr::n() ~ "peak at intermediate",
TRUE ~ "trough at intermediate"
),
.groups = "drop"
)
}
direction_edge <- describe_direction(supp_edge)
direction_pa <- describe_direction(supp_pa)
direction_edge
## # A tibble: 16 × 9
## variable panel fit_low fit_high fit_min fit_max x_at_max x_at_min shape
## <chr> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 NDVI_pre_365d NDVI… 792. 715. 497. 792. 0.227 0.462 trou…
## 2 NDVI_pre_90d NDVI… 525. 495. 495. 525. -0.147 0.712 decr…
## 3 ag_1985 Agri… 483. 1028. 483. 1028. 0.294 0 incr…
## 4 mean_elevation Elev… 879. 1479. 498. 1810. 259. 74.8 peak…
## 5 mean_hydro_di… Dist… 542. 892. 439. 892. 4072. 1316. trou…
## 6 mean_slope Slope 471. 562. 471. 572. 9.59 1.61 peak…
## 7 nearest_road_m Dist… 501. 2056. 501. 2056. 6033. 0 incr…
## 8 pr_max_10b_2a Maxi… 589. 774. 421. 774. 239. 86.9 trou…
## 9 pr_max_3b_2a Maxi… 483. 678. 483. 678. 120. 0 incr…
## 10 pr_mea_60b_2a Mean… 550. 450. 450. 550. 0.325 10.7 decr…
## 11 rmin_mea_60b_… Mean… 491. 519. 491. 519. 55.7 29.2 incr…
## 12 spi1y SPI … 651. 530. 497. 669. -1.41 0.19 peak…
## 13 tmmn_max_3b_2a Max … 449. 540. 449. 540. 298. 267. incr…
## 14 vs_mea_30b_2a Mean… 496. 522. 496. 522. 6.11 2.73 incr…
## 15 vs_mea_3b_2a Mean… 522. 483. 483. 522. 1.95 7.39 decr…
## 16 wood_cov Wood… 304. 591. 304. 591. 97.4 20.1 incr…
direction_pa
## # A tibble: 15 × 9
## variable panel fit_low fit_high fit_min fit_max x_at_max x_at_min shape
## <chr> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 NDVI_pre_365d NDVI… 0.286 0.304 0.286 0.304 0.651 0.227 incr…
## 2 NDVI_pre_90d NDVI… 0.353 0.267 0.267 0.353 -0.147 0.712 decr…
## 3 ag_1985 Agri… 0.296 0.214 0.214 0.296 0 0.294 decr…
## 4 mean_elevation Elev… 0.324 0.191 0.191 0.324 6.55 404. decr…
## 5 mean_hydro_di… Dist… 0.273 0.235 0.235 0.368 1645. 4072. peak…
## 6 nearest_road_m Dist… 0.293 0.291 0.27 0.293 0 3108. trou…
## 7 pr_mea_10b_2a Mean… 0.29 0.313 0.29 0.313 21.3 0 incr…
## 8 road_dens_km_… Road… 0.2 0.207 0.2 0.306 1.87 0 peak…
## 9 spei14d SPEI… 0.268 0.318 0.268 0.318 2.09 -2.09 incr…
## 10 spei1y SPEI… 0.229 0.396 0.229 0.396 2.09 -2.09 incr…
## 11 tmmn_mea_60b_… Mean… 0.435 0.18 0.18 0.435 269. 295. decr…
## 12 tmmx_max_3b_2a Maxi… 0.235 0.353 0.235 0.353 311. 285. incr…
## 13 vpd_min_10b_2a Mini… 0.375 0.439 0.284 0.439 1.18 0.371 trou…
## 14 vs_min_3b_2a Mini… 0.344 0.212 0.212 0.344 0.984 5.97 decr…
## 15 wood_cov Wood… 0.496 0.243 0.243 0.496 20.1 97.4 decr…
write.csv(direction_edge, "edge_density_effect_directions.csv", row.names = FALSE)
write.csv(direction_pa, "patch_area_effect_directions.csv", row.names = FALSE)