Quantcast
Channel: geomorph
Viewing all 38 articles
Browse latest View live

'read.morphologika' update

$
0
0

Update for read.morphologika function. This code will be added to geomorph on our next package update. This update fixes problems with message "object 'incoords' not found". Can be used with example data set mydata_readmorphologika. Here, I provide sample data in the Morphologika format composed of two specimens with 50 landmarks each, and with four data attributes. To import data attributes use matrix = TRUE, and make sure Morphologika attribute tags: '[labels]' and '[labelvalues]' are present, else use matrix = FALSE.The latter imports an array of landmarks only. Please see the geomorph manual for use of read.morphologika.


For example:

> setwd("C:/Programming")
> file<-"C:/Programming/mydata_readmorphologika.txt"
> mydata<-read.morphologika(file=file,matrix=T)
> head(mydata$dataframe)
  ID collector    date genus species     1      2      3      4      5      6      7      8      
1  1       EOC Jan2012     A       a 0.595 0.1679 0.2232 0.5028 1.2920 0.4237 0.5130 0.2047 
2  2       EOC Jan2012     B       b 0.743 0.3662 0.4697 1.3998 1.7515 1.8165 0.8139 2.8590 

on the other hand, "mydata$coords" provides one only with the landmarks coordinates.




Major update to the R-package geomorph

$
0
0

Hi Folks,

We have just completed a major update to the R-package geomorph:
software for geometric morphometric analyses in R.  Included are several new functions to  carry out additional GM analyses, as well as enhancements of existing functions and analyses.  The major highlights of these changes are:

- New function for the analysis of bilateral symmetry (both object and matching symmetry)
- Integration and modularity functions improved
- Comparison of modular partitions can allow more than two partitions
- New function for writing tps files
- New function for adjusting articulation angles
- Expanded functionality of motion and trajectory analysis function
- Additional data output options included in plotting and analysis routines

Full details of changes can be found in the geomorph manual (found on link below).

Geomorph can be downloaded from the CRAN website and package

Major update to the R-package geomorph

$
0
0

Hi Folks,

We have just completed a major update to the R-package geomorph:
software for geometric morphometric analyses in R.  Included are several new functions to  carry out additional GM analyses, as well as enhancements of existing functions and analyses.  The major highlights of these changes are:

- New function for the analysis of bilateral symmetry (both object and matching symmetry)
- Integration and modularity functions improved
- Comparison of modular partitions can allow more than two partitions
- New function for writing tps files
- New function for adjusting articulation angles
- Expanded functionality of motion and trajectory analysis function
- Additional data output options included in plotting and analysis routines

Full details of changes can be found in the geomorph manual (found on link below).

Geomorph can be downloaded from the CRAN website and package
repository:  http://cran.r-project.org/web/packages/geomorph/

Plot 3D Wireframes from Morphologika

$
0
0

Hi morphometricians,
A quick update: a function to plot Morphologika 3D wireframes using the package geomorph. This routine (or a version of it) will be included in our next package update under the "read.morphologika" function.

Enjoy!

Example:

library(geomorph)
# create an array of 10 random 3D specimens with 6 landmarks each to GPA
data<-array(abs(rnorm(18*10)),c(6,3,5))

# create a simple wireframe, e.g., pt1 connects to pt2, 2-to-3, 3-to-4,...etc.
wireframe<-matrix(c(1,2,2,3,3,4,4,5,5,6),ncol=2,byrow=T)
wireframe
mydata.gpa<-gpagen(data) #gpa landmarks

# choose the largest and/or smallest specimen
max<-which.max(mydata.gpa$Csize) #ID specimen w/largest CS
min<-which.min(mydata.gpa$Csize) #ID specimen w/smallest CS

# wireframe function: wirefun
# Input: 2 matrices: A & W
#  A is the procrustes residualsmatrix
#  W is the wireframe matrix
wirefun<-function(A,W,...){
  plot3d(A,type="n", aspect=FALSE,...)
  for(i in 1:dim(W)[1]){
    points3d(A[W[i,],],...)
    text3d(A[W[i,],],texts=W[i,],...)
    lines3d(rbind(A[W[i,1],],A[W[i,2],]),...)
  }
}

# Plot
wirefun(A=mydata.gpa$coords[,,1],W=wireframe,size=10,adj=2.5,col="black")

New fixed.angle() Function

$
0
0

Hello morphometricians,
Below you can find a new fixed angle function addressing the problem discovered by Fabio Machado in the morphmet mail archive. We will include this function in our next schedule update to geomorph.

Cheers,

Erik

CODE:

