Content Description

In addition to reading in data digitized in StereoMorph (see 01.1-Digitizing-Stereomorph) you may need to read in other types of GM-related files, or other files containing information about your specimens. Below are some basic instructions on how to do that.

Geomorph has several built-in functions to read landmark data files. Additionally, one can use standard IO functions in R to read in a text file. Geomorph also has the ability to digitize 2D or 3D data. For 3D, one can read in a 3D image in the form of a PLY file.

Read in Data from StereoMorph Files

In the previous lab, we learned how to digitize using StereoMorph. Here we take those datafiles and read them into geomorph using the readShapes function in StereoMorph combined with the readland.shapes function in geomorph. The result is an geomorphShapes object which may be used in downstream GM analyses.

library(geomorph)
## Loading required package: RRPP
## Loading required package: rgl
## Loading required package: Matrix
library(StereoMorph)
myShapes <- readShapes("Data/Fish-Shapes-ex")
mydata <- readland.shapes(myShapes)

mydata$landmarks$Fish1
##          [,1]      [,2]
## LM1  4.524372 -5.382586
## LM2  7.711429 -3.899458
## LM3 10.806832 -4.399389
## LM4 11.052632 -5.661714
## LM5  8.898764 -6.369949

Important detail! Specimens with missing data can still be read using the procedure above. In these cases, the landmark values will be replaced with NA, and can be estimated in subsequent data-processing steps using estimate.missing.


Read Landmark Data from Other Files

In addition to StereoMorph files, several other standard file formats are used to store GM data. Two of the more common file types are tps and nts files. These are text files that succinctly store landmark data in various types of matrices (open them in a text editor to gain simple understanding of the files). These were originally developed for the TPS series of software, and the statistics package NTSYS: hence their extension names. Geomorph provides functions to read in these type of files.

tps files have an inherent structure similar to the 3d-array data structure used in geomorph; whereas nts files correspond to a structure similar to two.d.arrays in geomorph. In both cases, data are read-in as a 3d-array. You can open both types of files in a text editor to get familiar with their structure. To read them into geomorph, use the corresponding functions: readland.tps and readland.nts.

Read Landmark Data from tps Files

mydata <- readland.tps("Data/salamanders.tps")
## 
## No specID provided; specimens will be numbered 1, 2, 3 ...
## 
## No curves detected; all points appear to be fixed landmarks.
str(mydata)
##  num [1:12, 1:2, 1:287] 8.82 9.29 5.24 2.17 1.91 ...
##  - attr(*, "dimnames")=List of 3
##   ..$ : NULL
##   ..$ : NULL
##   ..$ : chr [1:287] "1" "2" "3" "4" ...
dim(mydata)  # file contains 287 specimens with 12 landmarks each of 2D data
## [1]  12   2 287
mydata[,,1]
##            [,1]     [,2]
##  [1,]  8.818432 53.14680
##  [2,]  9.290848 52.18228
##  [3,]  5.235944 53.00901
##  [4,]  2.165240 51.47366
##  [5,]  1.909348 51.70987
##  [6,]  1.810928 51.80829
##  [7,]  1.102304 52.83186
##  [8,]  3.110072 54.48531
##  [9,]  6.023304 54.44594
## [10,]  8.916852 54.60342
## [11,] 10.649044 54.83962
## [12,] 14.015008 52.93028
mydata <- readland.tps("Data/salamanders.tps", specID="imageID") # Specify specimen labels
## 
## No curves detected; all points appear to be fixed landmarks.
str(mydata)
##  num [1:12, 1:2, 1:287] 8.82 9.29 5.24 2.17 1.91 ...
##  - attr(*, "dimnames")=List of 3
##   ..$ : NULL
##   ..$ : NULL
##   ..$ : chr [1:287] "USNM170655l " "USNM170656l " "USNM170657l " "USNM182599l " ...
mydata[,,1:2]
## , , USNM170655l 
## 
##            [,1]     [,2]
##  [1,]  8.818432 53.14680
##  [2,]  9.290848 52.18228
##  [3,]  5.235944 53.00901
##  [4,]  2.165240 51.47366
##  [5,]  1.909348 51.70987
##  [6,]  1.810928 51.80829
##  [7,]  1.102304 52.83186
##  [8,]  3.110072 54.48531
##  [9,]  6.023304 54.44594
## [10,]  8.916852 54.60342
## [11,] 10.649044 54.83962
## [12,] 14.015008 52.93028
## 
## , , USNM170656l 
## 
##           [,1]     [,2]
##  [1,]  8.89372 53.77644
##  [2,]  9.26840 52.77072
##  [3,]  5.56104 54.21028
##  [4,]  1.87340 52.75100
##  [5,]  1.28180 53.18484
##  [6,]  1.24236 53.32288
##  [7,]  0.84796 54.70328
##  [8,]  3.35240 55.76816
##  [9,]  6.29068 55.70900
## [10,]  8.87400 55.25544
## [11,] 10.74740 55.43292
## [12,] 14.39560 52.75100

