Appendix F — Protocol deviation — leave-one-reference-out check: Oke et al. (2020)

F.1 Recorded change

This chapter was not part of the pre-registered protocol. It quantifies the contribution of a single reference to the Hunt_harv (hunting/harvesting) disturbance-context level in model m01: Oke et al. (2020, Nature Communications 11: 4155, with companion dataset Clark 2020, KNB), a long-term monitoring dataset on Pacific salmon (Oncorhynchus spp.) body size.

NoteWhat changed—and what did not

Changed: this chapter documents the number of contrasts, references, species, and study systems that Oke et al. (2020) contributes to the Hunt_harv level, and refits m01 on the same data with every Oke et al. (2020) contrast removed (ref_id != "p209").

Unchanged: the dataset construction pipeline, the moderator definitions, the ref_id and phylogenetic random effects, the priors, and the MCMC settings all match the primary m01 model.

F.2 Identifying Oke et al. (2020) in PROCEED

Oke et al. (2020) contrasts are identified by ref_id == "p209". This matches exactly on DOI and on the database’s reference field.

Code
oke <- dat_es |> dplyr::filter(ref_id == "p209")

tibble::tibble(
  ref_id    = unique(oke$ref_id),
  doi       = unique(oke$doi),
  reference = unique(oke$reference)
) |>
  knitr::kable(caption = "Citation fields recorded for ref_id p209.") |>
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Citation fields recorded for ref_id p209.
ref_id doi reference
p209 10.1038/s41467-020-17726-z; 10.5063/F1707ZTM Oke, K. B., 2020�Nature communications�11: 4155; Clark, J., 2020 KNB

F.3 Contribution to the dataset

Code
oke_counts <- tibble::tibble(
  Field = c(
    "Total Oke et al. (2020) contrasts",
    "Classified `Hunt_harv`",
    "Classified `Other`",
    "Unique species",
    "Unique study systems (`sys_id`)"
  ),
  Value = c(
    nrow(oke),
    sum(oke$disturbance == "Hunt_harv"),
    sum(oke$disturbance == "Other"),
    dplyr::n_distinct(oke$sp_pub),
    dplyr::n_distinct(oke$sys_id)
  )
)
knitr::kable(oke_counts, caption = "Oke et al. (2020) contrasts in the analysis-ready dataset.") |>
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Oke et al. (2020) contrasts in the analysis-ready dataset.
Field Value
Total Oke et al. (2020) contrasts 1284
Classified `Hunt_harv` 811
Classified `Other` 473
Unique species 5
Unique study systems (`sys_id`) 1161
Code
oke |>
  dplyr::count(sp_pub, name = "n_contrasts", sort = TRUE) |>
  knitr::kable(caption = "Species represented among Oke et al. (2020) contrasts.") |>
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Species represented among Oke et al. (2020) contrasts.
sp_pub n_contrasts
Oncorhynchus nerka 407
Oncorhynchus tshawytscha 330
Oncorhynchus keta 311
Oncorhynchus kisutch 214
Oncorhynchus gorbuscha 22
Code
hh_all <- dat_es |> dplyr::filter(disturbance == "Hunt_harv")
hh_oke <- hh_all |> dplyr::filter(ref_id == "p209")

contribution <- tibble::tibble(
  Metric = c("Contrasts", "References", "Species", "Study systems (`sys_id`)"),
  `Hunt_harv total` = c(
    nrow(hh_all),
    dplyr::n_distinct(hh_all$ref_id),
    dplyr::n_distinct(hh_all$sp_pub),
    dplyr::n_distinct(hh_all$sys_id)
  ),
  `From Oke et al. (2020)` = c(
    nrow(hh_oke),
    1L,
    dplyr::n_distinct(hh_oke$sp_pub),
    dplyr::n_distinct(hh_oke$sys_id)
  )
) |>
  dplyr::mutate(`Oke share (%)` = round(100 * `From Oke et al. (2020)` / `Hunt_harv total`, 1))

knitr::kable(contribution, caption = "Oke et al. (2020) contribution to the Hunt_harv disturbance-context level.") |>
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Oke et al. (2020) contribution to the Hunt_harv disturbance-context level.
Metric Hunt_harv total From Oke et al. (2020) Oke share (%)
Contrasts 913 811 88.8
References 19 1 5.3
Species 17 5 29.4
Study systems (`sys_id`) 730 711 97.4
Code
hh_all |>
  dplyr::count(ref_id, reference, name = "n_contrasts", sort = TRUE) |>
  knitr::kable(caption = "All references contributing to the Hunt_harv disturbance-context level, ranked by number of contrasts.") |>
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) |>
  kableExtra::scroll_box(height = "350px")