fixed.angle<-function(A,art.pt=NULL,angle.pts=NULL,rot.pts=NULL,angle=0){
if (length(dim(A))!=3){
stop("Data matrix 1 not a 3D array (see 'arrayspecs').") }
if(length(grep("-999",A))!=0){
stop("Data matrix 1 contains missing values. Estimate these first(see 'estimate.missing').") }
n<-dim(A)[3]; k<-dim(A)[2]; p<-dim(A)[1]
if (k!=2){
stop("Method presently implemented for two-dimensional data only.")}
if (angle>pi*2){
stop("Additional angle must be specified in radians.")}
if (angle< -pi*2){
stop("Additional angle must be specified in radians.")}
angl<-array(NA,dim=n)
for (i in 1:n){
A[,,i]<-t(t(A[,,i])-A[art.pt,,i])
angl[i]<- acos((A[angle.pts[1],,i]/sqrt(sum(A[angle.pts[1],,i]^2)))%*%(A[angle.pts[2],,i]/sqrt(sum(A[angle.pts[2],,i]^2))))
}
dev.angle<- (angl-mean(angl))+angle
if(A[angle.pts[1],1,1]<0){dev.angle<- -1*dev.angle}
for (i in 1:n){
r = matrix(c(cos(dev.angle[i]),-sin(dev.angle[i]),sin(dev.angle[i]),cos(dev.angle[i])),2)
A[rot.pts,,i] = A[rot.pts,,i]%*%r
}
return(A)
}


New geomorph function to digitize multiple 2d images

$
0
0

Hi Morphometricians!

We've enhanced geomorph's ability to continuously digitize multiple specimens' images in 2d, if these are within the same directory. This new function allows one to digitize 2d images without interruption. Thanks to Samuel Brown and Karl Fetter for suggesting the improvement.

We will incorporate this function in our next package update. I'm including demonstration code and a link to archaeological lithic specimens below. To replicate the excercise, first download zipped folder containing the images of 3 specimens from this link .

These images are of Middle and Upper Paleolithic tools from excavations at Tor Sadaf, Jordan, conducted by Dr. Nancy Coinman

Cheers,

Erik

DIgitizing instructions can be found in the geomorph package manual (pp. 11-12)


# create a folder named "2d_midpaleolithic_specs" and unzip images there
# dir.create("C:/2d_midpaleolithic_specs/")

# then set the directory to where the images are located
> setwd("C:/2d_midpaleolithic_specs/")

> # create the file name character vector named "specs"
> # ensure that only ".jpg" files are called (for future reference)
> specs<-list.files()[grep(".JPG",list.files())]
> specs
[1] "spec100.JPG" "spec143.JPG" "spec164.JPG"

> # source the function "digitize2d.multi()"
> source(url("http://www.people.fas.harvard.edu/~eotarolacastillo/software/digitze2dmulti.R"))

> # To begin digitizing images call the function with with:
> diged.imgs <- lapply(specs, digitize2d.multi, nlandmarks=3, scale=1)
Loading required package: jpeg
set scale = 1

# to set the scale, use the mouse to digitize the length of the scale in the image


select landmarks 1:3

# to select landmarks, "point-and-click" at the locations of the landmarks of interest. in this case, the ends of a preparation platform and the tip were selected.


set scale = 1
select landmarks 1:3

(figure not shown)
set scale = 1
select landmarks 1:3

# here is another example using an upper-paleolithic blade.


Update to curves2d()

$
0
0

Dear morphometricians,

Below you will find an update to our function for digitizing curves in 2d: curves2d(). This solves a problem with the function plotting landmarks and semilandmarks out of sequence. To use it, you can "source()" the code from a directory, or copy and paste it during digitizing.


Cheers,

Erik

CODE:

curves2d<-function(file, nsliders){
lm<-readland.nts(spec.name<-basename(file))
lm <- matrix(lm, ncol = dim(lm)[2], byrow=T)
spec.name<-unlist(strsplit(spec.name, "\\."))[1]
plot(lm[,1],lm[,2],cex=1,pch=21,bg="white")
text(lm[,1],lm[,2],label=paste("LM",1:dim(lm)[1]),adj=.5,pos=1)
selected<-matrix(NA,ncol=3,nrow=nsliders)
select<-NULL
for(i in 1:nsliders){
for(j in 1:3){
select<-identify(lm,n=1,plot=FALSE,cex=5,pch=25)
selected[i,j]<-select
if(j==2){
points(lm[select,][1],lm[select,][2],cex=1.5,pch=19,col="red")
arrows(lm[selected[i,j],][1],lm[selected[i,j],][2],lm[selected[i,j-1],][1],lm[selected[i,j-1],][2]
,col="red",lwd=2,length=.15)
} else {
points(lm[select,][1],lm[select,][2],cex=1.1,pch=19,col="blue")
}
if(j==3){
arrows(lm[selected[i,j],][1],lm[selected[i,j],][2],lm[selected[i,j-1],][1],lm[selected[i,j-1],][2]
,col="red",lwd=2,length=.15,code=1)
#lines(rbind(lm[selected[i,j],],lm[selected[i,j-1],]),col="red",lwd=2)
} else { NA
}
}
}
output<-selected
cat(paste('"sliders',sep=""),file=paste("sliders.nts",sep=""),sep="\n")
cat(paste(1,dim(output)[1],3,0, "dim=3"),file="sliders.nts",sep="\n",append=TRUE)
write.table(output,file="sliders.nts",col.names = FALSE, row.names = FALSE,sep=" ",append=TRUE)
return(list(sliders=output))
}


Update to read.ply() and associated digitizing functions

$
0
0
Dear morphometricians,
Geomorph 1.1-4 has been recently uploaded to CRAN. Please update your R package list or go here to download the latest version. The news section highlights the following changes:

 CHANGES IN GEOMORPH VERSION 1.1-4

NEW FEATURES
o Enhanced plotting of ply files in read.ply()
o digitsurface(), buildtemplate(), plotspec(), digitfixed(), and digitcurves()* now support ply file input