Important detail! With tps files, missing data may be coded by using negative numbers for the landmarks. In these cases, readland.tps will prompt the user to determine whether the negative values are actual landmark coordinates, or whether they represent missing data. In the latter case, the landmark values will be replaced with NA, and can be estimated in subsequent data-processing steps using estimate.missing.

Read Landmark Data from nts Files

mydata <- readland.nts("Data/RATS.nts")
str(mydata)
##  num [1:8, 1:2, 1:164] -0.45 -0.59 -0.515 -0.33 0 0.145 -0.045 -0.26 -0.475 -0.28 ...
mydata[,,1]
##        [,1]   [,2]
## [1,] -0.450 -0.475
## [2,] -0.590 -0.280
## [3,] -0.515 -0.120
## [4,] -0.330  0.000
## [5,]  0.000  0.000
## [6,]  0.145 -0.395
## [7,] -0.045 -0.420
## [8,] -0.260 -0.465

Read Landmark Data from Morphologika Files

Another file type that is sometimes encountered is a Morphologika file; developed for the Morphologika package. One can read these files using geomorph also, using the function read.morphologika:

mydata <- read.morphologika("Data/mophologikaexample.txt")
str(mydata)
## List of 4
##  $ coords   : num [1:31, 1:3, 1:15] 16 15 15 16.3 15.9 ...
##   ..- attr(*, "dimnames")=List of 3
##   .. ..$ : NULL
##   .. ..$ : NULL
##   .. ..$ : chr [1:15] "Specimen 1" "Specimen 2" "Specimen 3" "Specimen 4" ...
##  $ labels   : chr [1:15, 1] "Female" "Female" "Female" "Female" ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:15] "Specimen 1" "Specimen 2" "Specimen 3" "Specimen 4" ...
##   .. ..$ : chr "Sex"
##  $ wireframe: num [1:40, 1:2] 1 22 6 24 15 15 17 15 5 23 ...
##  $ polygon  : num [1:37, 1:3] 7 8 9 9 6 11 10 11 13 12 ...
dim(mydata$coords)
## [1] 31  3 15
mydata$coords[,,1]
##        [,1]  [,2]  [,3]
##  [1,] 16.01 24.17 11.18
##  [2,] 15.00 24.86 11.16
##  [3,] 14.96 25.54 11.52
##  [4,] 16.26 24.36 11.48
##  [5,] 15.89 26.61 11.83
##  [6,] 17.16 25.33 12.35
##  [7,] 18.22 23.65 11.12
##  [8,] 18.77 23.75 11.21
##  [9,] 18.72 24.24 11.62
## [10,] 19.26 25.71 10.33
## [11,] 18.21 25.39 12.05
## [12,] 19.32 25.91 14.39
## [13,] 17.45 26.36 13.70
## [14,] 14.51 26.93 11.50
## [15,] 15.93 26.94 12.36
## [16,] 17.11 26.94 13.63
## [17,] 18.69 26.98 14.67
## [18,] 19.50 27.03 15.03
## [19,] 15.75 29.67 10.89
## [20,] 14.96 29.08 11.07
## [21,] 14.92 28.36 11.48
## [22,] 15.85 29.43 11.37
## [23,] 15.93 27.16 12.02
## [24,] 17.07 28.57 12.32
## [25,] 17.90 30.15 11.26
## [26,] 18.62 30.00 11.18
## [27,] 18.69 29.71 11.45
## [28,] 19.14 28.53 10.28
## [29,] 18.17 28.51 12.08
## [30,] 19.25 28.15 14.23
## [31,] 17.48 27.52 13.71