All references contributing to the Hunt_harv disturbance-context level, ranked by number of contrasts.
ref_id reference n_contrasts
p209 Oke, K. B., 2020�Nature communications�11: 4155; Clark, J., 2020 KNB 811
p092 Olsen 2004, Nature 428: 932-935 24
p163 Wolak et al. (2010), Conservation Biology 24(5): 1268-1277 21
p082 McGraw 2001, Biological Conservation 98: 25-32 10
p188 Skogland 1989, Oikos. 55:101-110 8
p197 Yoneda & Wright 2004, MEPS 276:237-248 8
p205 Pigeon et al. 2016, Evol. App. 9: 521-530 6
p183 Engelhard & Heino 2004 Mar. Ecol. Prog. Series, 272:245-256 5
p206 van de Walle et al. 2020, Biol. Let., 16: 20190707 5
p208 Leclerc 2016, Biol Let 12:20160197 3
p029 Coltman 2003, Nature 426: 655-658 2
p075 Law 2005, PNAS 102: 10218-10220 2
p175 Armstrong 1989, S. African J. Mar. Sci. 8:91-101 2
p019 Carlson 2007, Ecology letters 10 : 512-521 1
p047 Handford 1977, J. Fish. Res. Board Can. 34: 954-961 1
p117 Swain 2007, Proc. R. Soc. B 274 : 1015-1022 1
p138 Azorit 2002. Zeitschrift Fur Jagdwissenschaft 48: 137-144 1
p189 Pigeon 2017, Ecology. 98: 2456-2467 1
p207 Van de Walle et al., 2021 J Anim. Ecol. 1

F.4 Hunting/harvesting contrasts with and without Oke et al. (2020)

Code
hh_without_oke <- hh_all |> dplyr::filter(ref_id != "p209")

summarize_grp <- function(d, label) {
  tibble::tibble(
    Group           = label,
    n_contrasts     = nrow(d),
    n_references    = dplyr::n_distinct(d$ref_id),
    n_species       = dplyr::n_distinct(d$sp_pub),
    n_sys_id        = dplyr::n_distinct(d$sys_id),
    mean_lnM        = round(mean(d$yi_lnM_safe, na.rm = TRUE), 3),
    median_lnM      = round(median(d$yi_lnM_safe, na.rm = TRUE), 3),
    sd_lnM          = round(sd(d$yi_lnM_safe, na.rm = TRUE), 3),
    q2_5_lnM        = round(quantile(d$yi_lnM_safe, 0.025, na.rm = TRUE), 3),
    q97_5_lnM       = round(quantile(d$yi_lnM_safe, 0.975, na.rm = TRUE), 3),
    median_n_total  = round(median(d$n_total, na.rm = TRUE), 1),
    max_n_total     = max(d$n_total, na.rm = TRUE)
  )
}

dplyr::bind_rows(
  summarize_grp(hh_all,          "With Oke et al. (2020)"),
  summarize_grp(hh_without_oke,  "Without Oke et al. (2020)"),
  summarize_grp(hh_oke,          "Oke et al. (2020) only")
) |>
  knitr::kable(caption = "Raw lnM and sample-size summary for the Hunt_harv level, with and without Oke et al. (2020).") |>
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Raw lnM and sample-size summary for the Hunt_harv level, with and without Oke et al. (2020).
Group n_contrasts n_references n_species n_sys_id mean_lnM median_lnM sd_lnM q2_5_lnM q97_5_lnM median_n_total max_n_total
With Oke et al. (2020) 913 19 17 730 -1.127 -1.099 0.955 -2.950 0.676 335.0 77352
Without Oke et al. (2020) 102 18 12 19 -0.378 -0.303 1.318 -3.319 1.785 73.5 77352
Oke et al. (2020) only 811 1 5 711 -1.221 -1.194 0.855 -2.943 0.370 418.0 14296
Code
dplyr::bind_rows(
  hh_all         |> dplyr::mutate(group = "With Oke et al. (2020)"),
  hh_without_oke |> dplyr::mutate(group = "Without Oke et al. (2020)")
) |>
  dplyr::count(group, taxa) |>
  tidyr::pivot_wider(names_from = group, values_from = n, values_fill = 0) |>
  knitr::kable(caption = "Taxonomic composition of the Hunt_harv level, with and without Oke et al. (2020).") |>
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Taxonomic composition of the Hunt_harv level, with and without Oke et al. (2020).
taxa With Oke et al. (2020) Without Oke et al. (2020)
Fish 853 42
Mammal 27 27
Plant 12 12
Reptile 21 21
Code
hh_without_oke |>
  dplyr::count(sp_pub, name = "n_contrasts", sort = TRUE) |>
  knitr::kable(caption = "Species represented in the Hunt_harv level after excluding Oke et al. (2020).") |>
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Species represented in the Hunt_harv level after excluding Oke et al. (2020).
sp_pub n_contrasts
Gadus morhua 33
Malaclemys terrapin 21
Panax quinquefolius 10
Ovis canadensis 9
Ursus arctos 9
Rangifer t. tarandus 8
Clupea harengus 5
Sardinops ocellatus 2
Saussurea laniceps 2
Cervus elaphus hispanicus 1
Coregonus clupeaformis 1
Esox lucius 1