OTHER CHANGES
o Minor changes to plot window options in plotting functions
o Change to magnification factor usage in plotRefToTartget()

I will highlight the new read.ply() function and how this affects you, the user.
By employing the plotting capabilities of the rgl library, read.ply() now reads in information about color information of the ply file, and plots the vertices with their adjoining faces in an rgl window. The function has a new user option ShowSpecimen(=TRUE as default) that allows the user to view or not the ply file on input. The input file is an object of Mesh3d (and thus Shape3d) class, see rgl for details
myply <-read.ply("myply.ply", ShowSpecimen=T)
myply$vb # the vertex coordinates
myply$it # the face information
myply$material # color information of the vertices


Enhancement of ply file plotting in geomorph's function read.ply() and 3D digitizing functions digit.fixed(), buildtemplate(), digitsurface() and plotspec(). Screenshot from rgl window during digit.fixed(). Scallop shell surface mesh made by a NextEngine 3D laser scanner.

The geomorph 3D digitizing functions now take advantage of this enhanced plotting capability. In doing so, the digitizing functions are improved because the plotted faces (and color in available) make the mesh easier to see, and more intuitive digitizing (as if you had the specimen in your hand and a microscribe to digitize the landmarks). 

digit.fixed("myply.ply", 5, pntsize=1)
The option pntsize in digit.fixed(), digitsurface(), buildtemplate(), and plotspec() allows the user to change the size of the plotted vertex points, an accessibility improvement to the code.

Also, taking advantage of a rgl function bringtotop(), now when the user types Y or N in the console to accept or reject the landmark they digitizied, the focus automatically goes back to the rgl window in anticipation of the next landmark.

The changes to read.ply() function also invite easier transitions between our package geomorph and others in R (for example the package Morpho). Because our 3D digitizing functions use Mesh3d and Shape3d objects, the user is not restricted to using ply files and our read.ply function (although this is the only file type we can provide user support), but they can also input 3D mesh files of other formats which have been read in from user own functions or other packages and saved as Mesh3d/Shape3d objects using rgl functions qmesh3d() and tmesh3d().

But don't worry, if you don't have a fancy colored ply file, or a file with faces (only the vertex information), read.ply() will still work for you. And if you input the vertex information on your own, read.ply() will take it gladly, just make sure it is a matrix of number vertices by 3 (x,y,z), so that each vertex coordinates are on a separate row.

We invite you to run the example in plotspec() using data(scallopPLY) and view for yourselves the enhanced plotting and digitizing capabilities of geomorph!

Other improvements:
The 2D digitizing functions curves2d() and digitize2d() have also had a few tweaks to improve functionality and geomorph1.1-4 now contains the code posted here in June.

As always, we welcome your input. Please let us know how you are doing using these and other geomorph functions.

Emma

UPDATE 15:00 cdt Oct 10 2013:
If you have a ply file with no color, you easily can assign a color to it in R as follows:
myply$material <- "grey" # using color word
myply$material <- "#FCE6C9" # using RGB code (see here for codes)
Note that I have set the default in read.ply() to grey, but the digitizing functions use the default color for plotting by rgl, which is black, and is not very easy to look at while digitizing!

* Slight error: function digit.curves() has not been altered for ply plotting capabilities, our mistake.


Geomorph 1.1-5 Now available!

$
0
0
Geomorph users,

We have uploaded version 1.1-5 to CRAN. The windows binary has been compiled and the tarball is available. The MAC OSX binary may take a few days (mac users can install the package from source using the tar.gz file). The PDF of helpfiles has not yet been updated - as of 10am CST Dec 13 2013.

In this new version, there are some edits to existing function as well as a new function! In summary:


  • The 2d and 3d digitizing functions have had their helpfiles spruced up! Video tutorials of digitizing in geomorph are coming later this month.
  • The functions digit.curves and curves2d have got new names: define.sliders.2d and define.sliders.3d. This should help clear up any confusion regarding what these functions do (details below).
  • For better visualization, functions plotAllometry and plotTangetSpace now have a "group" option, where the groups are plotted in different colors. Simply type groups = mygroup, where 'mygroup' is a vector containing the labels for each specimen (order must match order of specimens). The plotTangetSpace example now contains this option, so go check it out!
  • There's a new function!compare.evol.rates - the function compares rates of morphological evolution for two or more groups of species on a phylogeny, under a Brownian motion model of evolution. This function is based on a new method in Systematic Biology: Adams 2014 Quantifying and Comparing Phylogenetic Evolutionary Rates for Shape and other High-Dimensional Phenotypic Data.(doi: 10.1093/sysbio/syt105) first published online 12/10/13. This approach generalizes comparative methods for single-valued traits (e.g., O’Meara et al. 2006) for the case of high-dimensional multivariate data.

define.sliders.2d and define.sliders.3d

These two functions are designed to aid the user in creating a landmark address file (curveslide.csv), within which landmarks that will be treated as sliding semilandmarks during Generalized Procrustes superimposition are defined. The input is a matrix of 2d or 3d coordinates for one specimen. These coordinates can be digitized with the geomorph digitizing functions, or they can come from external digitizing software.

