13  Elapsed time (log₁₀ generations)

Input Saved prediction and summary files.

Action Read the model record and build its figure.

Output Model table, checks, and plot.

Next Continue to the next model chapter.

13.1 Phylogenetic covariance and model species

This model contains 253 species (7,186 contrasts). The phylogenetic correlation matrix was constructed and aligned to those species as follows; brms uses it in (1 | gr(sp_ncbi, cov = A)).

Code
A_full <- prepR4pcm::pr_phylo_cor(tree_final)
# Fallback if needed: ape::vcv.phylo(tree_final, corr = TRUE)
dat_model <- dat_es |> dplyr::filter(!is.na(log10_generations))
phylo <- prepare_phylo_and_data(dat_model, A_full, fill_unmatched = TRUE)
dat_model <- phylo$dat_model
A <- phylo$A_mod
formula <- brms::bf(
  yi_lnM_safe ~ log10_generations + (1 | ref_id) +
    (1 | gr(sp_ncbi, cov = A)) + (1 | gr(es_id_model, cov = V)),
  sigma ~ log10_generations
)
V <- phylo$V
fit <- brms::brm(formula, data = dat_model,
                 data2 = list(A = A, V = V))

Continuous moderator: divergence as a function of elapsed time in generations (log₁₀).

13.2 Model summary

summary() is read from Rdata/epred_draws/m04.rds; the full brms fit is not loaded at render.

Code
print_cache_summary(cache)
 Family: gaussian 
  Links: mu = identity; sigma = log 
Formula: yi_lnM_safe ~ log10_generations + (1 | ref_id) + (1 | gr(sp_ncbi, cov = A)) + (1 | gr(es_id_model, cov = V)) 
         sigma ~ log10_generations
   Data: structure(list(es_id = c("es0313", "es0314", "es03 (Number of observations: 7186) 
  Draws: 4 chains, each with iter = 4000; warmup = 2000; thin = 1;
         total post-warmup draws = 8000

Multilevel Hyperparameters:
~es_id_model (Number of levels: 7186) 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)     1.00      0.00     1.00     1.00   NA       NA       NA

~ref_id (Number of levels: 254) 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)     0.74      0.04     0.66     0.83 1.00     1533     2796

~sp_ncbi (Number of levels: 253) 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)     0.83      0.17     0.53     1.22 1.01      905     1913

Regression Coefficients:
                        Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
Intercept                  -0.92      0.47    -1.84     0.02 1.00     1764
sigma_Intercept            -0.40      0.03    -0.45    -0.35 1.00     3966
log10_generations           0.29      0.04     0.22     0.36 1.00     3894
sigma_log10_generations    -0.15      0.02    -0.18    -0.12 1.00     3143
                        Tail_ESS
Intercept                   2947
sigma_Intercept             5723
log10_generations           5289
sigma_log10_generations     5258

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).

13.3 Main predictions in equivalent-d units

Predictions at 1, 10, and 100 generations are reported on the \(\ln M\) scale and as \(d_{\mathrm{eq}} \approx \sqrt{2\exp(2\ln M)}\). These are prediction-scale summaries from the cached posterior draws; the regression slope itself is not transformed into an equivalent \(d\).

Code
source(here::here("Scripts", "18_contrasts_cache.R"))
kable_contrasts(
  format_continuous_d_eq(cache, unit = "Generations"),
  caption = "Predicted lnM and equivalent d at selected elapsed generations, with 95% credible intervals."
)
Predicted lnM and equivalent d at selected elapsed generations, with 95% credible intervals.
Generations log10 value Mean lnM lnM lower 95% CrI lnM upper 95% CrI deq deq lower 95% CrI deq upper 95% CrI
1 -0.015 -0.921 -1.786 0.063 0.563 0.237 1.507
10 1.001 -0.630 -1.498 0.386 0.753 0.316 2.081
100 1.985 -0.349 -1.232 0.670 0.998 0.412 2.764

13.4 Orchard-like model figure

The orchard-style figure is read from Rdata/figures/publication/orchard/. The complete editable code used to build this plot is shown below.

Code
knitr::include_graphics(
  here::here("Rdata", "figures", "publication", "orchard", "m04_orchard_combined.png")
)

13.4.1 Editable plotting code

Code
library(here)
library(tidyverse)
library(patchwork)

model_id <- "m04"
moderator <- "log10_generations"
moderator_label <- "Elapsed time (log10 generations)"
col_location <- "#0072B2"
col_location_light <- "#88CCEE"
col_scale <- "#D55E00"
col_scale_light <- "#E69F00"
col_scale_ribbon <- "#F2B27E"

out_dir <- here::here("Rdata", "figures", "publication", "orchard")
out_dir_pdf <- here::here("Figures", "publication", "orchard")
dir.create(out_dir, recursive = TRUE, showWarnings = FALSE)
dir.create(out_dir_pdf, recursive = TRUE, showWarnings = FALSE)

