## PC1 vs. centroid size:
plot(pca$x[, 1] ~ gpa$Csize,
pch = 16, xlab = "Centroid size",
ylab = "PC1")
Allometry
The allometric effect is the potential influence of the size (i.e., the centroid size) on the shape (i.e., the Procrustes coordinates). To assess it, we should evaluate whether there is a strong and significant relationship between those two elements. One way to do so is to use a linear model (Cornillon et al. 2023; Fox 2016), and more precisely a linear regression of shape over size. For an overview of this topic, see for instance Klingenberg (2016) or Klingenberg (2022).
1 Using principal components
A first (elementary) approach would be to study the link between the first principal axis and the centroid size. This can be done, for instance, with:
A similar approach can be performed on PC2 and subsequent axes.
2 A more complex approach
However, it is also possible to inspect the whole effect of allometry by assessing the relationship between centroid size and the procrustes coordinates as a whole.
2.1 Using linear models
## Perform the regression analysis of Shape ~ Size:
<- procD.lm(
fit ~ csize,
coords data = gm.dtf,
iter = 999
)## ANOVA table:
$aov.table fit
Df SS MS Rsq F Z Pr(>F)
csize 1 0.07020 0.070200 0.25539 53.848 4.8678 0.001 ***
Residuals 157 0.20468 0.001304 0.74461
Total 158 0.27488
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
To conclude on the potential effect of the size on the shape, you should pay attention to the value of the Pr(>F)
(a p-value, informing on statistical significance) and Rsq
(i.e., \(R^2\), informing on the strength of the relationship).
Figure 2 shows how to represent graphically this relationship, using the method of regression scores (Drake et al. 2017). Note that each point represents an individual, and that you can color points according to a categorical variable with the col
argument.
plotAllometry(fit, size = gpa$Csize,
method = "RegScore", pch = 19)
2.2 Raw procrustes coordinates versus regression residuals
Depending on the significance and strength of the allometric effect, you can decide to run the subsequent analyses either on the raw Procrustes coordinates (to keep this potential effect of size on shape), or the residuals computed from the regression of the size over the shape (to get rid of this allometric effect and only analyze form variations). These residuals can be computed with:
## Regression residuals:
<- fit$residuals resid
2.3 Shape versus form
One last interesting analysis that can help us to decide whether to keep or get rid of this allometric effect consists in studying the individuals distribution when focusing on either the shape or the form, and assessing whether a covariate (like the age) is still influencing this variation.
## PCA of shape variation (performed on raw Procrustes coordinates):
<- PCA(gen.dtf[, 1:206], scale.unit = FALSE, graph = FALSE)
pca.shape fviz_pca_ind(pca.shape, axes = c(1, 2), col.ind = gm.dtf$age_class,
addEllipses = TRUE, label='none', legend.title = "Age class")
## PCA of form variation (performed on residuals from the regression of size over shape):
<- PCA(resid, scale.unit = FALSE, graph = FALSE)
pca.form fviz_pca_ind(pca.form, axes = c(1, 2), col.ind = gm.dtf$age_class,
addEllipses = TRUE, label = 'none', legend.title = "Age class")
3 More statistical inference and permutation tests
To go further in the interpretation, we can associate to these PCAs additional analyses to assess whether the selected covariate significantly contributes to the observed inter-individual variation.
- Can we significantly distinguish each age class based on the mandible shape?
permudist(pca.shape$ind$coord,
groups = gen.dtf$age_class,
rounds = 999)$p.value
Juvenile Sub-adult Adult
Sub-adult 0.036
Adult 0.001 0.001
Older adult 0.001 0.003 0.154
- Can we significantly distinguish each age class based on the mandible form?
permudist(pca.form$ind$coord,
groups = gen.dtf$age_class,
rounds = 999)$p.value
Juvenile Sub-adult Adult
Sub-adult 0.405
Adult 0.140 0.548
Older adult 0.247 0.065 0.032
Finally, it could be interesting to evaluate the correlation between this covariate and the shape:
cor.test(gm.dtf$csize, gm.dtf$age, method = "pearson")
Pearson's product-moment correlation
data: gm.dtf$csize and gm.dtf$age
t = 13.281, df = 157, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.6447083 0.7932121
sample estimates:
cor
0.7273664
We could also investigate whether the centroid size significantly varies depending on the value of the covariate:
## Distribution of centroid size among age classes:
boxplot(csize ~ age_class, data = gen.dtf,
xlab = "Age class", ylab = "Centroid size",
main = "Distribution of the centroid size among age classes")
We can then test whether this distribution significantly differs between each age class1:
## ANOVA (with randomized permutations):
<- lm.rrpp(csize ~ age_class, data = na.omit(gen.dtf))
age.size anova(age.size)
Analysis of Variance, using Residual Randomization
Permutation procedure: Randomization of null model residuals
Number of permutations: 1000
Estimation method: Ordinary Least Squares
Sums of Squares and Cross-products: Type I
Effect sizes (Z) based on F distributions
Df SS MS Rsq F Z Pr(>F)
age_class 3 54.374 18.125 0.67526 105.35 11.655 0.001 ***
Residuals 152 26.149 0.172 0.32474
Total 155 80.523
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Call: lm.rrpp(f1 = csize ~ age_class, data = na.omit(gen.dtf))
Since a significant effect does show up, we may want to perform post-hoc (or pairwise) tests, to identify which pairs of age classes differ significantly.
## Pairwise comparisons:
<- pairwise(age.size, groups = na.omit(gen.dtf)$age_class)
pw.age.size summary(pw.age.size)
Pairwise comparisons
Groups: Juvenile Sub-adult Adult Older adult
RRPP: 1000 permutations
LS means:
Vectors hidden (use show.vectors = TRUE to view)
Pairwise distances between means, plus statistics
d UCL (95%) Z Pr > d
Juvenile:Sub-adult 0.7792960 0.6435238 1.9427871 0.018
Juvenile:Adult 1.8680152 0.6281543 4.1874735 0.001
Juvenile:Older adult 2.2017588 0.8945375 3.5249089 0.001
Sub-adult:Adult 1.0887193 0.2369915 5.3142343 0.001
Sub-adult:Older adult 1.4224628 0.6949962 3.1184015 0.001
Adult:Older adult 0.3337435 0.6849893 0.4125271 0.356
References
Footnotes
In practice, you might want to check the quality of this model, for instance by executing the command
plot(age.size)
here. But an in-depth discussion about linear models is beyond the scope of this course.↩︎