F.5 Model specification

Model m01 (yi_lnM_safe ~ disturbance + (1 | ref_id) + (1 | gr(sp_ncbi, cov = A)) + (1 | gr(es_id_model, cov = V)), sigma ~ disturbance) was refit on the dataset with every Oke et al. (2020) contrast removed. The formula, priors, and MCMC settings are unchanged from the primary m01 fit: 4 chains × 4,000 iterations (2,000 warmup), adapt_delta = 0.97, max_treedepth = 15, cmdstanr backend. The model was fitted on a remote server, not while rendering this book.

Code
dat_model <- dat_es[!is.na(dat_es[["disturbance"]]), ]
dat_model <- dat_model |> dplyr::filter(ref_id != "p209")
dat_model[["disturbance"]] <- droplevels(factor(dat_model[["disturbance"]]))
dat_model <- dat_model |> dplyr::mutate(es_id_model = factor(seq_len(dplyr::n())))

phylo <- prepare_phylo_and_data(dat_model, A_full, label = "m01_leave_oke_out")
dat_model <- phylo$dat_model; A_mod <- phylo$A_mod; V <- phylo$V

formula <- build_ls_formula("disturbance", has_phylogeny = phylo$has_phylo)
priors  <- build_ls_priors(formula, dat_model, V, A = A_mod)

fit <- fit_ls_model(dat_model, formula, priors, V = V, A = A_mod,
                    mcmc_args = default_mcmc_args)

F.6 Convergence diagnostics and model summaries

The leave-Oke-out fit finished on the remote server in 14.62 hours (4 chains × 4,000 iterations each). Diagnostics for both fits, read from the project’s existing diagnostics table (primary m01) and from the leave-Oke-out fit’s own diagnostics file:

Code
dplyr::bind_rows(diag_primary, diag_loo) |>
  dplyr::select(fit, max_rhat, min_bulk_ess, min_tail_ess, n_divergent, max_treedepth_hits) |>
  knitr::kable(digits = 4, caption = "Convergence diagnostics, primary m01 vs. leave-Oke-out refit.") |>
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Convergence diagnostics, primary m01 vs. leave-Oke-out refit.
fit max_rhat min_bulk_ess min_tail_ess n_divergent max_treedepth_hits
With Oke et al. (2020) 1.0054 727.4961 1703.58 0 0
Without Oke et al. (2020) 1.0042 1092.6731 1742.58 0 0

F.6.1 Location — level estimates

Code
dplyr::bind_rows(loc_primary, loc_loo) |>
  dplyr::select(fit, level, emmean, lower.CrI, upper.CrI) |>
  tidyr::pivot_wider(names_from = fit, values_from = c(emmean, lower.CrI, upper.CrI)) |>
  knitr::kable(digits = 3, caption = "Location (mean lnM) estimate per disturbance-context level, primary m01 vs. leave-Oke-out refit.") |>
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Location (mean lnM) estimate per disturbance-context level, primary m01 vs. leave-Oke-out refit.
level emmean_With Oke et al. (2020) emmean_Without Oke et al. (2020) lower.CrI_With Oke et al. (2020) lower.CrI_Without Oke et al. (2020) upper.CrI_With Oke et al. (2020) upper.CrI_Without Oke et al. (2020)
Climate change -0.530 -0.542 -1.338 -1.455 0.319 0.353
Hunt_harv -0.806 -0.221 -1.614 -1.128 -0.036 0.659
Introduction -0.524 -0.526 -1.319 -1.384 0.240 0.331
Landscape change -0.323 -0.298 -1.134 -1.171 0.495 0.578
Other -0.811 -0.867 -1.611 -1.728 -0.040 -0.007
Pollution -0.357 -0.367 -1.214 -1.297 0.503 0.550
Response to introductions -0.430 -0.443 -1.348 -1.400 0.434 0.481

