The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
This vignette mirrors Manuscript Figure 5 of the
bayesTLS supplement – a single multi-taxon panel of the
thermal-sensitivity parameter z and the critical
temperature CTmax across the three redistributable case
studies – but draws the freqTLS Confidence
Eye for each estimate instead of a Bayesian posterior ridge.
Each row is a likelihood confidence interval (a pale
lens with a hollow point estimate), never a posterior density.
This vignette builds without Stan. Its
freqTLS maximum-likelihood fits and intervals are read from
a version-stamped maintainer cache generated by the package’s documented
fitting code. The individual case-study articles and test suite run the
same fit/profile paths live. The Bayesian multi-taxon ridge plot is the
bayesTLS complement; see the closing note.
The three shared case-study datasets span three corners of thermal physiology:
zebrafish_lethal life-stage
dataset — a separate experiment from the oxygen-gradient
zebrafish_o2 data in
vignette("case-study-zebrafish");The cross-study question is descriptive: laid side by side, how do
thermal limits compare across a crustacean, a fish (resolved by
developmental stage), and an insect (resolved by sex)?
CTmax (the critical temperature at a fixed reference
exposure) places each taxon on the temperature axis; z (the
change in temperature, in degrees Celsius, that multiplies tolerated
exposure time tenfold) measures how sharply tolerated exposure responds
to temperature: a smaller z is a steeper response
(a small warming sharply cuts tolerated time), a larger
z a more gradual one.
One caveat governs the whole panel. The reference exposures differ by study, because each follows the convention of its source assay:
| Taxon | Endpoint | Reference exposure (tref) |
Threshold |
|---|---|---|---|
| Shrimp | lethal | 1 hour | relative midpoint |
| Zebrafish (per stage) | lethal | 1 hour | relative midpoint |
| D. suzukii (per sex) | lethal | 4 hours (240 min) | relative midpoint |
Because a CTmax is defined at its reference
exposure, the four CTmax values are not on
a single common time scale: the fly number is the fitted relative
midpoint temperature at 4 hours, whereas the shrimp and zebrafish fits
use a 1-hour reference. The panel is therefore an illustrative
cross-taxon synthesis, not a single common-scale comparison.
z, by contrast, is a slope – degrees per tenfold change in
time – and is comparable across taxa regardless of the reference
exposure. Read the CTmax facet as four study-specific
anchors and the z facet as a like-with-like comparison of
duration sensitivity.
Each fit uses the configuration locked for its case study. The
grouped fits (zebrafish, fly) estimate a separate CTmax and
z per level with a shared shape (low,
up, k); the ungrouped shrimp fit estimates one
of each. All three use beta-binomial survival counts.
The cache records the package/source version, R and TMB versions, input
checksums, and the exact family, grouping, reference exposure,
threshold, shape, and interval configuration. The build script is
data-raw/build_case_study_summary_cache.R; the per-study
vignettes and tests exercise the live paths and their data-adequacy
warnings.
The vinegar-fly data ships per-individual (dsuzukii); we
aggregate it to (temp, time, sex) counts in base R, exactly
as the per-study vignette does.
summary_cache_path <- system.file(
"extdata", "case_study_summary_cache.rds", package = "freqTLS"
)
if (!nzchar(summary_cache_path) || !file.exists(summary_cache_path)) {
stop("The shipped cross-case-study cache is missing; reinstall freqTLS from a complete source tarball.")
}
summary_cache <- readRDS(summary_cache_path)
summary_cache$meta[c("schema_version", "generated_on", "freqTLS_version",
"freqTLS_source_commit", "R_version", "TMB_version")]
#> $schema_version
#> [1] 1
#>
#> $generated_on
#> [1] "2026-07-12"
#>
#> $freqTLS_version
#> [1] "0.1.0"
#>
#> $freqTLS_source_commit
#> [1] "589e3af6c7c226c571ddcbf682f86a578f77ad9c"
#>
#> $R_version
#> [1] "R version 4.6.0 (2026-04-24)"
#>
#> $TMB_version
#> [1] "1.9.21"The panel is built from one combined data frame of
(label, parameter, estimate, conf.low, conf.high), obtained
by calling confint(..., method = "profile") on each fit.
For the grouped fits we ask for the per-level parameter names
(CTmax:young_embryos, z:M, and so on); for the
ungrouped fits we ask for the bare CTmax and
z. Every interval here is a profile-likelihood confidence
interval, and – as the conf.status column confirms – every
profile closes.
panel <- summary_cache$panel
# Six rows, two parameters: a tidy printout of the headline numbers.
panel_wide <- data.frame(
Group = panel$label[panel$parameter == "CTmax"],
`CTmax estimate` = round(panel$estimate[panel$parameter == "CTmax"], 2),
`CTmax 95% CI` = sprintf("[%.2f, %.2f]",
panel$conf.low[panel$parameter == "CTmax"],
panel$conf.high[panel$parameter == "CTmax"]),
`z estimate` = round(panel$estimate[panel$parameter == "z"], 2),
`z 95% CI` = sprintf("[%.2f, %.2f]",
panel$conf.low[panel$parameter == "z"],
panel$conf.high[panel$parameter == "z"]),
check.names = FALSE
)
knitr::kable(
panel_wide,
caption = "Six taxon/group rows: CTmax (at the study reference exposure) and z, each with its profile-likelihood 95% confidence interval."
)| Group | CTmax estimate | CTmax 95% CI | z estimate | z 95% CI |
|---|---|---|---|---|
| Shrimp | 31.77 | [31.63, 31.92] | 2.19 | [1.96, 2.46] |
| Zebrafish: young embryos | 39.92 | [39.79, 40.04] | 2.00 | [1.82, 2.19] |
| Zebrafish: old embryos | 41.38 | [41.23, 41.61] | 1.80 | [1.53, 2.16] |
| Zebrafish: larvae | 39.79 | [39.67, 39.92] | 1.98 | [1.76, 2.22] |
| D. suzukii: female | 35.23 | [35.12, 35.32] | 3.01 | [2.86, 3.18] |
| D. suzukii: male | 35.25 | [35.16, 35.34] | 3.18 | [3.01, 3.36] |
The same headline numbers are shown beside the classical two-stage
estimator and the bayesTLS posterior, read from the
maintainer-built benchmark cache. The freqTLS and
bayesTLS fits use the matched relative-midpoint,
constant-shape configuration and the same per-study reference exposure.
The classical estimator uses absolute LT50 and is therefore an
approximate comparator for these lethal datasets, whose asymptotes lie
near zero and one.
| Group | Quantity | Two-stage (delta CI) | bayesTLS (95% CrI) | freqTLS (profile CI) |
|---|---|---|---|---|
| Shrimp | CTmax (°C) | 31.62 [31.34, 31.89] | 31.72 [31.60, 31.85] | 31.77 [31.63, 31.92] |
| Shrimp | z (°C / decade) | 2.04 [1.49, 2.60] | 2.17 [1.95, 2.43] | 2.19 [1.96, 2.46] |
| Zebrafish: young embryos | CTmax (°C) | 39.61 [39.34, 39.87] | 39.97 [39.82, 40.10] | 39.92 [39.79, 40.04] |
| Zebrafish: young embryos | z (°C / decade) | 2.22 [1.72, 2.71] | 1.93 [1.73, 2.13] | 2.00 [1.82, 2.19] |
| Zebrafish: old embryos | CTmax (°C) | 41.39 [40.88, 41.91] | 41.34 [41.19, 41.56] | 41.38 [41.23, 41.61] |
| Zebrafish: old embryos | z (°C / decade) | 2.33 [1.69, 2.96] | 1.90 [1.62, 2.24] | 1.80 [1.53, 2.16] |
| Zebrafish: larvae | CTmax (°C) | 39.82 [39.61, 40.02] | 39.73 [39.59, 39.85] | 39.79 [39.67, 39.92] |
| Zebrafish: larvae | z (°C / decade) | 2.16 [1.75, 2.57] | 2.02 [1.78, 2.26] | 1.98 [1.76, 2.22] |
| D. suzukii: female | CTmax (°C) | 34.80 [34.56, 35.04] | 35.20 [35.08, 35.30] | 35.23 [35.12, 35.32] |
| D. suzukii: female | z (°C / decade) | 2.99 [2.60, 3.38] | 3.02 [2.88, 3.18] | 3.01 [2.86, 3.18] |
| D. suzukii: male | CTmax (°C) | 34.98 [34.34, 35.62] | 35.22 [35.10, 35.32] | 35.25 [35.16, 35.34] |
| D. suzukii: male | z (°C / decade) | 3.40 [2.15, 4.65] | 3.18 [2.98, 3.39] | 3.18 [3.01, 3.36] |
Each row is drawn as an honest Confidence Eye – a pale, shallow
horizontal lens whose width is exactly the 95% confidence interval and
whose cosine taper is tallest at the estimate, with a hollow point
marking the estimate itself. The two facets carry independent x-axes
(CTmax in degrees Celsius; z in degrees
Celsius per tenfold change in exposure time), because the two parameters
live on different scales and, for CTmax, on different
reference exposures.
The geometry follows the freqTLS Confidence-Eye
contract: the shallow, wide lens reads as a confidence
interval, not a probability density, and a profile that did not
close would render as a hollow point with no lens. All
12 headline profiles here close (six groups for each of two parameters),
so every row carries a lens.
# Build the honest Confidence-Eye geometry by hand so all three fits share one
# cross-taxon panel: a cosine-tapered pale lens (width = confidence interval)
# plus a hollow point, faceted by parameter with free x-axes. This reuses the
# package lens shape (see ?plot_confidence_eye) but spans every fit in one figure.
stopifnot(requireNamespace("ggplot2", quietly = TRUE))
# Fixed top-to-bottom row order (shrimp, zebrafish stages, fly sexes).
row_order <- c(
"Shrimp",
"Zebrafish: young embryos", "Zebrafish: old embryos", "Zebrafish: larvae",
"D. suzukii: female", "D. suzukii: male"
)
panel$row <- match(panel$label, row_order)
panel$parameter <- factor(panel$parameter, levels = c("CTmax", "z"),
labels = c("CTmax (°C)", "z (°C / decade)"))
# One cosine-tapered lens polygon per row (tallest at the estimate, zero at each
# bound), built per facet so the free x-axes do not distort the taper.
lens_df <- do.call(rbind, lapply(seq_len(nrow(panel)), function(i) {
x <- seq(panel$conf.low[i], panel$conf.high[i], length.out = 80)
d_lo <- max(panel$estimate[i] - panel$conf.low[i], .Machine$double.eps)
d_hi <- max(panel$conf.high[i] - panel$estimate[i], .Machine$double.eps)
frac <- ifelse(x <= panel$estimate[i], (panel$estimate[i] - x) / d_lo,
(x - panel$estimate[i]) / d_hi)
w <- 0.32 * cos((pi / 2) * pmin(pmax(frac, 0), 1))
data.frame(id = i, parameter = panel$parameter[i], x = x,
ymin = panel$row[i] - w, ymax = panel$row[i] + w)
}))
# Reference-exposure annotation for the CTmax facet only.
tref_lab <- data.frame(
parameter = factor("CTmax (°C)",
levels = levels(panel$parameter)),
row = panel$row[panel$parameter == "CTmax (°C)"],
x = panel$conf.high[panel$parameter == "CTmax (°C)"],
lab = c("1 h", "1 h", "1 h", "1 h", "4 h", "4 h")
)
ggplot2::ggplot() +
ggplot2::geom_ribbon(
data = lens_df,
ggplot2::aes(x = x, ymin = ymin, ymax = ymax, group = id),
fill = "#1b7837", colour = NA, alpha = 0.30
) +
ggplot2::geom_point(
data = panel,
ggplot2::aes(x = estimate, y = row),
shape = 21, fill = "white", colour = "#1b7837", size = 3, stroke = 1
) +
ggplot2::geom_text(
data = tref_lab,
ggplot2::aes(x = x, y = row, label = lab),
hjust = -0.25, size = 2.7, colour = "grey35"
) +
ggplot2::scale_y_continuous(
breaks = seq_along(row_order), labels = row_order,
trans = "reverse", expand = ggplot2::expansion(add = 0.7)
) +
ggplot2::scale_x_continuous(
expand = ggplot2::expansion(mult = c(0.05, 0.20))
) +
ggplot2::facet_wrap(~ parameter, scales = "free_x") +
ggplot2::labs(
x = NULL, y = NULL,
title = "Thermal limits across three taxa: CTmax and z",
subtitle = "Confidence Eyes: pale lens = 95% confidence interval; hollow point = estimate.",
caption = paste(
"Profile-likelihood confidence intervals (freqTLS, no Stan).",
"CTmax reference exposure differs by study (annotated): not a common time scale."
)
) +
ggplot2::theme_minimal() +
ggplot2::theme(
panel.grid.major.y = ggplot2::element_blank(),
panel.grid.minor = ggplot2::element_blank(),
plot.caption = ggplot2::element_text(hjust = 0)
)The two grouped studies invite a within-taxon comparison: do the
zebrafish life stages differ, and do the fly sexes differ?
freqTLS requests a profile interval on the
difference (dCTmax:A-B, dz:A-B) and
uses its documented bootstrap fallback when a contrast profile does not
close. Both are prior-free frequentist counterparts to the
bayesTLS pMCMC bracket. A difference interval that excludes
zero is a clear separation; one that spans zero is not.
contrast_tbl <- summary_cache$contrasts
knitr::kable(
data.frame(
Contrast = contrast_tbl$parameter,
Difference = round(contrast_tbl$estimate, 3),
`95% CI` = sprintf("[%.3f, %.3f]",
contrast_tbl$conf.low, contrast_tbl$conf.high),
`Excludes 0` = ifelse(
contrast_tbl$conf.low > 0 | contrast_tbl$conf.high < 0, "yes", "no"
),
Method = contrast_tbl$method,
check.names = FALSE
),
caption = "Within-taxon contrasts: 95% confidence intervals from the requested profile or its documented bootstrap fallback."
)| Contrast | Difference | 95% CI | Excludes 0 | Method |
|---|---|---|---|---|
| dCTmax:old_embryos-young_embryos | 1.459 | [1.287, 1.653] | yes | bootstrap |
| dCTmax:larvae-young_embryos | -0.128 | [-0.281, 0.017] | no | bootstrap |
| dCTmax:larvae-old_embryos | -1.587 | [-1.808, -1.399] | yes | bootstrap |
| dz:old_embryos-young_embryos | -0.106 | [-0.285, 0.063] | no | bootstrap |
| dz:larvae-young_embryos | -0.008 | [-1.564, 1.598] | no | profile |
| dz:larvae-old_embryos | 0.098 | [-0.086, 0.283] | no | bootstrap |
| dCTmax:M-F | 0.024 | [-0.092, 0.154] | no | bootstrap |
| dz:M-F | 0.054 | [-0.026, 0.133] | no | bootstrap |
For zebrafish, the one clear separation in CTmax is
old embryos versus young embryos and larvae
versus old embryos: old embryos sit about 1.46 degrees Celsius
above young embryos, with a confidence interval well clear of zero,
while larvae are essentially indistinguishable from young embryos in
CTmax. None of the z contrasts excludes zero,
so the three stages share a common duration sensitivity even where their
critical temperatures differ. For D. suzukii, both the
CTmax and the z sex contrasts span zero: there
is no clear sex difference in either thermal limit, the same conclusion
Ørsted et al. (2024) reached for these data.
Two things stand out from the panel:
Resolving a taxon by an internal axis can matter or
not. Zebrafish life stage shifts CTmax by over a
degree (old embryos are the most heat-tolerant stage), whereas D.
suzukii sex shifts neither CTmax nor z
detectably. The Confidence Eyes make this visible at a glance: the
zebrafish lenses separate on the CTmax axis, while the two
fly lenses overlap almost completely.
Every estimate carries an honest, prior-free interval. All 12 headline profiles close (six groups for each of two parameters), so each row is a closed lens rather than a hollow point. Where a profile did not close (a weakly identified design or a boundary asymptote), the same display would show a hollow point with no lens – never a fabricated closed eye.
These are confidence intervals throughout: they summarise the likelihood’s support for each parameter and make no probability statement about the parameter itself.
This panel is the freqTLS (likelihood) counterpart to
Manuscript Figure 5 of the bayesTLS supplement. Its full
figure also includes the snow-gum PSII dataset, which is not
redistributed here because its source is CC BY-NC 4.0. The Bayesian
supplement draws the taxa as posterior ridge densities
with median points and 95% credible bars. The two displays answer the
same cross-study question from complementary inferential engines: the
bayesTLS ridge is a posterior density shaped by priors and
the data, whereas the freqTLS Confidence Eye is a
prior-free likelihood interval that cannot be read as a posterior. For
the Bayesian multi-taxon ridge plot, the within-taxon pMCMC contrasts,
and the full posterior workflow, see bayesTLS (https://github.com/daniel1noble/bayesTLS); for the
side-by-side posterior-versus-Confidence-Eye contrast on a single
dataset, see vignette("comparing-to-bayesTLS").
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.