For both functions, the procedure is as follows:
Say we have a file, spec, with 10 landmarks distributed around a closed-boundary of an object. 1 to 6 are fixed (type I landmarks) and 7 to 10 are semilandmarks.
nsliders = 4 (number of the digitized landmarks in spec to be defined as curve sliding semilandmarks).

Landmark '7' is the first sliding semilandmark, and it will slide between landmarks 6 and 8 along a curve. Then select landmark 6, then 7 then 8. The file created will have the first row will be:
 6  7  8
Landmark 8 is also a slider, to slide between 7 and 9, so select 7 then 8 then 9. Now the file has a new line:
 6  7  8
 7  8  9
Repeat the process until nsliders have been defined. Then you have a curveslide.csv file with nsliders lines that looks like this:
 before slide after
 6  7  8
 7  8  9
 8  9  10
 9  10 1
See that because the landmarks of our specimen were digitized on a closed-boundary circuit, the last slider slides between 9 (a slider) and 1 (a fixed landmark).

In define.sliders.3d, an extra option is available. If the matrix of coordinates also contains landmarks that are surface sliding semilandmarks (as made using buildtemplate and digitsurface), then the file of landmarks addresses (surfslide.csv) should be in the working directory and choose surfsliders = TRUE
So for example spec has 20 landmarks: 1 to 6 are fixed (type I landmarks) and 7 to 10 are curve sliding semilandmarks and 11 to 20 are surface sliding landmarks. Then surfside.csv is a vector: 11 12 13 14 15 16 17 18 19 20.
For 2d and 3d digitizing, It is good practice to digitize all of the fixed (type I landmarks) first, then the curve slider semilandmarks and surface slider semilandmarks. 
More information on surface and curve sliding semilandmarks can be found in the geomorph help files and references within.

Happy Holidays!

Emma

Geomorph and MacOS X

$
0
0
Happy New Year to all Geomorph users,

I have received a few emails from Mac users wanting to update to the new version of Geomorph. Unfortunately there is still a lag on the CRAN repository for a MacOS X binary of version 1.1-5. While this is a nuisance, there is a work around.

The package source 'tarball' can be installed in R or RStudio: Download the tarball, and then navigate to the Package Installer and choose the Local Source Package option. To do this, you will need to make sure you have C and Fortran compilers installed (see below).

First, read thoroughly the R FAQs. The process has become simpler with newer versions of R, but still involves two main downloads: Go to the tools page to install gofortran. Also install the free Xcode 5 (from the App store) - this is the developer tools package. Once installed XQuartz needs to be open when running R.

If you have any problems, please make sure you have the current version of all software being used (R, Xcode, gofortran). We hope that CRAN will upload the Mac binary soon.

Thanks,
Emma


Tips & Tricks 1: Averaging Data By Group

$
0
0
I thought it would be helpful to new users of Geomorph and R to discuss some tips and tricks for manipulating morphometric datasets in R. So I am starting a series called "Tips & Tricks". These will be published as I think of them, and assume you have already inputted your data into R using geomorph functions, such as readland.nts, readmulti.nts, readland.tps, read.morphologika, or simple read.csv. Remember that the read... functions in Geomorph turn the morphometric data into a 3D array (like a stack of filing cards; each card representing an individual and having on it a p landmarks by k dimensions matrix of coordinates). 

Exercise 1 - How to average a dataset of morphometric data (shape data) by group.

Lets start with the input objects. We have a 3D array of 30 specimens shape data (p by k coordinate data) called data, and a grouping variable group, which is of class factor, with m levels. We want to average the morphometric data by these m levels.

[Here you should familiarise yourself with the factor functions, such as  as.factor() and levels(), see here for more details].

The first thing to do is to change the 3D array data into a 2D array (n by p x k) with geomorph function two.d.array()

  x <- two.d.array(data)

I will explain a long-winded way of doing things, which is intuitive but cumbersome. Then I will show a simple one line version that utilises two useful base functions in R, which make life much simpler!

1) Set up the output matrix, which will be filled by a for loop:

  p <- dim(data)[1] # the number of landmarks
  k <- dim(data)[2] # the dimensions of the coordinates
  Y <- array(NA, dim=c(p,k,length(levels(group))) #new empty array to fill
  dimnames(Y)[[3]] <- levels(group)# set group levels as new names

Now write a for loop that subsets the 2D array by group and calculates the mean shape using geomorph function mshape():

for (i in 1: length(levels(group))){
grp <- x[which(group==levels(group)[i]),]# makes a subset 2D array with only specimens of the ith group by using which().
foo <- arrayspecs(grp ,p,k, byLand=F) # turn back into an 3D array
    Y[,,i] <- mshape(foo) # place into the new 3D array
  }
Since mshape() requires a 3D array, the switching between 2D and #D is necessary, but cumbersome. While this procedure is very long-winded, it does allow you to get used to manipulating arrays, and learn how to do procedures by levels of a grouping factor.

But if you look under the hood, you see that mshape is simply taking the means of the rows and columns of the matrix. This leads us to:

2) This for loop can in fact be replaced with one line:
means <- rowsum(x, group)/as.vector(table(group))# rowsum() is a simple base function to get the sum of the rows, while table() is a great function for getting group sizes (group n).
Y <- arrayspecs(means ,dim(data)[1],dim(data)[2], byLand=F)# then all you have to do is put the averaged data back into an 3D array.

