Skip to content

Constrained Ordination

Unconstrained ordination (PCA, NMDS, PCoA) shows the full structure in your data regardless of what drives it. Constrained ordination goes a step further: it shows only the variation in community composition that can be explained by a specified set of environmental or experimental variables.

This makes constrained ordination a powerful tool for directly answering questions like "how much of the variation in species composition is associated with moisture gradient?" or "do management types lead to different plant communities after accounting for soil pH?"


The Three Main Methods

RDA (Redundancy Analysis) is the constrained equivalent of PCA. It uses Euclidean distances and is appropriate for continuous, normally distributed response data. Apply a Hellinger transformation to species abundance data before RDA.

CCA (Canonical Correspondence Analysis) is the constrained equivalent of correspondence analysis. It uses chi-square distances and is designed for raw species counts, particularly when species show unimodal responses along environmental gradients.

db-RDA (Distance-based RDA) is the most general approach. It applies RDA to a distance matrix computed from any metric, including Bray-Curtis or UniFrac. It is the preferred method when you want constrained ordination with a non-Euclidean distance.


The Three Methods

library(vegan)

data(dune)
data(dune.env)

RDA is the constrained equivalent of PCA. Apply a Hellinger transformation to species abundance data before fitting.

The summary output reports constrained and unconstrained inertia. The constrained proportion is your R2: the fraction of total compositional variance explained by the model.

# Hellinger transformation
dune_hell <- decostand(dune, method = "hellinger")

# Fit RDA
rda_result <- rda(dune_hell ~ Management + Moisture, data = dune.env)
summary(rda_result)

# Significance tests
anova(rda_result, permutations = 999)              # Overall model
anova(rda_result, by = "term", permutations = 999) # Each term

# Plot (scaling = 2: correlations between species and environment)
plot(rda_result, scaling = 2)

CCA is the constrained equivalent of correspondence analysis. Use on raw counts when species show unimodal responses to gradients. No transformation needed.

If your gradient is short and species responses are approximately linear, RDA on Hellinger-transformed data often performs better.

# CCA on raw counts
cca_result <- cca(dune ~ Management + Moisture, data = dune.env)
summary(cca_result)

# Significance tests
anova(cca_result, permutations = 999)
anova(cca_result, by = "term", permutations = 999)

# Plot
plot(cca_result, scaling = 2)

db-RDA is the most flexible option. It applies RDA to any distance matrix, including Bray-Curtis or UniFrac, and is preferred for microbiome data or when consistency with PERMANOVA is important.

db-RDA tests the same hypothesis as PERMANOVA but additionally produces a constrained ordination diagram.

# db-RDA with Bray-Curtis
dbrda_result <- dbrda(dune ~ Management + Moisture,
                      data = dune.env,
                      dist = "bray")
summary(dbrda_result)

# Significance tests
anova(dbrda_result, permutations = 999)
anova(dbrda_result, by = "term", permutations = 999)

# Plot
plot(dbrda_result)

Variance Partitioning

When you have multiple groups of explanatory variables (for example, environmental variables and spatial variables), variance partitioning decomposes the total explained variance into components attributable to each group alone and their shared contribution.

# Partition variance between management and soil variables
vp <- varpart(dune_hell,
              ~ Management,
              ~ Moisture + A1,
              data = dune.env)

print(vp)
plot(vp, digits = 2,
     Xnames = c("Management", "Soil"),
     bg = c("#00AFBB", "#FC4E07"))

The output gives four fractions: - Variation explained by the first set of variables alone - Variation explained by the second set alone - Shared variation (confounded between the two sets) - Unexplained variation (residuals)


Choosing Between RDA, CCA, and db-RDA

RDA CCA db-RDA
Distance assumed Euclidean Chi-square Any
Response data Transformed abundances Raw counts Any
Species response model Linear Unimodal None
Most flexible Yes
Loadings interpretable Yes Yes Limited

A practical rule: if you are working with microbiome or ecological count data and already using Bray-Curtis elsewhere in your analysis, db-RDA gives the most consistent results. If you have transformed your data for RDA and it looks appropriate, RDA is simpler to interpret.


Exercise

Using the dune dataset, fit a constrained ordination model with Management and Moisture as explanatory variables. Test the significance of each term and interpret what fraction of compositional variance they explain.

Solution
library(vegan)

data(dune)
data(dune.env)

# Hellinger transformation
dune_hell <- decostand(dune, method = "hellinger")

# RDA
rda_result <- rda(dune_hell ~ Management + Moisture, data = dune.env)

# Variance explained
summary(rda_result)$cont$importance[2, 1:2]
# Proportion of constrained variance on RDA1 and RDA2

# Overall model
anova(rda_result, permutations = 999)

# Term-by-term
anova(rda_result, by = "term", permutations = 999)
# Which variable explains more variance? Is each significant?

# Plot
plot(rda_result, scaling = 2)

# Variance partitioning
vp <- varpart(dune_hell, ~ Management, ~ Moisture, data = dune.env)
plot(vp, Xnames = c("Management", "Moisture"),
     bg = c("#00AFBB", "#FC4E07"))