Skip to contents

This vignette analyses European anchovy (Engraulis encrasicolus) in the Mediterranean Sea using Bio-ORACLE v3 surface layers, OBIS occurrences, and a continuous presence-background SDM. climniche treats above-threshold suitability values as reference weights.

library(climniche)

case_path <- system.file("extdata/mediterranean_anchovy", package = "climniche")

# Prepared tables stored with the package.
metric_summary <- read.csv(
  file.path(case_path, "anchovy_climniche_metric_summary.csv")
)
variable_contributions <- read.csv(
  file.path(case_path, "anchovy_climniche_variable_contributions.csv")
)
layer_manifest <- read.csv(
  file.path(case_path, "anchovy_biooracle_layer_manifest.csv")
)
sdm_settings <- read.csv(
  file.path(case_path, "anchovy_presence_background_sdm_settings.csv")
)
fit_settings <- read.csv(
  file.path(case_path, "anchovy_climniche_fit_settings.csv")
)
predictor_screen <- read.csv(
  file.path(case_path, "anchovy_predictor_correlation_vif_screen.csv")
)

Prepared inputs

The environmental data are Bio-ORACLE v3 surface layers. Baseline time layers were averaged for current conditions; future rasters use the same variables under SSP2-4.5 at the 2050 time coordinate.

# Use readable scenario labels in the printed table.
layer_table <- layer_manifest
layer_table[["future_scenario"]] <- "SSP2-4.5"

unique(layer_table[, c(
  "depth", "current_time", "future_scenario", "future_time"
)])
#>                 depth                                current_time
#> 1 surface (depthsurf) Bio-ORACLE v3 baseline time layers averaged
#>   future_scenario          future_time
#> 1        SSP2-4.5 2050-01-01T00:00:00Z

subset(layer_table, retained_for_climniche, c(
  "label", "depth", "current_time", "future_scenario", "future_time"
))
#>                 label               depth
#> 1    Mean temperature surface (depthsurf)
#> 2   Temperature range surface (depthsurf)
#> 4      Salinity range surface (depthsurf)
#> 6             Mean pH surface (depthsurf)
#> 7    Mean chlorophyll surface (depthsurf)
#> 8  Mean current speed surface (depthsurf)
#> 9 Current speed range surface (depthsurf)
#>                                  current_time future_scenario
#> 1 Bio-ORACLE v3 baseline time layers averaged        SSP2-4.5
#> 2 Bio-ORACLE v3 baseline time layers averaged        SSP2-4.5
#> 4 Bio-ORACLE v3 baseline time layers averaged        SSP2-4.5
#> 6 Bio-ORACLE v3 baseline time layers averaged        SSP2-4.5
#> 7 Bio-ORACLE v3 baseline time layers averaged        SSP2-4.5
#> 8 Bio-ORACLE v3 baseline time layers averaged        SSP2-4.5
#> 9 Bio-ORACLE v3 baseline time layers averaged        SSP2-4.5
#>            future_time
#> 1 2050-01-01T00:00:00Z
#> 2 2050-01-01T00:00:00Z
#> 4 2050-01-01T00:00:00Z
#> 6 2050-01-01T00:00:00Z
#> 7 2050-01-01T00:00:00Z
#> 8 2050-01-01T00:00:00Z
#> 9 2050-01-01T00:00:00Z

The current reference layer is a continuous suitability raster from a presence-background SDM. Background cells are sampled Mediterranean cells outside occurrence cells; they are not confirmed absences. The maximum TSS threshold removes low suitability cells from the reference set. Suitability values above the threshold remain continuous weights.

subset(
  sdm_settings,
  setting == "presence_cell_count" |
    setting == "background_cell_count" |
    setting == "background_to_presence_ratio" |
    setting == "sdm_test_auc" |
    setting == "sdm_test_tss" |
    setting == "sdm_threshold"
)
#>                         setting  value
#> 5           presence_cell_count    462
#> 7         background_cell_count    462
#> 8  background_to_presence_ratio   1.00
#> 17                sdm_threshold 0.6165
#> 18                 sdm_test_auc  0.859
#> 19                 sdm_test_tss  0.572

Predictor screening was completed before the climniche fit. The retained variables are:

climniche_predictors <- subset(
  predictor_screen,
  role == "climniche exposure calculation" & retained
)