Read 3D image (PLY file)

Sometimes, we may wish to digitize directly from 3D images. These come in the form of ply files, and geomorph has the ability to read, and then digitize such images.

new <- read.ply("Data/Mandible.ply")
str(new)
## List of 5
##  $ vb           : num [1:4, 1:24700] -3.722 -1.233 -0.206 1 -0.368 ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:4] "xpts" "ypts" "zpts" ""
##   .. ..$ : NULL
##  $ it           : num [1:3, 1:50000] 17647 1 17626 21593 2 ...
##  $ primitivetype: chr "triangle"
##  $ material     : NULL
##  $ normals      : num [1:4, 1:24700] 0.3506 0.0769 -0.9334 1 -0.7159 ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:4] "xpts" "ypts" "zpts" ""
##   .. ..$ : NULL
##  - attr(*, "class")= chr [1:2] "mesh3d" "shape3d"

Read in text file (for landmarks or other variables)

Finally, one may have additional data, covariates, or other specimen information that one wishes to read into R for downstream analyses. As we are working in the R environment, one is free to do so using a variety of read functions. Below we provide an example for a data matrix, and a phylogeny:

food <- read.csv("Data/food.csv", header=TRUE, row.names=1)
str(food)
## 'data.frame':    69 obs. of  16 variables:
##  $ oligoch : num  -0.334 -0.334 -0.334 -0.334 -0.334 ...
##  $ gastrop : num  -0.212 -0.212 -0.212 -0.212 -0.212 ...
##  $ isopoda : num  -0.374 3.082 -0.374 -0.374 -0.374 ...
##  $ diplop  : num  -0.246 4.002 -0.246 -0.246 -0.246 ...
##  $ chilop  : num  -0.277 -0.277 3.552 -0.277 -0.277 ...
##  $ acar    : num  0.204 -0.501 -0.501 0.204 -0.501 ...
##  $ araneida: num  -0.374 -0.374 -0.374 2.17 -0.374 ...
##  $ chelon  : num  -0.309 -0.309 -0.309 -0.309 -0.309 ...
##  $ coleopt : num  0.718 0.392 -1.391 0.718 0.864 ...
##  $ collemb : num  -0.374 -0.374 -0.374 -0.374 -0.374 ...
##  $ diptera : num  -0.324 1.916 4.155 2.843 -0.324 ...
##  $ hymen   : num  0.935 -0.3 0.935 1.663 -0.7 ...
##  $ isopt   : num  -0.245 -0.245 -0.245 -0.245 -0.245 ...
##  $ orthopt : num  -0.273 -0.273 -0.273 2.959 -0.273 ...
##  $ larvae  : num  -0.645 0.873 -0.645 -0.645 3.646 ...
##  $ eggs    : num  -0.12 -0.12 -0.12 -0.12 -0.12 ...
food[1:2,]
##     oligoch    gastrop    isopoda     diplop     chilop       acar   araneida
## 1 -0.333567 -0.2116501 -0.3740649 -0.2462653 -0.2774757  0.2035222 -0.3740685
## 2 -0.333567 -0.2116501  3.0823626  4.0018112 -0.2774757 -0.5007004 -0.3740685
##       chelon   coleopt    collemb    diptera      hymen      isopt    orthopt
## 1 -0.3089659 0.7184250 -0.3735963 -0.3237473  0.9348487 -0.2453637 -0.2730511
## 2 -0.3089659 0.3918134 -0.3735963  1.9157772 -0.3004958 -0.2453637 -0.2730511
##       larvae       eggs
## 1 -0.6445006 -0.1203859
## 2  0.8725555 -0.1203859
library(ape)
mytree <- read.tree("Data/plethtree.tre")
plot(mytree)