10 Morphometric geometric demo: a between group analysis

This demo aims to give quick overview of the dispRity package (v.1.7) for palaeobiology analyses of disparity, including disparity through time analyses.

This demo showcases a typical between groups geometric morphometric analysis: we are going to test whether the disparity in two species of salamander (plethodons!) are different and in which ways they are different.

10.1 Before starting

Here we are going to use the geomorph plethodon dataset that is a set of 12 2D landmark coordinates for 40 specimens from two species of salamanders. This section will really quickly cover how to make a Procrustes sumperimposition analysis and create a geomorph data.frame to have data ready for the dispRity package.

## Loading geomorph

## Loading the plethodon dataset

## Running a simple Procrustes superimposition
gpa_plethodon <- gpagen(plethodon$land)
## Performing GPA
  |                                                                      |   0%
  |==================                                                    |  25%
  |===================================                                   |  50%
  |======================================================================| 100%
## Making projections... Finished!
## Making a geomorph data frame object with the species and sites attributes
gdf_plethodon <- geomorph.data.frame(gpa_plethodon,
                                     species = plethodon$species,
                                     site = plethodon$site)

You can of course use your very own landmark coordinates dataset (though you will have to do some modifications in the scripts that will come below - they will be easy though!).

## You can replace the gdf_plethodon by your own geomorph data frame!
my_geomorph_data <- gdf_plethodon

10.1.1 The morphospace

The first step of every disparity analysis is to define your morphospace.

Note that this is actually not true at all and kept as a erroneous sentence: the first step of your disparity analysis should be to define your question!

Our question here will be: is there a difference in disparity between the different species of salamanders and between the different sites (allopatric and sympatric)?

OK, now we can go to the second step of every disparity analysis: defining the morphospace. Here we will define it with the ordination of all possible Procrustes superimposed plethodon landmark coordinates. You can do this directly in dispRity using the geomorph.ordination function that can input a geomorph data frame:

## The morphospace
morphospace <- geomorph.ordination(gdf_plethodon)

This automatically generates a dispRity object with the information of each groups. You can find more information about dispRity objects here but basically it summarises the content of your object without spamming your R console and is associated with many utility functions like summary or plot. For example here you can quickly visualise the two first dimensions of your space using the plot function:

## The dispRity object
##  ---- dispRity object ---- 
## 4 customised subsets for 40 elements in one matrix:
##     species.Jord, species.Teyah, site.Allo, site.Symp.
## Plotting the morphospace

## Note that this only displays the two last groups (site.Allo and site.Symp) since they overlap!

The dispRity package function comes with a lot of documentation of examples so don’t hesitate to type plot.dispRity to check more plotting options.

10.2 Calculating disparity

Now that we have our morphospace, we can think about what we want to measure. Two aspects of disparity that would be interesting for our question (is there a difference in disparity between the different species of salamanders and between the different sites?) would be the differences in size in the morphospace (do both groups occupy the same amount of morphospace) and position in the morphospace (do the do groups occupy the same position in the morphospace?).

To choose which metric would cover best these two aspects, please check the Thomas Guillerme, Puttick, et al. (2020) paper and associated app. Here we are going to use the procrustes variance (geomorph::morphol.disparity) for measuring the size of the trait space and the average displacements (Thomas Guillerme, Puttick, et al. 2020) for the position in the trait space.

## Defining a the procrustes variance metric
## (as in geomorph::morphol.disparity)
proc.var <- function(matrix) {sum(matrix^2)/nrow(matrix)}
## The size metric
test_size <- test.metric(morphospace, metric = proc.var,
                         shifts = c("random", "size"))

## The position metric
test_position <- test.metric(morphospace, metric = c(mean, displacements),
                         shifts = c("random", "position"))

You can see here for more details on the test.metric function but basically these graphs are showing that there is a relation between changes in size and in position for each metric. Note that there are some caveats here but the selection of the metric is just for the sake of the example!