dat_es <- readRDS(here::here("Rdata", "effect_sizes", "proceed_lnm_safe.rds"))
cache <- readRDS(here::here("Rdata", "epred_draws", paste0(model_id, ".rds")))

theme_orchard <- function() {
  ggplot2::theme_classic(base_size = 13) +
    ggplot2::theme(
      axis.text.y        = ggplot2::element_text(size = 11),
      axis.title.x       = ggplot2::element_text(size = 12),
      axis.ticks.y       = ggplot2::element_blank(),
      panel.grid.major.x = ggplot2::element_line(colour = "grey92"),
      legend.position    = "bottom",
      legend.title       = ggplot2::element_text(size = 10),
      plot.title         = ggplot2::element_text(size = 13, face = "bold"),
      plot.caption       = ggplot2::element_text(size = 9, colour = "grey50")
    )
}

save_plot <- function(p, stem, width = 8, height = 6) {
  ggplot2::ggsave(file.path(out_dir_pdf, paste0(stem, ".pdf")), p,
                  width = width, height = height, device = cairo_pdf)
  ggplot2::ggsave(file.path(out_dir, paste0(stem, ".png")), p,
                  width = width, height = height, dpi = 300, type = "cairo")
}

raw <- dat_es[!is.na(dat_es[[moderator]]), ] |>
  dplyr::mutate(precision = 1 / sqrt(vi_lnM_safe))

pred <- cache$loc |>
  dplyr::group_by(.data[[moderator]]) |>
  dplyr::summarise(
    estimate = mean(.epred),
    lowerCL = quantile(.epred, 0.025),
    upperCL = quantile(.epred, 0.975),
    .groups = "drop"
  )

pred_sig <- cache$scl |>
  dplyr::group_by(.data[[moderator]]) |>
  dplyr::summarise(
    estimate = mean(sigma),
    lowerCL = quantile(sigma, 0.025),
    upperCL = quantile(sigma, 0.975),
    .groups = "drop"
  )

raw_pred_loc <- approx(
  pred[[moderator]], pred$estimate,
  xout = raw[[moderator]], rule = 2
)$y

raw_cont_sig <- raw |>
  dplyr::mutate(abs_resid = abs(yi_lnM_safe - raw_pred_loc))

p_loc <- ggplot2::ggplot() +
  ggplot2::geom_hline(yintercept = 0, linetype = "dashed", colour = "grey50") +
  ggplot2::geom_point(
    data = raw,
    ggplot2::aes(x = .data[[moderator]], y = yi_lnM_safe, size = precision),
    alpha = 0.22, shape = 21, fill = col_location_light, colour = col_location
  ) +
  ggplot2::geom_ribbon(
    data = pred,
    ggplot2::aes(x = .data[[moderator]], ymin = lowerCL, ymax = upperCL),
    alpha = 0.35, fill = col_location
  ) +
  ggplot2::geom_line(
    data = pred,
    ggplot2::aes(x = .data[[moderator]], y = estimate),
    linewidth = 1.1, colour = col_location
  ) +
  ggplot2::scale_size_continuous(name = "Precision (1/SE)", range = c(0.3, 4)) +
  ggplot2::labs(
    x = moderator_label,
    y = "lnM",
    title = NULL
  ) +
  theme_orchard()

p_scl <- ggplot2::ggplot() +
  ggplot2::geom_point(
    data = raw_cont_sig,
    ggplot2::aes(x = .data[[moderator]], y = abs_resid, size = precision),
    alpha = 0.20, shape = 21, fill = col_scale_light, colour = col_scale
  ) +
  ggplot2::geom_ribbon(
    data = pred_sig,
    ggplot2::aes(x = .data[[moderator]], ymin = lowerCL, ymax = upperCL),
    alpha = 0.35, fill = col_scale_ribbon
  ) +
  ggplot2::geom_line(
    data = pred_sig,
    ggplot2::aes(x = .data[[moderator]], y = estimate),
    linewidth = 1.1, colour = col_scale
  ) +
  ggplot2::scale_size_continuous(name = "Precision (1/SE)", range = c(0.3, 4)) +
  ggplot2::labs(
    x = moderator_label,
    y = "residual lnM (SD)",
    title = NULL,
    caption = NULL
  ) +
  theme_orchard()

p_comb <- patchwork::wrap_plots(
  p_loc,
  p_scl + ggplot2::guides(size = "none"),
  ncol = 1,
  guides = "collect"
) & ggplot2::theme(legend.position = "bottom")

save_plot(p_loc, paste0(model_id, "_orchard_location"), width = 8, height = 5)
save_plot(p_scl, paste0(model_id, "_orchard_scale"), width = 8, height = 4)
save_plot(p_comb, paste0(model_id, "_orchard_combined"), width = 8, height = 9)
p_comb