Both ways produce the same result. As is often the case with R, 'there are many ways to skin a cat'! The first example works with functions you likely already know, and allows you to become more proficient with writing your own for loops and searching or subsetting with which().  The second example shows you that looking deeper into R base functions will uncover little gem functions, which make our life much easier!

Enjoy averaging by group!

Emma




Tips & Tricks 2: Deleting Specimens and Landmarks

$
0
0
Today's exercise is nice and simple, and allows you to get used to manipulating datasets in R.

Exercise 2 - How to delete specimens or landmarks from a dataset of morphometric data (shape data).

When you load your shape data into R with Geomorph (with the read... functions), it will typically be in a 3D array format (class array). Recall that a 3D array is akin to having a p landmarks by k dimension matrix for each individual specimen arranged on separate filing cards, and these are stacked up into n dimensions.
For example:
class(mydata)
[1] array
dim(mydata)
[1] 12 2 40 # This means there are 12 landmarks, in 2 dimensions, and 40 specimens.
Imagine 40 filing cards with a 12 by 2 matrix on them. You get the idea.

Some analyses in geomorph require the dataset to be a 2D array, which is n rows and p*k columns.
mydata.2D <- two.d.array(mydata)
class(mydata.2D)
[1] matrix
dim(mydata.2D)
[1] 40 24 # This means there are 40 specimens and 24 variables (12 * 2).

R has a wonderful built in functionality to access parts of these arrays and matrices. This is why we don't write functions in Geomorph to add/delete specimens, or landmarks, because CRAN did it for us!
I'll give you a quick overview of indexing as it applies to deleting specimens. (You can read more about indexing here (section 3.4).)

Take the 2D array, mydata.2D. Say specimen 7 is an outlier, too juvenile perhaps, or damaged.
mydata.2D.new <- mydata.2d[-7,] # here we remove row number 7.

Or if you know specimens 7 through to 10 are no good to use:
mydata.2D.new <- mydata.2d[-(7:10),]

For several specimens, or those out of sequence:
omit <- c(5,7, 11, 30) # make a vector of the specimen numbers to delete
mydata.2D.new <- mydata.2d[-omit,]

For the 3D array, it is equally simple. Using the same specimen examples as above:
mydata.new <- mydata[,,-7]
mydata.new <- mydata[,,-(7:10)]
mydata.new <- mydata[,,-omit] # note this time, we are accessing the third position in the array, the "card", whereas above we were accessing the row of the matrix.

This same technique can be applied to landmarks.

In the 2D array: Landmark 5 is missing from some specimens. So let's delete it.
Since the landmark data are arranged x1 y1 x2 y2 ... the landmark we want to delete is in:
delete <- c((5*2), (5*2+1)) # position 10 and 11
mydata.2D.new <- mydata.2d[,-delete)]
dim(mydata.2D.new)
[1] 40 22 

Note that this will change the numbering of the landmarks.

In a 3D array, this is simpler:
mydata.new <- mydata[-5,,)] # this removes landmark 5 from each "card"
dim(mydata.new)
[1] 11  2 40

Getting adept with indexing is a valuable skill with R. Have fun deleting!

Emma









Geomorph 1.1-6 Now Available!

$
0
0
Geomorph users,

We have uploaded version 1.1-6 to CRAN. The windows and mac binaries have been compiled and the tarball is available.

The issue of the Mac OS X installers has been resolved. The problem stemmed from a dependancy (to JPEG), which was lagging behind for Mac binaries. We thank the curators for helping us with this issue.

Version 1.1-6 does not contain any new functions. It fixes a few small inconsistencies in the code and helpfiles (listed below). The most important update deals with two functions missing from the NAMESPACE in 1.1-5. We apologize for any problems this may have caused.
Also:
  • Minor I/O enhancements in readmulti.nts()
  • Minor I/O enhancements in define.sliders.3d() to allow sliders to be in any order
  • Simplified pPsup (original code from J. Claude) to not include size re-scaling by beta (underlying function used in trajectory.analysis() only)
  • Added name.check for groups in compare.evol.rates()
Emma

Geomorph Version 2.0 Now Available!

$
0
0
Geomorph users,

We have uploaded version 2.0 to CRAN. The windows and mac binaries have been compiled and the tarball is available.

Version 2.0 comes with substantial changes and new features: 

New functionphylo.pls()for assessing the multivariate association between two blocks of variables in a phylogenetic context. This is based on a new paper by Adams and Felice

New functiontwo.b.pls() for assessing the multivariate association between two blocks of variables

New functionmorphol.disparity() to compare Procrustes variance disparity among groups

New method for functionphysignal() to calculate phylogenetic signal using a generalized Kappa statsitic. This is based on a new paper by Adams (Systematic Biology in press)

F-ratios and R-squared values added to output of ProcD.lm()

3D Visualizations now include "surface" option to view shape deformation as warped mesh3d surfaces in the following: plotRefToTarget(), plotTangentSpace(), plotAllometry(), and bilat.symmetry(). 

New I/O functions: warpRefMesh() to create a mesh3d surface that represents the mean shape, findMeanSpec() to assist in choosing a template ply file for use with warpRefMesh() that identifies specimen closest to the mean shape, and defline.modules() to interactively assign landmarks to modular partitions (currently 2D only)