Note also the format of defining the disparity metrics here using metric = c(mean, displacements) or metric = proc.var. This is a core bit of the dispRity package were you can define your own metric as a function or a set of functions. You can find more info about this in the dispRity metric section but in brief, the dispRity package considers metrics by their “dimensions” level which corresponds to what they output. For example, the function mean is a dimension level 1 function because no matter the input it outputs a single value (the mean), displacements on the other hand is a dimension level 2 function because it will output the ratio between the distance from the centroid and from the centre of the trait space for each row in a matrix (an example of a dimensions level 3 would be the function var that outputs a matrix). The dispRity package always automatically sorts the dimensions levels: it will always run dimensions level 3 > dimensions level 2 > and dimensions level 1. In this case both c(mean, displacements) and c(mean, displacements) will result in actually running mean(displacements(matrix)). Alternatively you can define your metric prior to the disparity analysis like we did for the proc.var function.

Anyways, we can measure disparity using these two metrics on all the groups as follows:

## Bootstrapped disparity
disparity_size <-  dispRity(boot.matrix(morphospace), metric = proc.var)
disparity_position <- dispRity(boot.matrix(morphospace), metric = c(mean, displacements))

Note that here we use the boot.matrix function for quickly bootstrapping the matrix. This is not an essential step in this kind of analysis but it allows to “reduce” the effect of outliers and create a distribution of disparity measures (rather than single point estimates).

10.3 Analyse the results

We can visualise the results using the plot function on the resulting disparity objects (or summarising them using summary):

## Plotting the results
par(mfrow = c(1,2))
plot(disparity_size, main = "group sizes", las = 2, xlab = "")
plot(disparity_position, main = "group positions", las = 2, xlab = "")

## Summarising the results
##         subsets  n   obs bs.median  2.5%   25%   75% 97.5%
## 1  species.Jord 20 0.005     0.005 0.004 0.005 0.005 0.006
## 2 species.Teyah 20 0.005     0.005 0.004 0.005 0.005 0.006
## 3     site.Allo 20 0.004     0.004 0.003 0.003 0.004 0.004
## 4     site.Symp 20 0.006     0.006 0.006 0.006 0.006 0.007
##         subsets  n   obs bs.median  2.5%   25%   75% 97.5%
## 1  species.Jord 20 1.096     1.122 1.067 1.101 1.171 1.380
## 2 species.Teyah 20 1.070     1.105 1.033 1.065 1.143 1.345
## 3     site.Allo 20 1.377     1.407 1.315 1.381 1.448 1.530
## 4     site.Symp 20 1.168     1.221 1.148 1.187 1.269 1.458

Just from looking at the data, we can guess that there is not much difference in terms of morphospace occupancy and position for the species but there is on for the sites (allopatric or sympatric). We can test it using a simple non-parametric mean difference test (e.g. wilcox.test) using the dispRity package.

## Testing the differences
test.dispRity(disparity_size, test = wilcox.test, correction = "bonferroni")
## [[1]]
##                              statistic: W
## species.Jord : species.Teyah         3803
## species.Jord : site.Allo             9922
## species.Jord : site.Symp               14
## species.Teyah : site.Allo            9927
## species.Teyah : site.Symp             238
## site.Allo : site.Symp                   0
## [[2]]
##                                   p.value
## species.Jord : species.Teyah 2.076623e-02
## species.Jord : site.Allo     1.572891e-32
## species.Jord : site.Symp     2.339811e-33
## species.Teyah : site.Allo    1.356528e-32
## species.Teyah : site.Symp    1.657077e-30
## site.Allo : site.Symp        1.537286e-33
test.dispRity(disparity_position, test = wilcox.test, correction = "bonferroni")
## [[1]]
##                              statistic: W
## species.Jord : species.Teyah         6536
## species.Jord : site.Allo              204
## species.Jord : site.Symp             1473
## species.Teyah : site.Allo             103
## species.Teyah : site.Symp            1042
## site.Allo : site.Symp                9288
## [[2]]
##                                   p.value
## species.Jord : species.Teyah 1.053318e-03
## species.Jord : site.Allo     6.238014e-31
## species.Jord : site.Symp     4.137900e-17
## species.Teyah : site.Allo    3.289139e-32
## species.Teyah : site.Symp    2.433117e-21
## site.Allo : site.Symp        6.679158e-25

So by applying the tests we see a difference in terms of position between each groups and differences in size between groups but between the species.


Guillerme, Thomas, Mark N Puttick, Ariel E Marcy, and Vera Weisbecker. 2020. “Shifting Spaces: Which Disparity or Dissimilarity Measurement Best Summarize Occupancy in Multidimensional Spaces?” Ecology and Evolution.