For a phylogenetic species-level GLLVM, decomposes each trait's between-species latent variance into three additive components that sum to one: $$H_t^2 \;=\; \frac{[\boldsymbol\Sigma_\text{phy}]_{tt}}{V_{\eta,t}}, \qquad C^2_{\text{non},t} \;=\; \frac{[\boldsymbol\Sigma_\text{non,shared}]_{tt}}{V_{\eta,t}}, \qquad \psi_t \;=\; \frac{[\boldsymbol\Psi_\text{non}]_{tt}}{V_{\eta,t}},$$ where \(V_{\eta,t} = [\boldsymbol\Sigma_\text{phy}]_{tt} + [\boldsymbol\Sigma_\text{non,shared}]_{tt} + [\boldsymbol\Psi_\text{non}]_{tt}\) is the total between-species latent variance for trait \(t\) .
Usage
extract_phylo_signal(
fit,
ci = FALSE,
conf_level = 0.95,
method = c("profile", "wald", "bootstrap"),
nsim = 500L,
seed = NULL
)Arguments
- fit
A fit returned by
gllvmTMB()with aphylo_latent()term.- ci
Logical. When
TRUE, adds confidence-interval columns to the output for the H^2 column. DefaultFALSEfor backward compatibility.- conf_level
Confidence level when
ci = TRUE. Default 0.95.- method
One of
"profile"(default),"wald","bootstrap". Only used whenci = TRUE. For 2-component decompositions (a phylo diagonal vs species-level diagonal component only) profile uses a linear contrast; for 3-component decompositions (PGLLVM with phylo_latent plus a species-level latent decomposition with Psi) the full profile path is not yet implemented and falls back to numerical delta-method Wald bounds labelled"wald(numeric)".- nsim
Number of bootstrap replicates when
method = "bootstrap". Default 500.- seed
Optional RNG seed for the bootstrap.
Value
A data frame with columns trait, H2, C2_non, Psi,
V_eta (the denominator), one row per trait. The three proportions
sum to 1.0 by construction. When ci = TRUE, three additional
columns are added: H2_lower, H2_upper, H2_method.
Details
Interpretation:
- \(H_t^2\)
phylogenetic signal — proportion of between- species latent variance attributable to phylogenetically structured variation ("evolutionary conservatism"). When the model uses the folded
phylo_latent(..., unique = TRUE)decomposition, \(\boldsymbol\Sigma_\text{phy}\) is the sum \(\boldsymbol\Lambda_\text{phy} \boldsymbol\Lambda_\text{phy}^{\!\top} + \boldsymbol\Psi_\text{phy}\) and \(H_t^2\) reflects the total phylogenetic variance.- \(C^2_{\text{non},t}\)
non-phylogenetic communality — proportion of variance attributable to shared non-phylogenetic axes ("coordinated tip-level lability" across traits).
- \(\psi_t\)
uniqueness — proportion of variance not captured by any shared axis ("relative modularity").
Requires phylo_latent() (optionally with unique = TRUE for a
phylogenetic Psi) plus a species-level latent() term, which carries its
diagonal Psi companion by default. If the species-tier Psi is absent (a
latent(..., unique = FALSE) subset), \(\psi_t = 0\) for all traits and a
cli::cli_inform() advisory fires.
Which variances enter the denominator
V_eta is the species-level latent variance: only components whose
grouping is the cluster column contribute. Concretely
\(V_\eta = \sigma^2_{phy} + \sigma^2_{non}\), where \(\sigma^2_{non}\)
collects the species-grouped non-phylogenetic variance.
When
unit == cluster(the usualunit = "species"setup) the ordinarylatent()term and itsPsicompanion are species-level, so both enter.When
unit != cluster(a crossedsite x speciesdesign)Lambda_Band itsPsiare site-level and do not enter; the species-level non-phylogenetic variance is the cluster-tierq_itterm (indep(0 + trait | <cluster>), reported assd_q^2).
The denominator is defined at the species level. Other defensible
definitions exist — for instance a total-variance denominator
that also absorbs site-level variation, which would give a smaller H2 for
the same fit. Before 2026-07-08 this function used the unit tier
unconditionally, which silently reported H2 = 1 for every trait in a
crossed design because the q_it variance was never read. Compare
extract_proportions() if you want every component reported separately
rather than folded into a species-level ratio.
Examples
if (FALSE) { # \dontrun{
fit <- gllvmTMB(
value ~ 0 + trait + phylo_latent(species, d = 2) +
latent(0 + trait | species, d = 2) +
indep(0 + trait | species),
data = df,
trait = "trait",
unit = "species",
cluster = "species",
phylo_tree = tree
)
extract_phylo_signal(fit)
} # }