Generalized data input to allow 3D array or 2D matrix of data added to the following analysis functions: compare.evol.rates(), phylo.pls(), morphol.integr(), two.b.pls(), physignal(), and plotGMPhyloMorphoSpace()

Ability to input univariate data added to compare.evol.rates() and physignal()


Verbose output = T/F added to the following functions: bilat.symmetry(), phylo.pls(), two.b.pls(), morphol.integr(), plotAllometry(), plotTangentSpace(), physignal(). This new option allows the user to decide what information should be returned. Verbose=F, the default, returns the basic output, usually the test statistic and P-value.Verbose=T, returns new datasets, shape scores and more. 

As always, all the changes and additions for this version can be found in the geomorph news file.

Emma




Geomorph 3D Visualization

$
0
0
Dear geomorph users,

version 2.0 of geomorph brings new developments in how shape deformations from 3D coordinate shape data can be viewed. We have implemented warping of 3D surface files (e.g., .ply files), which allows the user to visualize the shape deformations along Principal Component axes, Multivariate Regression slopes, Partial Least Squares axes and group differences, to name a few.

The new function warpRefMesh() reads in a .ply file and landmark coordinates associated with this specimen, and uses the thin-plate spline method (Bookstein 1989) to warp the mesh into the shape defined by a second set of landmark coordinates, usually
those of the mean shape for a set of aligned specimens. 

When using this function for warping, it is highly recommended that the mean shape (derived from the users sample using mshape()) is used as the reference for warping (see Rohlf 1998). 

The workflow is as follows:
1. Calculate the mean shape using mshape()
2. Choose an actual specimen to use for the warping - the specimen used as the template for this warping is recommended to be one most similar in shape to the average of the sample, but can be any reasonable specimen - do this by eye, or use findMeanSpec()
3. Warp this specimen into the mean shape using warpRefMesh()
4. Use this average mesh where it asks for a mesh= in the analysis functions and visualization functions (plotTangentSpace(), plotAllometry(), bilat.symmetry(), and plotRefToTarget()).

> ref <- mshape(data)
> refmesh <- warpRefMesh("plyfile.ply", data[,,1], ref, color=NULL, centered=T) # here the digitized coordinates for specimen plyfile are the first in the array

warpRefMesh plots the imported mesh (below left) and the new warped mesh that represents the ref shape (mean shape, below right):




















The function also returns to object refmesh a mesh3d object of this new warped mesh, which can be used in any function in geomorph where mesh= is an option. For example,
> plotTangentSpace(data, axis1 = 1, axis2 = 2, warpgrids=T, mesh= refmesh)




















Here, we see that function plotTangentSpace returns the shape deformation matching the most negative and most positive shape along the axis specified in axis1=.

The warping capabilities in geomorph are similar to those done using IDAV Landmark (e.g., Drake and Klingenberg 2010), but of course the benefit is that now all your analyses and visualizations can be done in R.

Emma

Tips & Tricks 3: Ordering Datasets Alphabetically

$
0
0
Today's exercise is another nice and simple one, and allows you to get used to manipulating datasets in R.

Exercise 3 - How to reorder the dataset alphabetically by specimen name.