F.6.2 Location — pairwise contrasts

Code
dplyr::bind_rows(locctr_primary, locctr_loo) |>
  dplyr::select(fit, contrast, estimate, lower.CrI, upper.CrI, pd) |>
  tidyr::pivot_wider(names_from = fit, values_from = c(estimate, lower.CrI, upper.CrI, pd)) |>
  knitr::kable(digits = 3, caption = "Location pairwise contrasts (difference in mean lnM), primary m01 vs. leave-Oke-out refit.") |>
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) |>
  kableExtra::scroll_box(width = "100%")
Location pairwise contrasts (difference in mean lnM), primary m01 vs. leave-Oke-out refit.
contrast estimate_With Oke et al. (2020) estimate_Without Oke et al. (2020) lower.CrI_With Oke et al. (2020) lower.CrI_Without Oke et al. (2020) upper.CrI_With Oke et al. (2020) upper.CrI_Without Oke et al. (2020) pd_With Oke et al. (2020) pd_Without Oke et al. (2020)
Climate change - Hunt_harv 0.276 -0.321 -0.079 -0.754 0.630 0.115 0.942 0.929
Climate change - Introduction -0.006 -0.016 -0.399 -0.406 0.384 0.389 0.515 0.537
Climate change - Landscape change -0.207 -0.244 -0.672 -0.702 0.251 0.215 0.812 0.852
Climate change - Other 0.281 0.325 -0.063 -0.010 0.623 0.666 0.946 0.971
Climate change - Pollution -0.173 -0.175 -0.729 -0.758 0.381 0.414 0.732 0.726
Climate change - Response to introductions -0.100 -0.099 -0.692 -0.697 0.503 0.486 0.633 0.628
Hunt_harv - Introduction -0.282 0.305 -0.543 -0.049 -0.026 0.661 0.984 0.957
Hunt_harv - Landscape change -0.483 0.077 -0.830 -0.327 -0.133 0.490 0.998 0.639
Hunt_harv - Other 0.005 0.646 -0.078 0.352 0.087 0.935 0.541 1.000
Hunt_harv - Pollution -0.449 0.146 -0.923 -0.385 0.019 0.685 0.970 0.704
Hunt_harv - Response to introductions -0.376 0.222 -0.885 -0.342 0.130 0.806 0.928 0.780
Introduction - Landscape change -0.201 -0.228 -0.549 -0.573 0.138 0.104 0.880 0.907
Introduction - Other 0.287 0.341 0.038 0.094 0.537 0.591 0.988 0.996
Introduction - Pollution -0.167 -0.159 -0.584 -0.606 0.269 0.304 0.777 0.756
Introduction - Response to introductions -0.094 -0.083 -0.573 -0.567 0.373 0.409 0.649 0.629
Landscape change - Other 0.488 0.569 0.148 0.237 0.826 0.904 0.998 1.000
Landscape change - Pollution 0.035 0.069 -0.470 -0.436 0.537 0.604 0.547 0.604
Landscape change - Response to introductions 0.108 0.145 -0.456 -0.418 0.664 0.711 0.652 0.688
Other - Pollution -0.453 -0.500 -0.927 -0.986 0.008 -0.015 0.972 0.978
Other - Response to introductions -0.380 -0.424 -0.887 -0.937 0.129 0.100 0.933 0.945
Pollution - Response to introductions 0.073 0.076 -0.534 -0.549 0.670 0.695 0.600 0.595

F.6.3 Scale — level estimates

Code
dplyr::bind_rows(scl_primary, scl_loo) |>
  dplyr::select(fit, level, emmean, lower.CrI, upper.CrI, residual_SD) |>
  tidyr::pivot_wider(names_from = fit, values_from = c(emmean, lower.CrI, upper.CrI, residual_SD)) |>
  knitr::kable(digits = 3, caption = "Scale (log-sigma) estimate and implied residual SD per disturbance-context level, primary m01 vs. leave-Oke-out refit.") |>
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) |>
  kableExtra::scroll_box(width = "100%")
