With multivariate data, two or more ordered sets of levels of a
factor form a phenotypic trajectory in the multivariate dataspace. Such
trajectories represent phenotypic changes from level to level,
and may represent: sexual dimorphism (the difference between
male
and female
levels in a species),
phenotypic changes over space, or over ontogeny, or over evolutionary
time.
Phenotypic trajectories have multiple attributes which may quantified
and compared (see Collyer and Adams 2009; Adams and Collyer 2013). The
function trajectory.analysis
accomplishes this task.
Currently, trajectory.analysis
is found in the
RRPP
package, though it may be accessed through
geomorph
. There are two types of input: data in the form of
a factorial design where the trajectory points are estimated during the
analysis, or data can be input as sets of trajectories as may be found
in motion trajectories (sensu Adams and Cerney 2007).
library(geomorph)
## Loading required package: RRPP
## Loading required package: rgl
## Loading required package: Matrix
data(pupfish)
fit <- procD.lm(coords ~ Pop * Sex, data = Pupfish, iter = 999, print.progress = FALSE)
reveal.model.designs(fit)
## Reduced Full
## Pop 1 Pop
## Sex Pop Pop + Sex
## Pop:Sex Pop + Sex Pop + Sex + Pop:Sex <- Null/Full inherent in pairwise
anova(fit)
##
## 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)
## Pop 1 0.008993 0.0089927 0.15964 16.076 3.9997 0.001 **
## Sex 1 0.015917 0.0159169 0.28255 28.453 4.1103 0.001 **
## Pop:Sex 1 0.003453 0.0034532 0.06130 6.173 3.7015 0.001 **
## Residuals 50 0.027970 0.0005594 0.49651
## Total 53 0.056333
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Call: procD.lm(f1 = coords ~ Pop * Sex, iter = 999, data = Pupfish,
## print.progress = FALSE)
TA <- trajectory.analysis(fit, groups = Pupfish$Pop, traj.pts = Pupfish$Sex)
summary(TA, attribute = "MD") # Magnitude difference (absolute difference between path distances)
##
## Trajectory analysis
##
## 1000 permutations.
##
## Points projected onto trajectory PCs
##
## Trajectories:
## Trajectories hidden (use show.trajectories = TRUE to view)
##
## Observed path distances by group
##
## Marsh Sinkhole
## 0.04611590 0.02568508
##
## Pairwise absolute differences in path distances, plus statistics
## d UCL (95%) Z Pr > d
## Marsh:Sinkhole 0.02043082 0.01270556 2.66325 0.001
summary(TA, attribute = "TC", angle.type = "deg") # Correlations (angles) between trajectories
##
## Trajectory analysis
##
## 1000 permutations.
##
## Points projected onto trajectory PCs
##
## Trajectories:
## Trajectories hidden (use show.trajectories = TRUE to view)
##
## Pairwise correlations between trajectories, plus statistics
## r angle UCL (95%) Z Pr > angle
## Marsh:Sinkhole 0.7393716 42.32209 23.00833 3.67745 0.001
summary(TA, attribute = "SD") # No shape differences between vectors
##
##
## Cannot summarize trajectory shape differences for vectors.
# Retain results
TA.summary <- summary(TA, attribute = "MD")
TA.summary$summary.table
## d UCL (95%) Z Pr > d
## Marsh:Sinkhole 0.02043082 0.01270556 2.66325 0.001
# Plot results
TP <- plot(TA, pch = as.numeric(Pupfish$Pop) + 20, bg = as.numeric(Pupfish$Sex),
cex = 0.7, col = "gray")
add.trajectories(TP, traj.pch = c(21, 22), start.bg = 1, end.bg = 2)
legend("topright", levels(Pupfish$Pop), pch = c(21, 22), pt.bg = 1)
data(motionpaths)
fit <- lm.rrpp(trajectories ~ groups, data = motionpaths, iter = 999, print.progress = FALSE)
anova(fit)
##
## 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)
## groups 3 6520.9 2173.63 0.98608 849.85 21.229 0.001 **
## Residuals 36 92.1 2.56 0.01392
## Total 39 6613.0
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Call: lm.rrpp(f1 = trajectories ~ groups, iter = 999, data = motionpaths,
## print.progress = FALSE)
TA <- trajectory.analysis(fit, groups = motionpaths$groups, traj.pts = 5)
summary(TA, attribute = "MD") # Magnitude difference (absolute difference between path distances)
##
## Trajectory analysis
##
## 1000 permutations.
##
##
## Trajectories:
## Trajectories hidden (use show.trajectories = TRUE to view)
##
## Observed path distances by group
##
## 1 2 3 4
## 10.144421 6.557011 10.949722 10.097348
##
## Pairwise absolute differences in path distances, plus statistics
## d UCL (95%) Z Pr > d
## 1:2 3.58741011 1.317461 3.8913405 0.001
## 1:3 0.80530081 1.247854 0.7320629 0.250
## 1:4 0.04707265 1.284309 -1.6674019 0.950
## 2:3 4.39271092 1.262817 4.5955836 0.001
## 2:4 3.54033746 1.333765 3.8250970 0.001
## 3:4 0.85237346 1.251712 0.8703440 0.213
summary(TA, attribute = "TC", angle.type = "deg") # Correlations (angles) between trajectories
##
## Trajectory analysis
##
## 1000 permutations.
##
##
## Trajectories:
## Trajectories hidden (use show.trajectories = TRUE to view)
##
## Pairwise correlations between trajectories, plus statistics
## r angle UCL (95%) Z Pr > angle
## 1:2 0.9989147 2.669593 20.70022 -0.8792581 0.808
## 1:3 0.6122502 52.247611 22.06576 3.5215617 0.001
## 1:4 0.9996899 1.426827 20.81629 -1.3327426 0.901
## 2:3 0.6484120 49.578018 21.87022 3.3651369 0.001
## 2:4 0.9974452 4.096420 21.08371 -0.5446100 0.700
## 3:4 0.5923727 53.674438 21.14215 3.5973574 0.001
summary(TA, attribute = "SD") # Shape differences between trajectories
##
## Trajectory analysis
##
## 1000 permutations.
##
##
## Trajectories:
## Trajectories hidden (use show.trajectories = TRUE to view)
##
## Pairwise trajectory shape differences, plus statistics
## d UCL (95%) Z Pr > d
## 1:2 0.10279471 0.1855284 -0.15347678 0.551
## 1:3 0.10686382 0.1879151 -0.04044511 0.512
## 1:4 0.28213028 0.1881749 2.98789933 0.002
## 2:3 0.07843294 0.1862637 -0.91031401 0.814
## 2:4 0.36491114 0.1877718 3.94123541 0.001
## 3:4 0.35086211 0.1859428 4.01741549 0.001
TP <- plot(TA, pch = 21, bg = as.numeric(motionpaths$groups),
cex = 0.7, col = "gray")
add.trajectories(TP, traj.pch = 21, traj.bg = 1:4)