Use animal() when individuals have known additive
relatedness and the scientific question is about among-individual
location deviations after the fixed effects have been included. The
fitted first slices are Gaussian location models. They are useful for
animal-model and quantitative-genetic workflows, but they are not yet
full parity with every phylo() route. This page assumes a
pedigree or additive-relatedness matrix is already the right description
of your data; the structural-dependence overview is
where that choice gets made.
What is fitted today
| Question | Syntax | Status |
|---|---|---|
| Does one Gaussian response have additive individual deviations? |
animal(1 | individual, pedigree = pedigree),
animal(1 | individual, A = A), or
animal(1 | individual, Ainv = Ainv) in mu
|
Fitted first slice. Dense pedigree construction, covariance input, and precision input are supported. |
| Does one numeric fixed-effect slope also have additive individual deviations? |
animal(1 + x | individual, pedigree = pedigree) in
mu
|
Fitted first univariate one-slope slice with independent intercept and slope fields. Additional structured-slope layouts outside the exact fitted bivariate ledger cells and intercept-slope correlations remain planned. |
| Does a one-response Gaussian model have additive residual-scale deviations? |
animal(1 | individual, Ainv = Ainv) in
sigma, alone or matching the mu term;
animal(1 + x | individual, A = A) for the exact one-slope
route |
The residual-scale intercept is fitted. The exact A-matrix q1
sigma one-slope route is fitted and inference-ready with
caveats under raw uncorrected log-SD Wald-z intervals; profile is
diagnostic-only at g = 8. Matching univariate
mu and sigma animal intercepts estimate one
animal mean-scale correlation. Pedigree/Ainv bridge marshalling,
additional multiple or labelled sigma-slope layouts outside the exact
fitted bivariate ledger cells, and structured slope correlations remain
planned. |
| Do two Gaussian response means share an animal-model correlation? | matching labelled
animal(1 | p | individual, pedigree = pedigree),
animal(1 | p | individual, A = A), or
animal(1 | p | individual, Ainv = Ainv) terms in
mu1 and mu2
|
Fitted first q=2 location-location slice.
corpairs(level = "animal") reports the latent animal
correlation separately from residual rho12. |
| Do animal-model deviations link means and residual scales across two responses? | the same labelled
animal(1 | p | individual, Ainv = Ainv) term in
mu1, mu2, sigma1, and
sigma2
|
Fitted first q=4 location-scale slice.
corpairs(level = "animal") reports six constant latent
animal correlations; profile intervals for those derived correlations
remain unavailable. |
| Does the animal effect change multiple slopes or a predictor-dependent correlation? | examples such as
animal(1 + x + z | individual, pedigree = pedigree) or
animal corpair() formulas |
Planned. These routes need separate diagnostics, recovery tests, interval targets, and examples before use. |
The pedigree route expects a data frame whose
identifiers match the grouping variable used in the formula. The
A route uses a precomputed additive relationship covariance
matrix, and the Ainv route uses the corresponding precision
matrix. Use exactly one of pedigree, A, or
Ainv for a fitted animal term.
Start with the smallest useful model
For one response, start with the fitted location-intercept route:
fit_animal <- drmTMB(
y ~ treatment + animal(1 | individual, pedigree = pedigree),
data = dat,
family = gaussian()
)For the exact Arc 1a REML route, keep sigma ~ 1, use an
unlabelled intercept or independent intercept-plus-one-numeric-slope
shape, and set REML = TRUE:
fit_animal_reml <- drmTMB(
bf(
y ~ x + animal(1 + x | individual, A = A),
sigma ~ 1
),
data = dat,
family = gaussian(),
REML = TRUE
)The multi-seed campaign used the A representation shown
here, with n_each = 20 and one fixed M = 8
relationship matrix. Pedigree and Ainv inputs have
deterministic representation-parity evidence only, not multi-seed
campaign coverage. These domains do not admit slope-only, labelled,
multiple-slope, scale-side, bivariate, or non-Gaussian REML routes.
For two responses, use the same animal block label in
mu1 and mu2:
fit_animal_q2 <- drmTMB(
bf(
mu1 = trait1 ~ treatment +
animal(1 | p | individual, Ainv = Ainv),
mu2 = trait2 ~ treatment +
animal(1 | p | individual, Ainv = Ainv)
),
data = dat,
family = biv_gaussian()
)
corpairs(fit_animal_q2, level = "animal")
rho12(fit_animal_q2)The two extractors answer different questions.
corpairs() reports the fitted latent animal-model
correlation among individual location deviations. rho12()
reports the residual correlation between the two responses after the
fixed effects and random effects have been included.
For reports, keep this intercept-only q=2 animal correlation point-only. The profile mechanism computes, but interval calibration and coverage are still planned for this row:
animal_pairs <- corpairs(fit_animal_q2, level = "animal")
plot_corpairs(animal_pairs)That plot should be read as an animal-layer correlation display, not
as a residual rho12 plot. Do not add an interval eye until
this exact row has validated interval evidence. The q=4 rows below are
also point-only: current q=4 animal correlations are derived rows.
When the biological question is whether additive individual deviations in means and residual scales covary, use the same labelled animal term in all four bivariate endpoint formulas:
fit_animal_q4 <- drmTMB(
bf(
mu1 = trait1 ~ treatment +
animal(1 | p | individual, Ainv = Ainv),
mu2 = trait2 ~ treatment +
animal(1 | p | individual, Ainv = Ainv),
sigma1 = ~ treatment +
animal(1 | p | individual, Ainv = Ainv),
sigma2 = ~ treatment +
animal(1 | p | individual, Ainv = Ainv)
),
data = dat,
family = biv_gaussian()
)
corpairs(fit_animal_q4, level = "animal")The q=4 path is constant across individuals and responses: it
estimates four latent animal endpoint scale parameters and six latent
animal correlations. Each endpoint’s individual marginal SD also
includes sqrt(A[i, i]). This is not a direct-SD model and
it does not make the residual correlation rho12
animal-structured.
What to inspect
After fitting, inspect the animal layer before interpreting it:
| Output | Use |
|---|---|
check_drm(fit) |
Confirm the structured layer was recognized and review convergence diagnostics. |
fit$sdpars$mu |
Read the fitted latent animal scale s; individual
i has marginal SD s sqrt(A[i, i]). |
ranef(fit, "animal_mu") |
Inspect conditional individual deviations on the fitted animal layer. |
summary(fit)$covariance |
Check how the animal SD or correlation is reported beside other covariance layers. |
profile_targets(fit) |
See which animal SD or q=2 correlation targets can be profiled directly; q=4 correlations are derived-only in the first slice. |
corpairs(fit, level = "animal") |
Read the fitted q=2 animal mean-mean correlation, or the six q=4 animal endpoint correlations when the model has the all-four block. |
If the ordinary repeatability model answers a useful sensitivity
question, fit (1 | individual) as a comparison. Report it
as an ordinary individual random-effect model, not as an additive animal
model.
Rendered checks
The small examples below keep three evidence grains separate. The
relationship matrix is raw structure supplied to the model. The SD plot
converts the fitted latent scale s to individual marginal
SDs s sqrt(A[i, i]) before comparing them with residual
sigma; it omits uncertainty intervals because the animal q1
location-SD row is not interval-validated. The q=2 animal-correlation
plot is also a fitted point estimate from corpairs() with a
dotted zero line; its interval calibration remains planned.
animal_example <- simulate_animal_guide_data()
animal_dat <- animal_example$data
A <- animal_example$A
Ainv <- animal_example$Ainv
fit_animal <- drmTMB(
bf(
body_size ~ age + sex + animal(1 | individual, Ainv = Ainv),
sigma ~ 1
),
family = gaussian(),
data = animal_dat
)
if (requireNamespace("ggplot2", quietly = TRUE)) {
animal_matrix <- relatedness_heatmap_data(A)
ggplot2::ggplot(
animal_matrix,
ggplot2::aes(column, row, fill = relatedness)
) +
ggplot2::geom_tile() +
ggplot2::coord_equal() +
ggplot2::scale_fill_gradientn(
colours = c("#F7FBFF", "#C6DBEF", "#6BAED6", "#08519C"),
name = "Additive\nrelatedness"
) +
animal_guide_theme() +
ggplot2::theme(
axis.text = ggplot2::element_blank(),
axis.ticks = ggplot2::element_blank(),
panel.grid = ggplot2::element_blank()
) +
ggplot2::labs(
title = "Animal-model input structure",
subtitle = "Known additive relatedness among individuals",
x = "Individual",
y = "Individual"
)
}
Additive relatedness matrix used by the animal-model example; this heatmap is the known input structure, not an uncertainty display.
if (requireNamespace("ggplot2", quietly = TRUE)) {
animal_scale <- unname(fit_animal$sdpars$mu["animal(1 | individual)"])
animal_node_sd <- animal_scale * sqrt(diag(A))
animal_sd <- data.frame(
estimate = c(
unname(exp(coef(fit_animal, "sigma")["(Intercept)"])),
animal_node_sd
),
label = c(
"Residual\nsigma",
rep("Animal node\nmarginal SD", length(animal_node_sd))
)
)
ggplot2::ggplot(animal_sd, ggplot2::aes(y = label)) +
ggplot2::geom_vline(
xintercept = 0,
linewidth = 0.45,
linetype = "dashed",
colour = "grey55"
) +
ggplot2::geom_point(
ggplot2::aes(x = estimate),
shape = 21,
size = 3.5,
stroke = 1,
fill = "white",
colour = "#0072B2"
) +
ggplot2::scale_x_continuous(
expand = ggplot2::expansion(mult = c(0.02, 0.05))
) +
animal_eye_theme() +
ggplot2::labs(
title = "Animal marginal SD is separate from residual sigma",
subtitle = "Node SD = s sqrt(Aii); point estimates only",
x = "Fitted standard deviation",
y = NULL
)
}
Fitted residual sigma and individual marginal animal SD
point estimates s sqrt(A[i,i]) from a univariate Gaussian
model. The animal q1 location-SD interval is not validated, so this
comparison is point-only.
For two response means, the animal-model correlation row is a fitted
latent correlation among individual additive deviations. It is not the
residual rho12 correlation and it is not a raw sample
correlation among observations.
animal_q2_example <- simulate_animal_q2_guide_data()
animal_q2_dat <- animal_q2_example$data
Ainv <- animal_q2_example$Ainv
fit_animal_q2_example <- drmTMB(
bf(
mu1 = body_size ~ climate +
animal(1 | p | individual, Ainv = Ainv),
mu2 = activity ~ climate +
animal(1 | p | individual, Ainv = Ainv),
sigma1 = ~ 1,
sigma2 = ~ 1,
rho12 = ~ 1
),
family = c(gaussian(), gaussian()),
data = animal_q2_dat
)
animal_q2_pairs <- corpairs(
fit_animal_q2_example,
level = "animal"
)
animal_q2_pairs
#> level group block from_dpar to_dpar from_coef to_coef
#> 1 animal individual p mu1 mu2 (Intercept) (Intercept)
#> from_response to_response class
#> 1 body_size activity mean-mean
#> parameter estimate min
#> 1 cor(mu1:(Intercept),mu2:(Intercept) | p | individual) 0.5878297 0.5878297
#> max n_values link_estimate link_min link_max modelled conf.status
#> 1 0.5878297 1 0.6743444 0.6743444 0.6743444 FALSE not_requested
#> interval_source
#> 1 not_available
if (requireNamespace("ggplot2", quietly = TRUE)) {
animal_q2_display <- animal_q2_pairs
animal_q2_display$display_label <- "Animal\nmu1-mu2"
plot_corpairs(
animal_q2_display,
colour = "level",
label = "display_label",
facet = NULL
) +
ggplot2::scale_colour_manual(values = c("animal" = "#0072B2")) +
ggplot2::scale_fill_manual(values = c("animal" = "#0072B2")) +
animal_eye_theme() +
ggplot2::labs(
title = "Animal-model latent mean correlation",
subtitle = "Point estimate only; dotted line marks zero",
x = "Correlation estimate"
)
}
#> Warning: No shared levels found between `names(values)` of the manual scale and the
#> data's fill values.
Animal-model intercept-only q=2 location-location point estimate from
corpairs(); the dotted vertical line marks zero correlation
and no interval is shown because calibration remains planned.
Boundaries
The following animal-model routes remain planned:
- sparse large-pedigree precision construction;
- multiple animal-model slopes such as
animal(1 + x + z | individual, pedigree = pedigree); - animal-model intercept-slope correlations;
- multiple or labelled residual-scale structured slopes beyond the
exact A-matrix q1
animal(1 + x | individual, A = A)sigma route; - predictor-dependent animal
corpair()regressions; - generic direct-SD grammar for animal-model standard deviations;
- richer non-Gaussian animal structured effects: labelled covariance
blocks, multiple structured slopes, structured scale routes beyond the
NB2 one-slope gate, and q=2 or q=4 non-Gaussian animal covariance
blocks. Exact q=1 animal gates already fit today for
poisson(),nbinom2(), andbeta(): Poisson, NB2, and betamuaccept an unlabelled intercept plus one independent slope; NB2sigmaaccepts the same q1 intercept-plus-one-slope form; betasigmaaccepts an intercept only. These rows retain their recorded point-fit/recovery tiers – trust the point estimate, not the interval.
Use the structural-dependence
overview when you are choosing among animal(),
phylo(), spatial(), and relmat().
Use the detailed structural-dependence tutorial when
you need the current fitted examples, equations, and broader parity
ladder.