Scale (log-sigma) estimate and implied residual SD per disturbance-context level, primary m01 vs. leave-Oke-out refit.
level emmean_With Oke et al. (2020) emmean_Without Oke et al. (2020) lower.CrI_With Oke et al. (2020) lower.CrI_Without Oke et al. (2020) upper.CrI_With Oke et al. (2020) upper.CrI_Without Oke et al. (2020) residual_SD_With Oke et al. (2020) residual_SD_Without Oke et al. (2020)
Climate change -0.692 -0.693 -0.871 -0.865 -0.527 -0.525 0.501 0.500
Introduction -0.677 -0.677 -0.712 -0.714 -0.640 -0.642 0.508 0.508
Response to introductions -0.436 -0.435 -0.583 -0.585 -0.287 -0.287 0.647 0.647
Other -0.554 -0.875 -0.612 -0.975 -0.495 -0.779 0.575 0.417
Landscape change -1.123 -1.127 -1.374 -1.381 -0.899 -0.903 0.325 0.324
Pollution -0.876 -0.874 -1.142 -1.140 -0.639 -0.637 0.416 0.417
Hunt_harv -0.327 -0.494 -0.388 -0.723 -0.267 -0.266 0.721 0.610

F.6.4 Scale — pairwise contrasts

Code
dplyr::bind_rows(sclctr_primary, sclctr_loo) |>
  dplyr::select(fit, contrast, estimate, lower.CrI, upper.CrI, pd) |>
  tidyr::pivot_wider(names_from = fit, values_from = c(estimate, lower.CrI, upper.CrI, pd)) |>
  knitr::kable(digits = 3, caption = "Scale (log-sigma) pairwise contrasts, primary m01 vs. leave-Oke-out refit.") |>
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) |>
  kableExtra::scroll_box(width = "100%")
Scale (log-sigma) pairwise contrasts, primary m01 vs. leave-Oke-out refit.
contrast estimate_With Oke et al. (2020) estimate_Without Oke et al. (2020) lower.CrI_With Oke et al. (2020) lower.CrI_Without Oke et al. (2020) upper.CrI_With Oke et al. (2020) upper.CrI_Without Oke et al. (2020) pd_With Oke et al. (2020) pd_Without Oke et al. (2020)
Climate change - Introduction -0.015 -0.016 -0.199 -0.191 0.155 0.153 0.558 0.566
Climate change - Response to introductions -0.256 -0.257 -0.486 -0.484 -0.028 -0.034 0.988 0.988
Climate change - Other -0.138 0.182 -0.329 -0.009 0.038 0.380 0.937 0.968
Climate change - Landscape change 0.431 0.434 0.142 0.155 0.737 0.739 0.999 0.999
Climate change - Pollution 0.184 0.181 -0.119 -0.113 0.489 0.481 0.877 0.888
Climate change - Hunt_harv -0.365 -0.199 -0.554 -0.481 -0.189 0.082 1.000 0.919
Introduction - Response to introductions -0.241 -0.242 -0.393 -0.394 -0.090 -0.089 1.000 0.999
Introduction - Other -0.123 0.198 -0.191 0.094 -0.053 0.305 1.000 1.000
Introduction - Landscape change 0.447 0.450 0.222 0.219 0.702 0.705 1.000 1.000
Introduction - Pollution 0.199 0.197 -0.040 -0.044 0.471 0.465 0.945 0.943
Introduction - Hunt_harv -0.350 -0.183 -0.421 -0.413 -0.278 0.045 1.000 0.943
Response to introductions - Other 0.118 0.440 -0.038 0.262 0.276 0.617 0.925 1.000
Response to introductions - Landscape change 0.687 0.692 0.419 0.417 0.976 0.989 1.000 1.000
Response to introductions - Pollution 0.440 0.439 0.166 0.157 0.746 0.733 0.999 0.999
Response to introductions - Hunt_harv -0.109 0.058 -0.270 -0.209 0.053 0.335 0.906 0.659
Other - Landscape change 0.570 0.252 0.340 0.009 0.826 0.525 1.000 0.979
Other - Pollution 0.322 -0.001 0.080 -0.262 0.597 0.283 0.995 0.518
Other - Hunt_harv -0.227 -0.381 -0.311 -0.628 -0.142 -0.129 1.000 0.999
Landscape change - Pollution -0.248 -0.253 -0.582 -0.596 0.099 0.099 0.920 0.928
Landscape change - Hunt_harv -0.796 -0.633 -1.054 -0.972 -0.563 -0.310 1.000 1.000
Pollution - Hunt_harv -0.549 -0.380 -0.821 -0.735 -0.307 -0.057 1.000 0.989