Skip to contents

This page is the syntax lookup for choosing a covariance keyword. The formula grammar has two decisions: what relates the grouping levels, and what covariance among traits is required at that grouping level.

Use Choose your next gllvmTMB step when you know the modelling task but need help locating this keyword reference or the next post-fit function.

The keywords below are live API, but a valid formula does not guarantee that a complex covariance is estimable from a particular data set. Fit health, replication, trait count, and the scientific covariance question still matter.

Choose in two steps

1. What relates the grouping levels?

  • No prefix: levels are independent, as in an ordinary random effect.
  • animal_: individuals are related through a pedigree, A, or Ainv.
  • phylo_: species are related through a tree or phylogenetic covariance.
  • spatial_: locations share a mesh-based spatial field, represented with a sparse Gaussian Markov random field (GMRF) approximation so nearby locations can be correlated.
  • kernel_: levels are related through a supplied dense covariance matrix K — the generic dense-matrix source (the fifth grid row).

These sources are alternatives based on study design, not a progression from fine to broad scale. Add a source prefix only when that structured relationship is part of the estimand.

2. What trait covariance is needed?

There are three fundamental cross-trait structures, from simplest to richest:

  • indep: a separate marginal variance for each trait and zero cross-trait covariance — a diagonal model. Its parsimony modifier common = TRUE ties all trait variances to one shared value (the scalar special case).
  • dep: a full unstructured trait covariance with (T(T+1)/2) covariance parameters. Use only when trait count and grouping-level replication support a saturated covariance.
  • latent: a parsimonious reduced-rank cross-trait covariance 𝚲𝚲𝖳\boldsymbol\Lambda\boldsymbol\Lambda^{\mathsf T} represented by (d) latent variables. Its modifier unique = TRUE adds the trait-diagonal Ψ\Psi companion.

scalar and unique are modifiers, not separate modes. scalar is indep with the variances tied to one shared value; unique is latent with its diagonal-Ψ\Psi companion. This mirrors how the deprecated unique() keyword now lives as latent(unique = TRUE). The named scalar(), phylo_scalar(), animal_scalar(), spatial_scalar(), and kernel_scalar() keywords fit exactly this model but are soft-deprecated compatibility syntax (they emit a one-time warning); write indep(..., common = TRUE) in new code.

All fitted keyword covariances are random-effect covariances on the model’s linear-predictor or latent scale. They are not automatically response-scale covariances for non-Gaussian traits.

The 5 × 3 grid

The rows are the five correlation sources across grouping levels; the columns are the three fundamental trait-covariance modes. Every cell is a live keyword. The scalar and unique sub-cases are modifiers, listed under the table.

Source × mode covariance keyword grid
Source Independent Dependent Latent
none indep() dep() latent()
animal animal_indep() animal_dep() animal_latent()
phylogenetic phylo_indep() phylo_dep() phylo_latent()
spatial spatial_indep() spatial_dep() spatial_latent()
kernel kernel_indep() kernel_dep() kernel_latent()

Scalar (one shared variance). Add common = TRUE to any indep term — e.g. indep(0 + trait | g, common = TRUE). The soft-deprecated scalar() / *_scalar() keywords fit the same model but warn once and are kept only for compatibility. Omitting a multi-trait covariance term entirely means no such term is fitted.

Unique (diagonal-Ψ\Psi companion). Add unique = TRUE to a latent term (see the latent default below). The standalone unique() keyword is soft-deprecated in favour of indep() (for a plain diagonal) and latent(unique = TRUE) (for the paired companion).

What the modes estimate