Say you have a 2D array dataset with specimen names (here species) as the row names of species data 
(I have jumbled up the species of geomorph's data(plethspecies) for illustrative purposes)
                      [,1]         [,2]      [,3]        [,4]        [,5]        [,6]       [,7]       [,8]
P_cinereus       0.2170911 -0.000276374 0.2592660 -0.05280429 -0.01647032 -0.01611658 -0.2561081 -0.1222936
P_nettingi       0.2182337 -0.007565857 0.2550516 -0.07272572 -0.02249780 -0.02076196 -0.2448233 -0.1139709
P_hoffmani       0.2157877 -0.002494932 0.2538394 -0.05447151 -0.02241651 -0.01523319 -0.2502073 -0.1157858
P_virginia       0.2155726  0.001949692 0.2575607 -0.05119322 -0.03633579 -0.01912463 -0.2491259 -0.1158853
P_serratus       0.2086011  0.005599942 0.2474015 -0.05370812 -0.02172973 -0.01504136 -0.2538781 -0.1217033
P_electromorphus 0.2094443 -0.001604654 0.2502967 -0.05379854 -0.02843583 -0.01551027 -0.2536498 -0.1242497
P_shenandoah     0.2164737  0.003217350 0.2621750 -0.04501284 -0.01737607 -0.01863017 -0.2564934 -0.1198138
P_hubrichti      0.2154898 -0.000836868 0.2522478 -0.06473866 -0.03708750 -0.02215923 -0.2497272 -0.1155023

P_richmondi      0.2115516 -0.005225566 0.2499019 -0.06172998 -0.02749914 -0.01938572 -0.2553196 -0.1238423
...

and you want to order them alphabetically by name, this is simply:

> y <- y[order(rownames(y)),] # where y is a 2D array of your data

The equivalent for your 3D array is:
> Y <- Y[,,order(dimnames(Y)[[3]])] # where Y is a 3D array

Easy! In these two examples, the specimen names are in the data matrix itself. But what if you want to sort by other classifiers?

Using this construct, you can be smarter with ordering and sort by any other classifier, simply by adding in the classifying vector as x in Y[,,sort(x)]
for example,

> data(plethodon)
> Y <- plethodon$land
# the individual specimens in this dataset are in a random order. To sort the individuals by species names as given by the classifier $species:
> plethodon$species 
 [1] Jord  Jord  Jord  Jord  Jord  Jord  Jord  Jord  Jord  Jord  Teyah Teyah Teyah Teyah Teyah Teyah Teyah Teyah
[19] Teyah Teyah Jord  Jord  Jord  Jord  Jord  Jord  Jord  Jord  Jord  Jord  Teyah Teyah Teyah Teyah Teyah Teyah
[37] Teyah Teyah Teyah Teyah
Levels: Jord Teyah

> Y[,,order(plethodon$species)] # where Y is a 3D array

Manipulating datasets in R is challenging at first, but is easy once you know the tricks!

Emma

Update 19th April: The original version  of this post used the function sort() rather than order(). While they both came to the same conclusion in these examples, I should explain the difference between them, and why I changed them. sort() returns an ordered vector of the object within the parentheses, while order() returns the addresses of the elements within object if they would be ordered. order() therefore is more often used within Y[] than on its own.

Geomorph 2.1 Now Available!

$
0
0
Geomorph users,

We have uploaded version 2.1 to CRAN. The windows and mac binaries have been compiled and the tarball is available.

Version 2.1 comes with some small changes and new features: 

Mike Collyer has now officially joined the geomorph team!

New functions 
pairwise.slope.test() to compare slopes of regression lines. This is based on a new paper by Mike Collyer and colleagues (Collyer, M.L., D.J. Sekora, and D.C. Adams. 2014. A method for analysis of phenotypic change for phenotypes described by high-dimensional data. Heredity. In Press) 


procD.pgls()to assess high-dimensional ANOVA and regression models in a phylogenetic context. This is based on a new paper by Dean Adams (Adams, D.C. 2014. A method for assessing phylogenetic least squares models for shape and other high-dimensional multivariate data. Evolution. In Press)

New features
We have added residual randomization options added to procD.lm()and pairwiseD.test(), as described in Collyer et al. 2014.

We have also enhanced capabilities of the digitizing function
digitize2d(). The function now reads multiple images and outputs a TPS file. It can be used with missing data. And a digitizing session can be restarted where previous session stopped. In this overhaul, we have fixed a bug in the previous digitize2d() regarding the scale. If any users think they are affected by this, please contact Emma (sherratt[at]iastate[dot]edu).

Emma

Free Geometric Mophometrics - a Summary

$
0
0
I have seen a few questions floating around the interwebs recently from people starting up in morphometrics and wondering what is the best software to use. I am inspired by my fellow 3D expert Dr. Peter Falkingham's blog post on free software choices for working with 3D slice data and surface models (acquired by micro-CT, laser/photo surface scanners or Photogrammetry). I though i'd write a complementary piece on free software for collecting landmark-based morphometric data.

Why free?
Software development is hard work, so it is understandable that it costs money. However, sometimes the cost of the software is so high it makes it completely inaccessible - and software that isn't used is not helpful for anyone. As Peter so eloquently put it, 

"using freely available software where possible means that my skills are transferrable to different workplaces. It means grant money can be spent on hardware and materials, rather than software licenses. And it means that when I train students in the software I use, they can take those skills wherever they go and not have to re-learn a different proprietary package to do something they have already been doing for weeks/months/years."

And this is my stance also - I spent a good portion at the start of my PhD trying to find adequate ways of getting 3D landmark data from my CT scans of caecilian skulls for free, because I didn't want to be tied to the CT facilities computers. Most importantly though, I believe in Science being accessible and affordable. And the good news is Morphometrics is more free than ever!

Geomorph is, of course, free, and available on CRAN, which is also free! I will be highlighting several geomorph features here. But many people for good reasons prefer more GUI-based applications for their data collection, and so I will present a brief overview of some common and easy to find options.

2D landmark data collection

Geomorph's function digitize2d() allows users to read in one .jpeg file after the next, set the scale and place the landmarks. Then it conveniently write a .TPS file of the coordinate data, which can then be easily read into geomorph (using readland.tps()) . One benefit of using geomorph and R is that it works on Mac, Windows and Linux. 

tpsDIG distributed by F.James Rohlf on the SUNY Morphometrics website, is the classic 2D landmark data software. A good video tutorial of how to use this software is found here. The GUI interface is very user-friendly, and it facilitates collecting both landmark data and also curves and outlines. TpsDIG is only available for Windows, but is not too RAM-demanding so can be run on Virtual machines (a good free virtual machine is VirtualBox). TpsDIG also writes .tps files (obviously!).

ImageJ from NIH is the go-to image manipulation and measurement tool, a must for any morphometrician. It also runs on Mac, Windows and Linux. It isn't specifically for 2D landmark data, so it can be daunting to start with because there are so many other features. But it is simple: Import an image; measure the scale using the line tool and cmd+M, the go to Analyze > Set scale and set what the distance in pixels is in mm. Then you can use the point tool to click and place landmarks. The coordinates are printed in the results window, and need to be copied into an excel sheet (or your freeware equivalent) and saved as a text file. For importing into geomorph, it's best to save it as one row per specimen and x1,y1,x2,y2 ... columns, then it can be brought in using read.table() and converted to a 3D array using arrayspecs(). Advanced users can even make their own macros in ImageJ for their specific needs. Related to ImageJ is FiJi, developed for more image processing.


3D landmark data collection

Geomorph's function digit.fixed() allows users to digitize 3D landmarks on surfaces of .PLY files. , which are one type of 3D surface file (Meshlab is great free software to convert files into this format). These already contain the scale of the specimen, so all one needs to do is place the landmarks. Here is a video of how. The landmark data for each specimen are written to a .NTS file, which can be read into geomorph (using readmulti.nts()) . As mentioned  already, the benefit of using geomorph and R is that it works on Mac, Windows and Linux.  Semilandmark data can also be collected with geomorph, using either digit.fixed(), or buildtemplate() and digitsurface().  Videos demonstrating how to use these are here.

Landmark Editorby IDAV was the software I used the most before starting with geomorph. It also reads in .PLY files, and has a nice feature of setting correspondence between meshes for semi-automatic digitizing. LE only works on Windows machine, sadly. I have tried with minimal success to get it working on a virtual machine, because it has high-reliance on the VRAM and RAM, particularly with large meshes. Also the software is not being updated with the changing Windows operating systems, so it still performs the best on XP machines. LE outputs a .DTA file, which is essentially an .NTS file for multiple specimens. This file can be read into geomorph using readland.nts() but beware, the file has incorrect header notation; every header is 1 n p-x-k 1 9999 Dim=3, rather than 1 n p-x-k 0 Dim=3, which denotes that missing data is in the file even when it is not. Best to change the header by hand so that you don't get a "NAs introduced by coercion" error.

Meshlab by the Visual Computing Lab has a feature called PickPoints. I'll say now that I have found this feature quite difficult to master, and so I always returned to Landmark Editor. Landmarks are placed on the surface of any 3D surface file (that has faces) that Meshlab can read (see the website for the full list, but includes the standard .PLY, .STL and .VRML). To place a landmark, hold option and left-mouse button click on the surface. The function has a template option for semi-automated digitizing also. To save the coordinate data, Meshlab writes a .pp file, which has the coordinates embedded in with a lot of other code. The R package Morpho by S. Schlager has a function to read in these files (read.mpp()). Meshlab is available for Mac, Windows and Linux. 

Edgewarp by Bill Green and Fred L. Bookstein has been around since 1994 (available here). The software reads in slice data, i.e. CT or MRI imaging systems, and allows users to place landmarks and semilandmarks. It is available for Mac and Linux only. The command-line startup makes this software less appealing to newbies, but it has a dedicated following, particularly in the anthropology sector. I have very little experience with it, so would love to have anyone with more experience to comment.

I'd love to hear about anyone's experience with these, or other software I have omitted (this is NOT a comprehensive list). Comment away!

Emma

Tips & Tricks 4: Reading In Data Files

$
0
0
Today's exercise is another nice and simple one, and allows you to get used to manipulating datasets in R.

Exercise 4 - How to read a file of coordinate data into R and make sure it is numeric.

Reading your data files into R  for analysis with geomorph or other packages can be challenging. Geomorph has several functions for common data file types of coordinate data (e.g. readland.tps(), readland.nts()).

But what if your data are not in this format?

One of the main issues people face is that using read.table() or read.delim(), numerical data can be coerced into a factor automatically. Below is a very simple solution to make sure your data are numerical:

mydata <- read.table("data.txt",header=TRUE,row.names=1,
stringsAsFactors = FALSE) 
# here we are reading in a tab-delimited text file from MorphoJ, but this can be an issue with data from any outside program. The stringsAsFactors = FALSE is VERY important here

is.numeric(mydata)
[1] FALSE # here R tells is the data are not numeric, even though we can see they are if we use View(mydata).

The solution is:
as.matrix(sapply(mydata[], as.numeric))

For example, say we know the shape coordinates are present in the file after two columns of non-shape coordinates (these could be centroid size, or a classifier), then:

shape <- as.matrix(sapply(mydata[,-(1:2)], as.numeric)) 
# here we say, use all columns except the first two.

is.numeric(shape)
[1] TRUE # now it's numeric. Ready to go!

Simple! 

Emma

Geomorph update 2.1.1 now available!

$
0
0
Geomorph users,

We have uploaded version 2.1.1 to CRAN. The windows and mac binaries have been compiled and the tarball is available.

Version 2.1.1 contains small updates and fixes a few small bugs.

New Feature: Specimens can now be rotated to their principal axes in gpagen() with option to disable (PrinAxes=TRUE by default). This helps visualizations in other functions. Thank you to Jessie Atterholt of UC Berkeley for this suggestion. 
example:
data(hummingbirds)

gpagen(hummingbirds$land,curves=hummingbirds$curvepts, PrinAxes=TRUE)

Bug Fixes: 

  •     Fixed concatenated SSCP matrix issue in procD.lm(), pairwise.D.test() and pairwise.slope.test()
  •    Corrected issue reading specimen names in readland.tps()
  •    Corrected color options for plotting groups in plotTangentSpace()
  •    Corrected test for slope:group interaction in plotAllometry()

Computational Change: Underlying code for ancestral state estimation (used in plotGMPhyloMorphoSpace() and physignal()) has been changed to use fastAnc() from Liam Revell's phytools.

Emma
Viewing all 38 articles
Browse latest View live