-------- Original Message --------
Subject: Re: GPA possible based on subset of landmarks?
Date: Mon, 27 Feb 2012 13:58:17 -0500
From: annat haber <[email protected]>
To: [email protected]
Hi Dominique,
If you have only two configurations, you can use my R function
unifyVD.R, pasted in the end and also downloadable from Rohlf's website
http://life.bio.sunysb.edu/morph/
It's designed to unify the ventral and dorsal aspects of the skull based
on a subset of landmarks that are taken from both aspects. Your problem
sounds exactly the same, only your "ventral" and "dorsal" configurations
are two different specimens, if I understand correctly.
But, since you probably want to simultaneously superimpose more than two
configurations you need to modify it and combine it with the gpa
function - a version of which is also pasted in the end of this email
("PROC.R"). If you're familiar with R and can do this yourself, then the
two functions should give you a good starting point. Otherwise, I'll try
to do it when I get a chance.
Basically, the easiest procedure, I think, would be to translate every
complete configuration based on the centroid of the subset, then use the
PROC function (or the procGPA function in package shapes) on all the
subsets. Then find the rotation matrix between each original subset and
its superimposed coordinates and use this rotation matrix to rotate the
complete configuration(after it has been already translated onto the
subset centroid) using this bit of code (repeat this part separately for
each subset):
M<- t(na.omit(S)) %*% na.omit(O) # S is the superimposed coordinates and
O is the original translated coordinates of a specific subset.
SVD <- svd(M)
L <- diag(SVD$d)
S <- ifelse(L<0, -1, L)
S <- ifelse(L>0, 1, L)
RM <- SVD$v %*% S %*% t(SVD$u) # the rotation matrix
Xsi<- Xc %*% RM# rotate the translated complete configuration Xc
You should of course also scale everything to centroid size before doing
the gpa, but I'm actually not sure how exactly (input anyone?). I
suppose you should scale every configuration by the centroid of its subset.
I hope that helps (and correct...). Please feel free to contact me
directly with any questions or comments.
Cheers,
Annat
On Mon, Feb 27, 2012 at 7:21 PM, morphmet
<[email protected]
<mailto:[email protected]>> wrote:
-------- Original Message --------
Subject: GPA possible based on subset of landmarks?
Date: Thu, 16 Feb 2012 18:36:59 -0500
From: Dominique Adriaens <[email protected]
<mailto:[email protected]>>
To: <[email protected] <mailto:[email protected]>>
Dear all,
Does anyone know how it would be possible to perform GPA on a set of
landmark configurations, where the actual GPA is performed based on a
subset of landmarks in the configurations but where the other landmarks
are modified accordingly (but are not involved in the GPA itself). We
want to combine different sets of digitised landmark configurations,
being a set of landmarks on bony elements (which comprise a subset of
landmarks shared in all configurations) and different sets of landmarks
on muscles (a sequence of images are used, where muscles are
subsequently peeled off). The final goal is then to pool all the muscle
landmarks with that shared set of bony landmarks into one dataset,
after
they have been superimposed based on the coordinates of the shared
‘bony
landmarks’.
Any suggestion would be welcome!
Thanks and best regards
Dominique
*Prof. Dr. Dominique Adriaens*
Ghent University
Evolutionary Morphology of Vertebrates & Zoology Museum
K.L. Ledeganckstraat 35, B-9000 Gent
BELGIUM
tel: +32 9 264.52.19 <tel:%2B32%209%20264.52.19>, fax: +32 9
264.53.44 <tel:%2B32%209%20264.53.44>
E-mail: [email protected]
<outbind://5-__000000002B873A8E03CAD411AE9E00__5004995AACC4103900/[email protected]
<mailto:[email protected]>>
URL: http://www.fun-morph.ugent.be/
http://www.zoologymuseum.__ugent.be/
<http://www.zoologymuseum.ugent.be/>
http://www.evolutietheorie.be/
Logo labo klein
### unifyVD
## This function works with both 2D and 3D; no need to specify which it is
# X is a configuration of one specimen in the format of k landmarks by m
dimensions
# "ventral" and "dorsal" are vectors indicating the names (NOT indices)
# of the ventral and dorsal landmarks, respectively.
# comV and comD are vectors indicating the common landmarks' names (NOT
indices) for the ventral and dorsal sides respectively (in the same order);
# the function attaches the ventral side to the dorsal side
# (or any other two aspects of the same structure) based on the common
landmarks.
# It finds the rotation matrix that minimizes the sum of squared deviations
# between the ventral and the dorsal
# (Rohlf 1990. Proceedings of the Michigan Morphometrics Workshop),
# and calculates the errors as the vector length between the ventral and
the dorsal
# equivalent landmarks after fitting.
# If either the dorsal or the ventral copy of a common landmark is missing,
# that landmark is ignored for the unification.
# Any other missing data does not affect the procedure at all and can be
safely included.
# If average=TRUE then the dorsal and ventral copies of the common
landmarks are averaged
# and listed only for the dorsal, so the output will have fewer rows
than the input.
# NOTE: the resulting configuration will be re-organized to have all the
dorsal
# landmarks first, then all the ventral ones.
# It is therefore HIGHLY RECOMMENDED that landmarks will be designated
by names in X
# (i.e., rownames(X) is a charcter vector rather than NULL)
# The output includes the unified data ($unified) and the unification
errors ($errors)
# an example for an input file and a protocol that implements this
function can be downloaded from
# http://home.uchicago.edu/~annat/
# Please email me with comments and questions [email protected]
<mailto:[email protected]>
# last updated Feb 28 2011
unifyVD<- function(X, dorsal, ventral, comD, comV, average=FALSE) {
V <- X[comV,]
D <- X[comD,]
Xv<- X[ventral,]
Xd <- X[dorsal,]
V[which(is.na <http://is.na>(D))] <- NA
D[which(is.na <http://is.na>(V))] <- NA# making sure both ventral and
dorsal of the same LM are NA's whenever one of them is
mV<- matrix(apply(V, 2, mean, na.rm=TRUE), byrow=TRUE, nr=nrow(Xv),
nc=ncol(Xv))
Xvc<- Xv-mV# translating all the ventral LM's based on the centroid of
the common ones
Vc<- scale(V, scale=F)
mD<- matrix(apply(D, 2, mean, na.rm=TRUE), byrow=TRUE, nr=nrow(Xd),
nc=ncol(Xd))
Xdc<- Xd-mD# translating all the dorsal LM's based on the centroid of
the common ones
Dc<- scale(D, scale=F)
M<- t(na.omit(Dc)) %*% na.omit(Vc) # arbitrarily choosing the dorsal as
the reference
SVD <- svd(M)
L <- diag(SVD$d)
S <- ifelse(L<0, -1, L)
S <- ifelse(L>0, 1, L)
RM <- SVD$v %*% S %*% t(SVD$u) # the rotation matrix
Xvr<- Xvc%*% RM# rotate all the translated ventral LM's
dv<- rbind(Xdc, Xvr)
dv[comV[which(is.na <http://is.na>(dv[comV,1]))],] <-
dv[comD[which(is.na <http://is.na>(dv[comV,1]))],]
dv[comD[which(is.na <http://is.na>(dv[comD,1]))],] <-
dv[comV[which(is.na <http://is.na>(dv[comD,1]))],]
if (average==TRUE) {
dv[comD,] <- (dv[comD,]+dv[comV,])/2
dv<- dv[-match(comV, rownames(dv)),]}
list(unified=dv, errors=sqrt(rowSums((Xvr[comV,]-Dc)^2)))}
#### PROC
# AA is an array of the k x m x N format; k landmakrs, m dimensions, N
specimens; partial procrustes superimposition;
scale.centroid<- function(X) {X/sqrt(sum(X^2, na.rm=TRUE))} # X is
centered already
fitX <- function(X, Ref) {
X[which(is.na <http://is.na>(Ref))] <- NA
Ref[which(is.na <http://is.na>(X))] <- NA
M<- t(na.omit(Ref)) %*% na.omit(X)
SVD <- svd(M)
V<- SVD$v# eigenvectors scaled to 1 unit length
U <- SVD$u
L <- diag(SVD$d)
S <- ifelse(L<0, -1, L)
S <- ifelse(L>0, 1, L)
RM<- V%*% S%*% t(U) # the rotation matrix
Xr<- X%*% RM} # rotate X onto the reference
PROC<- function(AA, sizescaled=TRUE) {
Xc<- array(apply(AA, 3, scale, scale=FALSE), dim=dim(AA)) # centered
if(sizescaled==TRUE) {Xs<- array(apply(Xc, 3, scale.centroid),
dim=dim(AA))} else{Xs<- Xc}
R <- Xs[,,1]
d <- 1
while (d>0.001) {
Xf<- array(apply(Xs, 3, fitX, Ref=R), dim=dim(AA), dimnames=dimnames(AA))
MC<- matrix(nr=nrow(Xf), nc=ncol(Xf)) # mean configuration
for (i in 1:nrow(Xf)) {for (j in 1:ncol(Xf)) {MC[i,j] <- mean(Xf[i,j,],
na.rm=T)}}
for (i in 1:nrow(R)) { if (is.na <http://is.na>(R[i,1])) MC[i,]<-NA}
d <- sqrt(sum((MC-R)^2, na.rm=T))
R <- MC
Xs <- Xf}
list(rotated=Xf, opt.stat=d)}
--
Annat Haber, PhD
Postdoc fellow
Tel-Aviv University
Department of Zoology
Tel Aviv 69978, Israel
c: +972 50 2517 901
http://home.uchicago.edu/~annat/ <http://home.uchicago.edu/%7Eannat/>