Momocs: Using R to analyze shape

We will go through the Momocs package. This is one of my favorite R packages and I have used it extensively to analyze leaf shape when I was a PhD student at Davis. For example in Martinez et al., 2015. My collegue at the time, Dan Chitwood introduced me to the package where he used it to create some stunning work analyzing modulations in shape in Grape Leaves and violins!

The package has changed a bit since I last visited. It appears as though Vincent Bonhomme has really embraced Tidyverse and has updated the Momocs package to reflect this. AND it appears that he is busily working on the Momocs 2.0 release (so stay tuned!).

Getting enviroment ready

library(Momocs)
library(tidyverse)
## Warning: package 'ggplot2' was built under R version 3.3.2
## Warning: package 'readr' was built under R version 3.3.2
## Warning: package 'dplyr' was built under R version 3.3.2

Examining Objects

The Momocs package come with some great example datasets that we can use for examples, so we will just use these to make things easier.

First: Coo Objects

A shape is described in euclidian space and the Shapes can be organized into a collection of coordinates.

a Coo object that carries:

A component named $coo, a list of shapes (as matrix.ces); most of the time, a component named $fac, a data.frame to store covariates, either factors or numerics;possibly, other components of interest.

## Check out one of the data sets:
shapes
## Out (outlines)
##   - 30 outlines, 836 +/- 255 coords (in $coo)
##   - 0 classifiers (in $fac): 
## # A tibble: 0 x 0
##   - also: $ldk
str(shapes)
## coo : List of 30
##  $ arrow   : num [1:888, 1:2] 200 199 198 197 197 196 195 194 193 192 ...
##  $ bone    : num [1:810, 1:2] 200 199 198 197 196 195 194 193 192 191 ...
##  $ buttefly: num [1:1077, 1:2] 200 200 200 199 199 199 198 198 197 197 ...
##  $ cat     : num [1:710, 1:2] 200 200 199 198 197 197 196 195 196 197 ...
##  $ check   : num [1:494, 1:2] 200 199 199 198 197 197 196 195 194 194 ...
##  $ cross   : num [1:806, 1:2] 200 200 199 198 198 197 197 196 195 195 ...
##  $ dog     : num [1:768, 1:2] 200 199 198 197 196 195 194 193 192 191 ...
##  $ fish    : num [1:943, 1:2] 200 199 198 197 196 195 194 193 192 191 ...
##  $ hand    : num [1:995, 1:2] 200 199 198 197 196 195 194 193 192 191 ...
##  $ hands   : num [1:1660, 1:2] 200 199 198 197 197 198 197 196 195 194 ...
##  $ heart   : num [1:554, 1:2] 200 199 198 197 197 198 199 198 198 197 ...
##  $ info    : num [1:514, 1:2] 200 199 198 197 196 195 194 193 192 191 ...
##  $ lady    : num [1:853, 1:2] 200 199 198 197 197 198 199 198 198 197 ...
##  $ leaf    : num [1:680, 1:2] 200 199 198 197 197 196 196 196 196 196 ...
##  $ leaf2   : num [1:792, 1:2] 200 200 201 200 200 200 200 200 200 199 ...
##  $ leaf3   : num [1:620, 1:2] 200 201 200 200 200 200 200 200 200 199 ...
##  $ leaf4   : num [1:1300, 1:2] 200 199 198 198 197 196 195 194 193 194 ...
##  $ moon    : num [1:571, 1:2] 200 199 198 197 196 195 194 193 192 191 ...
##  $ morph   : num [1:719, 1:2] 200 199 198 197 197 198 197 196 195 194 ...
##  $ parrot  : num [1:534, 1:2] 200 199 198 197 196 196 195 194 193 193 ...
##  $ penta   : num [1:957, 1:2] 200 199 198 197 197 196 196 197 196 196 ...
##  $ pigeon  : num [1:1240, 1:2] 200 199 198 197 196 195 194 193 192 191 ...
##  $ plane   : num [1:853, 1:2] 200 199 198 197 197 198 197 196 195 194 ...
##  $ puzzle  : num [1:778, 1:2] 200 199 198 197 197 198 199 198 197 196 ...
##  $ rabbit  : num [1:662, 1:2] 200 199 198 197 196 195 194 193 192 191 ...
##  $ sherrif : num [1:735, 1:2] 200 199 198 197 197 198 199 198 197 197 ...
##  $ snail   : num [1:930, 1:2] 200 199 198 197 196 195 194 193 192 191 ...
##  $ star    : num [1:1107, 1:2] 200 199 198 197 196 196 196 195 194 194 ...
##  $ tetra   : num [1:793, 1:2] 200 199 198 197 196 195 194 193 192 191 ...
##  $ umbrella: num [1:724, 1:2] 200 200 199 199 198 197 197 196 195 194 ...
## fac : Classes 'tbl_df', 'tbl' and 'data.frame':  0 obs. of  0 variables
## ldk :  list()
## Check out the coordinates of a single shape.
shapes[18] %>% head() 
##      [,1] [,2]
## [1,]  200   50
## [2,]  199   49
## [3,]  198   49
## [4,]  197   50
## [5,]  196   50
## [6,]  195   49

Visualizations

Since we are literally exploring shape, visualization of our data is extremely important. Momocs comes with a few different ways to visualize.

panel(shapes, names = TRUE) ## base R

cat <- shapes[4]
coo_plot(cat)

## #Rcatladies
coo_plot(cat, col="purple", main="Meow") 

More detail into the data structure of Momocs

As discussed previously, a dataset (group of shapes) in Momocs is described as a Coo. Once you apply a method to that you get a Coe.

Coo + Morphometric method = Coe (x; y) coordinates + appropriate method = quantitative variables

Break for Discussion on S3 objects

  • [ ] How many of you are coming from Python? Or use Python?
  • [ ] How many of you use S3 and know what it is in R?
  • [ ] How is S3 different from classes in Python?
  • [ ] What about S4 and S5 then?!

** What is the difference between S3 and 4?** - S3 can only dispatch on it’s first argument, whereas S4 can dispatch on multiple arguments. If you want to be able to write methods for function foo that should do different things if given an object of class “bar” or given objects of class “bar” and “foobar”, or given objects of class “barfoo” and “foobar”, then S4 provides a far better way to handle such complexities. (ref)

More on S3: * Read Advanced R The S3 object system Chapter

So, let’s delve a bit more into our data.

class(shapes)
## [1] "Out" "Coo"

Does that make sense?

Another example of a more popular class - the tibble

class(iris) 
## [1] "data.frame"
iris_tibble <- as_data_frame(iris)

## Tibbles have 3 classes
class(iris_tibble)
## [1] "tbl_df"     "tbl"        "data.frame"

Now back to Momocs….

## Let's check out the Cat Shape
cat <- shapes[4]
class(cat) # just a matrix
## [1] "matrix"
coo_plot(cat)

## Play with plot attributes
coo_plot(cat, col="pink", main="Meow")

## More attributes
?coo_plot

## Meeeeeow
coo_plot(coo_sample(cat, 125), points=TRUE, pch=20, main="125-pts Meow")

coo_plot(coo_sample(cat, 100), points=TRUE, pch=20, main="100-pts Meow")