subset(climniche_predictors, retained, c("label", "vif_after_screening"))
#>                  label vif_after_screening
#> 10    Mean temperature            1.440695
#> 11   Temperature range            1.514125
#> 13      Salinity range            1.445024
#> 15             Mean pH            2.102541
#> 16    Mean chlorophyll            1.587461
#> 17  Mean current speed            1.793713
#> 18 Current speed range            1.744511

Reproducing the climniche step

This example uses fit_climniche_terra() because the prepared Bio-ORACLE layers are terra rasters. The current and future layers must be aligned, and the suitability map is passed to occupied as a continuous reference layer. occupied_threshold removes low suitability cells without converting the remaining values to one.

# Use the maximum TSS threshold to remove low suitability cells.
threshold_row <- subset(sdm_settings, setting == "sdm_threshold")
sdm_threshold <- as.numeric(threshold_row[["value"]])

# Keep the Bio-ORACLE variables retained after predictor screening.
climniche_predictors <- subset(
  predictor_screen,
  role == "climniche exposure calculation" & retained
)
selected_predictors <- climniche_predictors[["variable"]]
predictor_labels <- setNames(
  climniche_predictors[["label"]],
  selected_predictors
)

# The suitability raster supplies continuous reference weights.
fit <- fit_climniche_terra(
  current = current_layers[[selected_predictors]],
  future = future_layers[[selected_predictors]],
  occupied = anchovy_suitability,
  occupied_threshold = sdm_threshold,
  domain = mediterranean_sea_mask,
  sensitivity = predictor_sensitivity
)

climniche_summary(fit)

Niche-relative decomposition

The fit returns four quantities. Climatic Displacement is the distance from current to future conditions in the fitted sensitivity weighted climatic space. Niche Distance Shift is the signed change in distance from the current realised niche centre. Climatic Reconfiguration is the remaining non-radial component, calculated from the identity \(D_i^2 = R_i^2 + C_i^2\). Niche Boundary Exceedance is the positive excess beyond the chosen weighted quantile of current reference-cell distances from the realised niche centre.

subset(
  fit_settings,
  setting == "boundary_quantile" |
    setting == "tolerance" |
    setting == "boundary_exceedance_tolerance"
)
#>                          setting             value
#> 19             boundary_quantile              0.95
#> 20                     tolerance 0.886937582984278
#> 22 boundary_exceedance_tolerance                 0

metric_summary[, c(
  "n", "reference_weight_sum", "boundary_quantile",
  "mean_climate_change_amount", "mean_niche_distance_change",
  "prop_outside_niche", "mean_niche_boundary_exceedance"
)]
#>       n reference_weight_sum boundary_quantile mean_climate_change_amount
#> 1 10374             7265.403              0.95                   4.282655
#>   mean_niche_distance_change prop_outside_niche mean_niche_boundary_exceedance
#> 1                   2.725927          0.0880985                      0.1676494

Variable contributions summarize fitted change; they should not be interpreted causally.

variable_contributions
#>                variable mean_contribution abs_mean_contribution
#> 1               ph_mean        14.7283258            14.7283258
#> 2     temperature_range         2.2908469             2.2908469
#> 3        salinity_range         1.1141710             1.1141710
#> 4      temperature_mean         0.5162404             0.5162404
#> 5 sea_water_speed_range         0.4613986             0.4613986
#>                          interpretation
#> 1 positive fitted variable contribution
#> 2 positive fitted variable contribution
#> 3 positive fitted variable contribution
#> 4 positive fitted variable contribution
#> 5 positive fitted variable contribution

Mediterranean maps

The map figure shows the four continuous reported quantities within current suitable habitat.

metric_maps <- plot_climniche_maps(
  fit,
  occupied = anchovy_suitability,
  occupied_only = TRUE,
  occupied_threshold = sdm_threshold,
  study_region = mediterranean_boundary,
  degree_labels = "hemisphere",
  legend_title = NULL,
  legend_position = "bottom"
)

metric_maps

Summary figure

The summary figure uses one weighted plane for Climatic Displacement and Niche Distance Shift and a second for Climatic Reconfiguration and Niche Boundary Exceedance. It also shows model-derived variable contribution shares and weighted distributions of the four reported quantities.

summary_figure <- plot_climniche_summary_figure(
  fit,
  scope = "current",
  top_variables = 6,
  variable_labels = predictor_labels,
  title = NULL
)

summary_figure