For the intercept-only grid, let KggK_{gg'} be an entry of the relationship or model-implied covariance operator among grouping levels. For the ordinary no-prefix row, 𝐊=𝐈\mathbf K = \mathbf I. Animal, phylogenetic, and dense-kernel inputs supply fixed covariance operators and may have non-unit diagonals. Spatial terms instead imply 𝐊(𝛉)\mathbf K(\boldsymbol\theta) through a mesh-based precision whose range and scale parameters are estimated.

The clearest ordering-free definition is

Cov(bgt,bgt)=ΣT,ttKgg, \operatorname{Cov}(b_{gt}, b_{g't'}) = \Sigma_{T,tt'} K_{gg'},

where 𝚺T\boldsymbol\Sigma_T is the trait covariance implied by the selected mode: diag(ψ1,,ψT)\mathrm{diag}(\psi_1,\ldots,\psi_T) for indep (collapsing to the shared σ2𝐈T\sigma^2\mathbf I_T under the common = TRUE / scalar modifier), a free 𝚺T\boldsymbol\Sigma_T for dep, and 𝚲𝚲𝖳\boldsymbol\Lambda\boldsymbol\Lambda^{\mathsf T} with an optional 𝚿\boldsymbol\Psi companion for latent. This elementwise form does not depend on whether software stacks traits or grouping levels first.

The diagonal in animal_indep() or phylo_indep() is diagonal across traits, but observations remain correlated within each trait through the pedigree or phylogeny. It is not independent residual noise.

The important latent default

Here, unique = is an argument of a latent term that toggles its diagonal Psi companion; it is not a separate covariance mode or a call to the deprecated covariance-function syntax.

The diagonal Psi companion is controlled differently across sources:

  • ordinary latent() includes 𝚲𝚲𝖳+𝚿\boldsymbol\Lambda\boldsymbol\Lambda^{\mathsf T}+\boldsymbol\Psi by default; use unique = FALSE for loadings only;
  • animal_latent(), phylo_latent(), spatial_latent(), and kernel_latent() are loadings-only by default;
  • use unique = TRUE on a source-specific or single-kernel latent term when that same source should also carry a trait-diagonal Psi component.

For animal, phylogenetic, and kernel models, source-specific Psi is diagonal across traits but still correlated across individuals, species, or other levels through the supplied relationship or covariance operator. Spatial Psi is also diagonal across traits, while each trait-specific field remains correlated across locations through the mesh-based spatial precision.

These diagonal statements describe intercept-only trait covariance. With an augmented intercept-and-slope term, *_indep(1 + x | group) estimates a per-trait intercept–slope correlation (a double bar, 1 + x || group, drops it). The random-slope section below gives the corresponding blocks.

Ordinary long and wide syntax

The long and wide forms below express the same covariance choices. The Morphometrics article executes and compares both data shapes.

# Decomposed covariance: Lambda Lambda^T + Psi
fit_long <- gllvmTMB(
  value ~ 0 + trait +
    latent(0 + trait | individual, d = 2),
  data = df_long,
  trait = "trait",
  unit = "individual"
)

fit_wide <- gllvmTMB(
  traits(length, mass, wing, tarsus, bill) ~ 1 +
    latent(1 | individual, d = 2),
  data = df_wide,
  unit = "individual"
)

Replace latent(...) with indep(...) for a diagonal baseline or dep(...) for a full covariance. In wide formulas, 1 inside a bar-style term expands to the long-form 0 + trait representation.

Exact source-specific syntax

The latent animal/phylogenetic helpers take the grouping column directly. The indep and dep counterparts use a bar formula, and the one-shared-variance (scalar) case is the common = TRUE modifier on indep. Spatial helpers all use the bar-form orientation.

Animal

animal_indep(0 + trait | id, pedigree = ped, common = TRUE)  # one shared variance
animal_indep(0 + trait | id, pedigree = ped)
animal_dep(0 + trait | id, pedigree = ped)
animal_latent(id, d = 2, pedigree = ped)                 # loadings only
animal_latent(id, d = 2, pedigree = ped, unique = TRUE)  # + animal Psi

Phylogenetic

phylo_indep(0 + trait | species, tree = tree, common = TRUE)  # one shared variance
phylo_indep(0 + trait | species, tree = tree)
phylo_dep(0 + trait | species, tree = tree)
phylo_latent(species, d = 2, tree = tree)                 # loadings only
phylo_latent(species, d = 2, tree = tree, unique = TRUE)  # + phylo Psi

Use tree = for the usual phylogenetic workflow. vcv =, A =, and Ainv = support advanced precomputed covariance/precision inputs; their row and column names must match the grouping levels.

Spatial

spatial_indep(0 + trait | site, mesh = mesh, common = TRUE)  # one shared variance
spatial_indep(0 + trait | site, mesh = mesh)
spatial_dep(0 + trait | site, mesh = mesh)
spatial_latent(0 + trait | site, d = 2, mesh = mesh)
spatial_latent(0 + trait | site, d = 2, mesh = mesh, unique = TRUE)

Spatial models require a mesh built from the model’s coordinate columns with make_mesh(). Pass that mesh either inside the spatial keyword or through the top-level mesh = argument to gllvmTMB(). A source-valid formula still needs enough locations and spatial spread to identify range and covariance parameters.

Dense kernels (the fifth grid row)

A supplied dense covariance matrix K is the generic dense-matrix source. Its keywords follow the same grid as the other sources, with the tied-variance case as the common = TRUE modifier on kernel_indep().

kernel_indep(unit_id, K = K, name = "known", common = TRUE)  # one shared variance x K
kernel_indep(unit_id, K = K, name = "known")
kernel_dep(unit_id, K = K, name = "known")
kernel_latent(unit_id, K = K, d = 2, name = "known")
kernel_latent(
  unit_id, K = K, d = 2, name = "known", unique = TRUE
)

For a single named kernel, unique = TRUE adds that kernel’s diagonal Psi companion. Multiple named-kernel fits currently use the latent-only route; do not assume that each component receives its own Psi. When kernels overlap strongly, the fitted sum may be more stable than attribution to individual kernel components.

Named kernels should encode a relationship fixed before fitting. The model does not turn an analyst-supplied association matrix into evidence of a causal or reciprocal process. When more than one named kernel is fitted, use diagnose_kernel_separability() before interpreting component-specific output; collapse indistinguishable kernels rather than assigning them separate biological stories.

Other formula markers

Random slopes

phylo_slope(x | species) and animal_slope(x | id) are live slope-only structured routes. They are not additional covariance modes and should not be confused with an augmented intercept-and-slope covariance such as animal_dep(1 + x | id, ...) or spatial_latent(1 + x | site, ...).

An augmented random-slope term describes deviations around a fixed population-average slope. Include that fixed slope separately:

# Long form
value ~ 0 + trait + (0 + trait):x +
  phylo_indep(0 + trait + (0 + trait):x | species)

# Equivalent wide form
traits(t1, t2, t3) ~ 1 + x +
  phylo_indep(1 + x | species)

The three structured modes do not merely represent increasing computational complexity. They estimate different covariance objects (for a single slope x and TT traits):

  • *_indep(1 + x | g) estimates TT independent per-trait 2×22 \times 2 (intercept, slope) blocks – each trait gets its own intercept variance, slope variance, and intercept–slope correlation, with no covariance across traits. Extract it at level = "phy" / "spatial" / "kernel".
  • *_dep(1 + x | g) estimates a full interleaved 2T×2T2T \times 2T covariance across all trait intercepts and slopes. Same extraction levels.
  • *_latent(1 + x | g, d = K) estimates separate reduced-rank cross-trait covariance matrices for the intercept and slope columns; it does not estimate intercept–slope covariance. Extract the per-column matrices at level = "phy_slope" or level = "spde_slope".

Correlated and uncorrelated slopes: | and ||

There is one more choice for a random slope – whether the intercept and slope are correlated – and it is set by the number of bars, matching lme4/glmmTMB:

  • A single bar, mode(1 + x | g), estimates the intercept–slope correlation (the default).
  • A double bar, mode(1 + x || g), drops it: the intercept and slope are uncorrelated. It is exactly mode(1 | g) + mode(0 + x | g).

The bar count sets only the intercept–slope coupling; the mode still sets the cross-trait structure. For TT traits:

mode 1 + x \| g (correlated) 1 + x \|\| g (uncorrelated)
indep a separate 2×22 \times 2 per trait a per-trait intercept variance + slope variance (fully diagonal)
dep full 2T×2T2T \times 2T across all trait intercepts and slopes a full intercept covariance and a full slope covariance, with intercepts \perp slopes (𝚺int𝚺slope\boldsymbol\Sigma_{\text{int}} \oplus \boldsymbol\Sigma_{\text{slope}})
latent separate reduced-rank 𝚲\boldsymbol\Lambda per column block (already uncorrelated) the same – \|\| is the explicit spelling

Both bar forms are available for the phylo_, animal_, kernel_, and spatial_ sources.

Choose the mode from the scientific covariance assumption, not as an automatic fallback after a difficult fit. Centre and scale x, retain the transformation, and confirm repeated, overlapping within-unit coverage before fitting a random slope. The behavioural reaction-norm guide shows those design checks for the ordinary Gaussian case. Family-specific response requirements still apply; changing family = is not the only change needed when moving from continuous traits to counts, proportions, trials, or ordered categories.

Known sampling covariance

meta_V() is not a grid row. It adds a known observation/sampling covariance to a meta-analytic model rather than estimating a random-effect trait covariance. The exact-additive route requires the same row-aligned matrix in the formula marker and the top-level argument:

value ~ 0 + trait + latent(0 + trait | study, d = 1) + meta_V(V = V)
# In gllvmTMB(...), also pass known_V = V.

Use A/Ainv for relatedness and V for known sampling covariance; they are different scientific objects. This syntax lookup does not provide the applied estimand, diagnostic, and interpretation workflow needed for a full meta-analytic example. meta_known_V() remains a soft-deprecated alias; new code uses meta_V().

What not to combine

At one grouping level and correlation source, specify one trait-covariance story:

  • do not combine dep with indep or latent at that source;
  • do not combine standalone indep with latent at that source;
  • the same rules apply to ordinary, animal, phylogenetic, spatial, and single-kernel terms.

Different grouping levels can carry different covariance terms—for example, a between-individual latent() term and a within-individual indep() term—when the design identifies both.

If the first choice is too complex

  • Full dep() is unstable or imprecise: try a lower-rank latent() model, or indep() if cross-trait covariance is not essential.
  • An added LV is weak or unstable across refits: reduce d and compare fit health and information criteria.
  • A diagonal variance is at zero: treat it as a boundary estimate; compare the simpler model rather than interpreting a tiny component literally.
  • A relationship input fails: check grouping-level names, matrix dimensions, positive-semidefiniteness, tree tips, or mesh/data alignment.
  • You are unsure which source prefix to use: return to the biological sampling design. A more elaborate source is not automatically a better model.

See Fit diagnostics before interpreting the selected covariance and Covariance and correlation for the corresponding estimands.