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.
Most readers only need the two choices below; the optional
rho setting on a structured term is covered later, in Advanced: estimating the
source strength.
Choose in two steps
1. What is being related?
The first five sources describe relationships among stable units: for example, individuals, species, locations, or rows of a supplied relatedness matrix. Temporal is the additional source for ordered repeated states within a series. It uses the same three trait-covariance modes, but its series and time coordinates have a different scientific meaning.
- No prefix: levels are independent, as in an ordinary random effect.
-
animal_: individuals are related through a pedigree,A, orAinv. -
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 matrixK— the generic dense-matrix source (the fifth grid row). -
temporal_: ordered states within eachseriesshare an AR1 or OU kernel.time =names the occasion or elapsed-time column; AR1 preserves integer gaps and OU uses elapsed-time distances.
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 modifiercommon = TRUEties 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 represented by (d) latent variables. Its modifierunique = TRUEadds the trait-diagonal companion.
scalar and unique are modifiers,
not separate modes. scalar is indep
with the variances tied to one shared value; unique = TRUE
adds the
diagonal-
companion to a latent term. The standalone deprecated
unique() keyword remains compatibility syntax for the plain
diagonal case. 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, plus temporal
The five stable-unit sources form the familiar 5 × 3 grid. Temporal adds a sixth, within-series row with the same three trait-covariance modes. Thus the formal grammar is a 6 × 3 source-by-mode grid, while this presentation keeps the important distinction visible. Every cell is a live keyword. The scalar and unique sub-cases are modifiers, listed under the table.
| 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()
|
| temporal (within series) |
temporal_indep()
|
temporal_dep()
|
temporal_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-
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).
The temporal addition
temporal_indep(0 + trait | series, time = occasion),
temporal_dep(...), and
temporal_latent(..., d = 1) form the temporal row. Here
series identifies one independent trajectory, and
time = occasion uses the bare occasion column
from the data: it is neither a formula term nor a character string. A
replicate = measurement column identifies repeated
measurements at the same (series, occasion) state. The
provider creates that state index privately; it does not change
unit or unit_obs, which retain their ordinary
stable-unit and within-unit meanings.
AR1 accepts ordered integer occasions and preserves unobserved
occasions as gaps; OU accepts elapsed numeric time without automatic
rescaling. With temporal_latent(unique = TRUE), Psi is
itself correlated through the temporal kernel, not IID occasion noise.
The temporal article shows matching long and traits(...)
wide calls. In scope: focused Gaussian local fits,
source parsing, covariance oracles, simulation, and ordinary
unit/unit-observation composition. Partial: recovery is
not yet a general claim. The bounded temporal-only forecast, profile,
bootstrap, and supplied-candidate comparison helpers have their own
contracts; generic forecasts, new-data prediction, generic
intervals/profiles, and automatic selection remain unavailable. Four
replicated-AR1 additive temporal_indep() pairs with one
diagonal kernel, phylogenetic, animal, or spatial source are separately
implemented, with pair-specific local evidence only: the kernel
combination met its prespecified recovery criteria in one local
simulated example, while the phylogenetic, animal, and spatial recovery
studies retain failed cases. These pairs require complete Gaussian
identity-link data, native TMB/Laplace ML, at least two complete
measurements per series–occasion, and a source fixed at
rho = 1. Supply the source inside its keyword
(K =, tree =/vcv =,
pedigree =/A =/Ainv =, or
mesh =). The spatial route needs time and space contrasts
that are not proportional. OU source combinations, temporal
dep/latent combinations, temporal slopes,
other families, higher rank, source-by-time interactions, and other
structured-source combinations are unavailable. See Temporal covariance for the standalone
workflow and the adjacent source-combination limits.
What the modes estimate
For the intercept-only grid, let be an entry of the relationship or model-implied covariance operator among grouping levels. For the ordinary no-prefix row, . Animal, phylogenetic, and dense-kernel inputs supply fixed covariance operators and may have non-unit diagonals. Spatial terms instead imply through a mesh-based precision whose range and scale parameters are estimated.
The clearest ordering-free definition is
where
is the trait covariance implied by the selected mode:
for indep (collapsing to the shared
under the common = TRUE / scalar modifier), a free
for dep, and
with an optional
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 by default; useunique = FALSEfor loadings only; -
animal_latent(),phylo_latent(),spatial_latent(), andkernel_latent()are loadings-only by default; - use
unique = TRUEon 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 PsiPhylogenetic
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 PsiUse 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.
What sits outside the grid
Slope variation by response column
The 6 × 3 grid describes trait covariance for random effects. The slope helpers answer a separate question: how do fixed-predictor coefficients vary across the response columns? They are not a new grid row, column, or mode.
| Column relationship | Use |
|---|---|
| no supplied relationship | slope(x | trait) |
| a phylogenetic tree | phylo_slope(x | trait, tree = tree) |
| a pedigree or relationship matrix | animal_slope(x | trait, A = A) |
| a labelled covariance matrix | kernel_slope(x | trait, K = K) |
| one coordinate pair per column | spatial_slope(x | trait, mesh = column_mesh) |
For this helper family, the right side must be the variable that
labels the response columns, supplied through trait = and
usually named trait. The helper adds no random intercept.
With two or more predictors, | estimates their full
covariance and || keeps their predictor variances but fixes
their covariance to zero. Retrieve that predictor-by-predictor matrix
with extract_Sigma(fit, level = "column_slope").
value ~ 0 + trait + moisture + canopy +
phylo_slope(moisture + canopy | trait, tree = tree)This is Gaussian long-format point estimation only. Wide column-slope
grammar, non-Gaussian responses, latent predictor covariance, several
helpers in one model, and intervals are deliberately deferred.
Group-indexed phylo_slope(x | species) and
animal_slope(x | id) remain current and warning-free for
models whose coefficients vary across sampled units. They answer a
different grouping-axis question from the response-column slope helpers
described here. In short: use
phylo_slope(x | trait, tree = tree) when the slope of
x should vary across response columns
(e.g. across traits or species treated as responses) and use
phylo_slope(x | species) when the slope of x
should vary across the sampled grouping units
(e.g. across individuals or sites) that the tree relates.
Intercepts and slopes by response column
column_coef(), phylo_coef(),
animal_coef(), kernel_coef(), and
spatial_coef() extend the coefficient basis to an explicit
random intercept, a slope, or both. They are also outside the 6 × 3
grid: their covariance is across coefficient-basis columns, not a new
trait-covariance mode.
# IID response-column intercepts and slopes
value ~ 1 + column_coef(1 + moisture | trait)
# Tree-correlated response-column intercepts and slopes; estimate rho
value ~ 1 + phylo_coef(1 + moisture | trait, tree = tree, rho = NULL)
# Pedigree-correlated response-column intercepts and slopes; fix rho
value ~ 1 + animal_coef(1 + moisture | trait, pedigree = pedigree, rho = 1)
# C3/C4 grand intercepts and slopes, plus kernel-correlated
# response-column intercept and slope deviations; estimate rho
value ~ 0 + pathway + moisture:pathway +
kernel_coef(1 + moisture | trait, K = K, name = "environment", rho = NULL)
# The same hierarchical model from a wide response data frame;
# pass the keyed pathway table through column_data
traits(sp1, sp2, sp3, sp4) ~ 0 + pathway + moisture:pathway +
kernel_coef(1 + moisture | trait, K = K, name = "environment", rho = NULL)
# Species locations as the response-column relationship; rho is fixed at 1
value ~ 0 + pathway + moisture:pathway +
spatial_coef(1 + moisture | trait, mesh = column_mesh)Use | for a full coefficient covariance and
|| for a diagonal one. Retrieve the ordered basis
covariance and source metadata with
extract_Sigma(fit, level = "column_coef"). All five helpers
support Gaussian point models through long or traits(...)
wide input. Numeric rho fixes the phylogenetic, animal, or
dense-kernel mixture; phylo_coef(rho = NULL) and
kernel_coef(rho = NULL) estimate one interior value.
animal_coef() accepts exactly one pedigree, relationship
covariance A, or precision Ainv;
kernel_coef() accepts one labelled dense positive-definite
covariance K and reports its name and supplied scale.
spatial_coef() accepts one mesh built with exactly one
labelled coordinate pair per response column and currently requires
rho = 1; its extractor reports the aligned coordinates,
fitted range, and projected unit-diagonal source covariance. Estimated
animal rho, spatial IID mixtures, non-Gaussian responses,
and intervals remain unavailable. The existing slope-only helpers above
remain current, warning-free, and non-deprecated.
For exact compatibility, a no-intercept dense-vcv
phylo_coef(..., rho = 1) call uses the released
phylo_slope() conditioning K + 1e-8 I. Other
fixed/estimated coefficient routes use the raw covariance-scale mixture.
At the corresponding no-intercept rho = 1 endpoint,
animal_coef() uses the released animal_slope()
route exactly. Its dense-A route therefore inherits the
released A + 1e-8 I conditioning seam; pedigree and
sparse-Ainv endpoints retain their released precision. At
the no-intercept rho = 1 kernel endpoint,
kernel_coef() uses kernel_slope() exactly and
therefore retains raw K without a ridge. At the
no-intercept spatial endpoint, spatial_coef() uses
spatial_slope() exactly and retains its projected-SPDE
normalization and range parameter.
For a worked comparison of a tree among sampled species and a tree among response columns, read Where does the phylogeny belong?.
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
depwithindeporlatentat that source; - do not combine standalone
indepwithlatentat 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.
Advanced: estimating the source strength
Canonical phylo_*, animal_* and
kernel_* indep/dep/latent terms also accept trailing
rho = 1. Fixed values between zero and one attenuate
between-level source covariance while preserving the resolved source
diagonal. This does not add a grid row or mode. With
unique = TRUE, the same strength applies to both the
loadings and Psi; ordinary intercept effects stay separate. Omitted rho
and explicit one preserve existing models, including multi-kernel
endpoints. New attenuation currently supports one structured
trait-intercept block per fit.
rho = NULL estimates one strength only in the documented
complete, replicated Gaussian design with retained observation noise and
no competing ordinary covariance. Estimated latent terms require rank
one and at least four traits. Spatial terms use the same attenuation
weight while range stays separately estimated. Spatial recovery remains
unvalidated. Augmented slopes and source-strength intervals are not
included. A converged optimizer does not establish identification or
recovery. See Strength of a
known source for runnable long and wide examples, extraction and
interpretation. These defaults do not change the separate
response-column coefficient helpers.
If the first choice is too complex
-
Full
dep()is unstable or imprecise: try a lower-ranklatent()model, orindep()if cross-trait covariance is not essential. -
An added LV is weak or unstable across refits:
reduce
dand 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.
