df_plot <- df_clean %>% filter(!is.na(Titer) & Titer >= 0)
# ── Pull the Tukey adjusted p-value for each configured comparison ───────────
# TukeyHSD names its rows "B-A"; look the pair up in either orientation so the
# brackets can never disagree with the table printed above.
tukey_p_lookup <- setNames(tukey_m_tbl$p_adj, tukey_m_tbl$comparison)
tukey_p_for <- function(g1, g2) {
for (key in c(paste0(g1, "-", g2), paste0(g2, "-", g1))) {
if (key %in% names(tukey_p_lookup)) return(unname(tukey_p_lookup[[key]]))
}
NA_real_
}
p_signif_label <- function(p) {
dplyr::case_when(
is.na(p) ~ NA_character_,
p <= 1e-4 ~ "****",
p <= 1e-3 ~ "***",
p <= 1e-2 ~ "**",
p <= 0.05 ~ "*",
TRUE ~ "ns"
)
}
# Bracket heights are given on the raw (untransformed) titer scale because
# scale_y_log10() transforms them along with the data.
y_top <- max(df_plot$Titer_pseudo, na.rm = TRUE)
sig_tbl <- do.call(rbind, lapply(COMPARISONS, function(cmp) {
data.frame(
group1 = cmp[1],
group2 = cmp[2],
p_adj = tukey_p_for(cmp[1], cmp[2]),
stringsAsFactors = FALSE
)
}))
sig_tbl$label <- p_signif_label(sig_tbl$p_adj)
sig_tbl <- sig_tbl[!is.na(sig_tbl$p_adj) & sig_tbl$p_adj < ALPHA, , drop = FALSE]
if (nrow(sig_tbl) > 0) {
sig_tbl$y.position <- y_top * 3 * (2.6 ^ (seq_len(nrow(sig_tbl)) - 1))
}
p_combined <- ggplot(df_plot, aes(x = MergedGroup, y = Titer_pseudo, fill = MergedGroup)) +
geom_violin(trim = FALSE, alpha = 0.45, color = "black", bw = VIOLIN_BW) +
geom_jitter(width = 0.18, size = 1, alpha = 0.60) +
scale_fill_manual(values = PALETTE_MERGED, guide = "none") +
scale_y_log10(labels = scales::label_scientific()) +
expand_limits(y = y_top * if (nrow(sig_tbl) > 0) 3 * 2.6 ^ nrow(sig_tbl) else 5) +
labs(
x = "Group",
y = paste0("Viral Titer + ", PSEUDOCOUNT, " (pfu/mL, log scale)"),
title = "Viral Titers by Combined Group",
caption = paste0("Brackets show Tukey HSD adjusted p-values (alpha = ",
ALPHA, "); non-significant comparisons are not drawn.")
) +
theme_bw(base_size = 13) +
theme(
axis.text.x = element_text(angle = 30, hjust = 1),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank()
)
if (nrow(sig_tbl) > 0) {
p_combined <- p_combined +
ggpubr::stat_pvalue_manual(
sig_tbl,
label = "label",
size = 5,
bracket.size = 0.6
)
}
ggsave(file.path(OUTPUT_DIR, "Viral_Titer_CombinedGroups_sig.tiff"), plot = p_combined,
width = FIG_WIDTH, height = FIG_HEIGHT + 0.5, units = "in", dpi = FIG_DPI,
compression = "lzw")
print(p_combined)