Supplementary Information (doc 718K)

advertisement
Supplementary tutorial: functions for G-matrix comparisons.
Comparing G: Multivariate Analysis of Genetic Variation in Multiple Populations
J. David Aguirre, Emma Hine, Katrina McGuigan and Mark W. Blows
Notes on the structure of the tutorial
Below we present the R script we used to generate the results presented in Aguirre et al.. The
output files for this worked example (Supplementary data: SI_output_and_ped) have a smaller number
of MCMC samples than those in the original manuscript to limit the computational time required to
complete this tutorial. An understanding of the basic R commands is assumed, and experienced users
are encouraged to improve the script at their discretion. For less experienced users, however, the
matrix operations will work so long as the lines in Courier New font are copied in to the R window.
It is important that the entire function is copied into the R window, thus, we have flagged the #START
and #END of each function. Furthermore, some example results are presented in text. These sections
are not intended to be copied into the R window and are flagged by #< and #>. At the end of the
tutorial we provide the script to produce the figures. However, we stress that script for the figures
should be considered examples, as there in many different and likely better, ways to draw these
figures. If users have any problems implementing the methods described in this tutorial please do not
hesitate to contact the corresponding author (d.aguirre@uq.edu.au).
Importing the model output
The files are in the format typical of MCMCglmm (Hadfield, 2010). An example syntax is
provided along with the original data in Dryad; however, these models can take some time to run, so,
in the interest of expedience, we move forward using the output files provided. The output files are
structured such that each matrix element of each variance component is a column and each row is an
MCMC sample of the posterior distribution of that matrix element. Thus, because there were eight
traits, and we specified an unstructured covariance structure for each trait at the animal, vial and
residual levels, our output file for each population has 192 columns (i.e. 8 x 8 + 8 x 8 + 8 x 8) and 1000
rows.
First, we will define a number of terms that will be used repeatedly.
MCMCsamp <- 1000
#number of MCMC samples
n <- 8
#number of traits
m <- 6
#number of matrices to compare
r <- 3
#number of random effects specified in the model. In our analyses these
were animal, vial and residual effects.
traitnames <- c("lc2","lc3","lc4","lc5","lc6","lc7","lc8","lc9")
#trait names
Gnames <- c("b1","b2","c1","c2","m1","m2")
#matrix labels
Then we will set up an empty array, and fill this array by referencing the correct file path for
the output files. Note that the file path will need to be customized to the directory where the files have
been stored on your computer.
MCMCarray <- array(,c(MCMCsamp,(n^2)*r,m))
#empty array
MCMCarray[,,1] <as.matrix(read.csv(file="C:/Users/uqjaguir/Desktop/Heredity/SI_output_and
_ped/VC_b1_3MCMC.csv",header =T))
#G1 stored as the 1st element of dim[3]
MCMCarray[,,2] <as.matrix(read.csv(file="C:/Users/uqjaguir/Desktop/Heredity/SI_output_and
_ped/VC_b2_3MCMC.csv",header =T))
#G2 stored as the 2nd element of dim[3]
MCMCarray[,,3] <as.matrix(read.csv(file="C:/Users/uqjaguir/Desktop/Heredity/SI_output_and
_ped/VC_c1_3MCMC.csv",header =T))
#G3 stored as the 3rd element of dim[3]
MCMCarray[,,4] <as.matrix(read.csv(file="C:/Users/uqjaguir/Desktop/Heredity/SI_output_and
_ped/VC_c2_3MCMC.csv",header =T))
#G4 stored as the 4th element of dim[3]
MCMCarray[,,5] <as.matrix(read.csv(file="C:/Users/uqjaguir/Desktop/Heredity/SI_output_and
_ped/VC_m1_3MCMC.csv",header =T))
#G5 stored as the 5th element of dim[3]
MCMCarray[,,6] <as.matrix(read.csv(file="C:/Users/uqjaguir/Desktop/Heredity/SI_output_and
_ped/VC_m2_3MCMC.csv",header =T))
#G6 stored as the 6th element of dim[3]
Reshaping the array and standardizing G
We now need to reshape the MCMCarray to get the G and P arrays in the format we need to
run the functions below.
Garray <- array(,c(n,n,m,MCMCsamp))
dimnames(Garray) <- list(traitnames,traitnames,Gnames)
Parray <- array(,c(n,n,m,MCMCsamp))
dimnames(Parray) <- list(traitnames,traitnames,Gnames)
for (i in 1:m){
for (j in 1:MCMCsamp){
G <- matrix(MCMCarray[j,1:(n^2),i],ncol= n)
CE <- matrix(MCMCarray[j,((n^2)+1):((n^2)*2),i],ncol= n)
R <- matrix(MCMCarray[j,(((n^2)*2)+1):((n^2)*3),i],ncol= n)
Garray[,,i,j] <- G
Parray[,,i,j] <- G + CE + R
}
}
The Garray and Parray objects have the MCMC samples of G and P stored in the first two
dimensions of the array. The third dimension identifies the population and the fourth dimension
identifies the MCMC sample. For example, if we wanted to view the genetic variance in the lc2 trait
(i.e. matrix element 1, 1) of the c1 population for the 5th MCMC sample we would use the following
syntax,
Garray[1,1,3,5]
Similarly, if we wanted to view the G matrix of the b2 population for the 13th MCMC sample we
would use the following syntax.
Garray[,,2,13]
Last, if we wanted to view the G matrices for all populations for the 42nd MCMC sample we
would use the following syntax.
Garray[,,,42]
Next, we provide a method to apply the multivariate standardization (
)
presented in Hansen and Houle (2008) to the G array. We will proceed in our example, without
applying the standardization as our traits are measured and analyzed on the same scale. Nevertheless,
to apply the standardization we first define a function to calculate
then we use this function to
apply the standardization to each MCMC sample of each replicate line.
inv.rootP <- function (P){
rootP <- matrix(0,n, n)
for (i in 1:n){
val <- eigen(P)$values
vec <- eigen(P)$vectors
rootP <- rootP + (vec[,i] %*% t(vec[,i]))*sqrt(val[i])
}
solve(rootP)
}
HHGarray <- array(,c(n,n,m,MCMCsamp))
for (k in 1:MCMCsamp){
for (j in 1:m){
P <- inv.rootP(Parray[,,j,k])
HHGarray[,,j,k] <- P %*% Garray[,,j,k] %*% P
}
}
The HHGarray object contains the standardized G array.
Generating randomised G matrices for hypothesis tests
The approach we use to generate the randomised G matrices uses the rbv function in the
MCMCglmm package. rbv uses the pedigree structure of a population to generate breeding values for
individuals by sampling from a multivariate normal distribution with a mean = 0 and a variance = G.
Therefore, the first step in generating randomised G matrices is to import the pedigree files for each
population. Again, the file path will need to be customized for your computer.
Ped.b1 <as.data.frame(read.csv(file="C:/Users/uqjaguir/Desktop/Heredity/SI_output
_and_ped/Ped.b1.csv",header =T))
Ped.b2 <as.data.frame(read.csv(file="C:/Users/uqjaguir/Desktop/Heredity/SI_output
_and_ped/Ped.b2.csv",header =T))
Ped.c1 <as.data.frame(read.csv(file="C:/Users/uqjaguir/Desktop/Heredity/SI_output
_and_ped/Ped.c1.csv",header =T))
Ped.c2 <as.data.frame(read.csv(file="C:/Users/uqjaguir/Desktop/Heredity/SI_output
_and_ped/Ped.c2.csv",header =T))
Ped.m1 <as.data.frame(read.csv(file="C:/Users/uqjaguir/Desktop/Heredity/SI_output
_and_ped/Ped.m1.csv",header =T))
Ped.m2 <as.data.frame(read.csv(file="C:/Users/uqjaguir/Desktop/Heredity/SI_output
_and_ped/Ped.m2.csv",header =T))
To generate the randomised G matrices we will write a loop to calculate breeding values for
each individual given the populations pedigree and the corresponding MCMC sample of G. These
vectors of breeding values are archived and then randomly allocated to populations. Last we construct
6 randomised G for each MCMC sample.
library(MCMCglmm)
rand.Garray <- array(,c(n,n,m,MCMCsamp))
dimnames(rand.Garray) <- list(traitnames,traitnames,Gnames)
for (i in 1:MCMCsamp){
b1.bv<-rbv(Ped.b1,Garray[,,1,i])
b2.bv<-rbv(Ped.b2,Garray[,,2,i])
c1.bv<-rbv(Ped.c1,Garray[,,3,i])
c2.bv<-rbv(Ped.c2,Garray[,,4,i])
m1.bv<-rbv(Ped.m1,Garray[,,5,i])
m2.bv<-rbv(Ped.m2,Garray[,,6,i])
a.pop <cumsum(c(dim(Ped.b1)[1],dim(Ped.b2)[1],dim(Ped.c1)[1],dim(Ped.c2)[1],dim(
Ped.m1)[1],dim(Ped.m2)[1]))
pop.bv <- rbind(b1.bv,b2.bv,c1.bv,c2.bv,m1.bv,m2.bv)
rand.pop.bv <- pop.bv[sample(dim(pop.bv)[1],replace=F),]
rand.Garray[,,1,i] <- cov(rand.pop.bv[1:a.pop[1],])
rand.Garray[,,2,i] <- cov(rand.pop.bv[(a.pop[1] + 1):a.pop[2],])
rand.Garray[,,3,i] <- cov(rand.pop.bv[(a.pop[2] + 1):a.pop[3],])
rand.Garray[,,4,i] <- cov(rand.pop.bv[(a.pop[3] + 1):a.pop[4],])
rand.Garray[,,5,i] <- cov(rand.pop.bv[(a.pop[4] + 1):a.pop[5],])
rand.Garray[,,6,i] <- cov(rand.pop.bv[(a.pop[5] + 1):a.pop[6],])
}
This approach simulates a set of G that have been sampled from the same population, and
thus the only dissimilarity among them is random sampling error. Furthermore, because rand.Garray
is of the same order as the Garray (i.e. n x n x m x MCMCsamp), the matrix comparison functions work
for both the observed and randomised arrays.
Method 1. Random projections through G
Matrix projection is a simple but effective tool for uncovering similarities or dissimilarities
among matrices. The function below uses the projection of random, normal vectors through MCMC
samples of G matrices to identify regions of the genetic space where matrices differ significantly in
variance.
#START
R.proj <- function(Gs,p,vec){
if (dim(Gs)[[1]] != dim(Gs)[[2]]){
stop("G array must be of order n x n x m x MCMCsamp")
}
if (is.na(dim(Gs)[4])) {
stop("There are no MCMCsamples")
}
n <- dim(Gs)[[1]]
m <- dim(Gs)[[3]]
MCMCsamp <- dim(Gs)[[4]]
rand.vec <-matrix(,vec,n)
for (i in 1:vec){
b <- runif(n,-1,1)
rand.vec[i,] <- b/(sqrt(sum(b^2)))
}
#generate unit length random vectors
proj<- function(G,b) t(b) %*% G %*% (b)
#internal function to do projection
G.proj <- array(,c(MCMCsamp, m, vec))
colnames(G.proj) <- dimnames(Gs)[[3]]
for (i in 1:vec){
G.proj[,,i]<- t(apply(Gs, 3:4, proj, b = rand.vec[i,]))
}
#project each random vector through each MCMC sample of each G
prs <- cbind(rep(1:m, each = m), 1:m)
prs.comp <- prs[prs[,1] < prs[,2], , drop = FALSE]
#setting up an index for HPD comparisons
proj.score <-matrix(,vec,((m^2 - m)/2))
for (k in 1:vec){
HPD.int <- HPDinterval(as.mcmc(G.proj[,,k]), prob = p)
proj.score[k,] <- ifelse(HPD.int[prs.comp[,1],1] >
HPD.int[prs.comp[,2],2] | HPD.int[prs.comp[,2],1] >
HPD.int[prs.comp[,1],2],1,0)
}
#for a given random vector, examine if the HPD intervals of any
pair of G matrices overlap
vec.score <-cbind(rand.vec, proj.score)
colnames(vec.score) <- c(1:n, paste(dimnames(Gs)[[3]][prs.comp[,
1]], ".vs.", dimnames(Gs)[[3]][prs.comp[, 2]], sep = ""))
#collate the random vectors and the outcome of their projection on
the G matrices
sig.vec <- subset(vec.score, rowSums(vec.score[,(n+1):(n+((m^2 m)/2))]) > 0)
#collate just the random vectors that resulted in significant
differences in variance
if(dim(sig.vec)[1] <= 1) {warning("There were <= 1 significant
vectors, try a larger vec or lower p"); eig.R <- "Na"}
else{
eig.R <- eigen(cov(sig.vec[,1:n]))
rownames(eig.R$vectors) <- dimnames(Gs)[[1]]
colnames(eig.R$vectors) <- c(paste("e", 1:n, sep = ""))
}
#eigen analysis of the R matrix
list(G.proj = G.proj, vec.score = vec.score, eig.R = eig.R)
}
#END
The arguments passed to R.proj are:
Gs
The G array must be of the order n x n x m x MCMCsamp
p
The probability density interval for assessing significant differences among matrices
vec
The number of random vectors
The line below applies the R.proj function to the observed G array, assuming a probability of
0.95 and 1000 random vectors, then stores the results in MCMC.R.proj. This calculation will take a few
minutes to complete, but will vary depending on the computer specifications, as well as the number of
MCMC samples and the number of random vectors.
MCMC.R.proj <- R.proj(Garray, p = 0.95, vec = 1000)
MCMC.R.proj is a list with 3 slots:
$G.proj
Genetic variance in the direction of each random vector for each MCMC
samples of G. The rows of $G.proj identify the MCMC samples, the columns
identify the replicate line and third dimension of $G.proj identifies the random
vector.
$vec.score
For each row of $vec.score, the first n columns show the random vector, and
the remaining columns show the results of pairwise HPD comparisons of
genetic variance in the direction of the random vector. Zeros indicate the HPD
intervals overlapped (i.e. non-significant differences in variance), whereas ones
indicate the HPD intervals did not overlap (i.e. a significant difference in
variance)
$eig.R
The eigenanalysis of the R (co)variance matrix
Note, because vectors are generated randomly, the vector ID’s and summary statistics
presented below will differ slightly to those on your computer. Thus, it is important that you customise
the row indexes in the plot script for the correct rows on your computer. We can visualize what is
happening internally in M.proj by plotting the posterior distribution of genetic variances for a vector
where there were significant differences among replicate lines and a vector for which there were no
significant differences among replicate lines (Figure 1). To find candidate vectors for the example in
this appendix we can examine the first 8 rows of columns 9 to 23 (i.e the columns for the pair wise
hypothesis tests) of MCMC.M.proj$vec.score
MCMC.R.proj$vec.score[1:n,(n+1):(n+((m^2 - m)/2))]
#<
[1,]
[2,]
[3,]
[4,]
[5,]
[6,]
[7,]
[8,]
[1,]
[2,]
[3,]
[4,]
[5,]
b1.vs.b2 b1.vs.c1 b1.vs.c2 b1.vs.m1 b1.vs.m2 b2.vs.c1 b2.vs.c2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
b2.vs.m1 b2.vs.m2 c1.vs.c2 c1.vs.m1 c1.vs.m2 c2.vs.m1 c2.vs.m2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
[6,]
[7,]
[8,]
[1,]
[2,]
[3,]
[4,]
[5,]
[6,]
[7,]
[8,]
#>
0
0
0
m1.vs.m2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
Recalling that vectors finding significant differences are indexed with 1’s and those not finding
significant difference are indexed with 0’s. The table above shows that for direction defined by vector 3
the genetic variance in m2 differed from the genetic variance in the b1 and b2 populations (Figure 1A )
whereas for the remaining vectors, there were no significant differences in genetic variance among
populations (Figure 1B).
Figure 1. Posterior means and 95% HPD intervals of the genetic variance in the direction of
random vectors #3 (panel B) and #5 (panel A)for each population. In this example the vector in panel A
would contribute to the R matrix whereas the vector in panel B would not contribute to the R matrix.
To examine the proportion of random vectors that found significant differences in genetic
variance among populations we can calculate the number of vectors that found significant (TRUE) and
non-significant (FALSE) pair wise differences in genetic variance.
table(rowSums(MCMC.R.proj$vec.score[,(n+1):(n+((m^2 - m)/2))]) > 0 )
#<
FALSE
844
#>
TRUE
156
The 156 vectors that identified differences (at 95% HPD) in genetic variation among matrices
summarize the directions in multivariate space where matrices differ significantly in variance. The next
step is then to examine the eigenstructure of the R matrix. To visualize the eigenstructure of the R
matrix we can use,
lapply(MCMC.R.proj$eig.R, round, digits = 3)
#<
$values
[1] 0.300 0.156 0.137 0.125 0.118 0.080 0.058 0.028
$vectors
lc2
lc3
lc4
lc5
lc6
lc7
lc8
lc9
#>
e1
0.356
-0.885
-0.267
-0.008
0.103
-0.036
0.087
-0.011
e2
-0.616
-0.012
-0.645
-0.238
0.126
-0.270
0.158
0.188
e3
0.193
-0.006
-0.014
-0.466
-0.636
0.054
-0.089
0.575
e4
e5
e6
e7
-0.004 0.138 0.602 0.275
-0.015 0.004 0.429 0.179
0.194 0.377 -0.533 -0.105
-0.698 -0.064 0.131 -0.456
0.572 0.293 0.310 -0.221
0.360 -0.808 0.047 -0.287
-0.136 -0.007 -0.037 0.396
0.017 0.310 0.229 -0.620
e8
0.003
-0.024
-0.197
-0.098
-0.105
-0.236
-0.885
-0.318
Then to examine the of eigenvectors R that result in significant differences in genetic variance
among populations we can use.
proj<- function(G, b) t(b) %*% G %*% (b)
#Function to do projection
R.vec.proj <- array(, c(MCMCsamp, m, n))
for (i in 1:n){
R.vec.proj[,,i] <- t(apply(Garray, 3:4, proj, b =
MCMC.R.proj$eig.R$vectors[,i]))
}
#Genetic variance in each population in the direction of the eigenvectors
of R
HPD.R.vec.proj <- array(, c(m, 2, n))
for (i in 1:n){
HPD.R.vec.proj[,,i] <- HPDinterval(as.mcmc(R.vec.proj[,,i]), prob =
0.95)
}
#HPD intervals for the genetic variance in each population in the
direction of the eigenvectors of R
Figure 2 Genetic variance in the direction of each of the eigenvectors of R for each population.
In figure 2 we see that only the first eigenvector of R results in significant differences in genetic
variance among populations.
Method 2. Krzanowski’s common subspaces
Krzanowski (1979) provides a method for identifying the common subspaces for a
representative subset of vectors of two or more matrices. In our first example we will use first four (i.e.
n/2) eigenvectors of each G, but we highlight that this is a decision the reader needs to consider
carefully. Because, as we will show, the number of eigenvectors included for each matrix can influence
our final conclusions.
#START
kr.subspace <- function(Gs, vec){
if (dim(Gs)[[1]] != dim(Gs)[[2]]){
stop("G array must be of order n x n x m x MCMCsamp")
}
if (is.na(dim(Gs)[4])) {
stop("There are no MCMCsamples")
}
n <- dim(Gs)[[1]]
m <- dim(Gs)[[3]]
MCMCsamp <- dim(Gs)[[4]]
if(length(vec) != m){stop("vec must have length = m")}
h <- function (g, v){
AA <- array(, c(n, n, m))
for (k in 1:m){
g.vec <- eigen(g[,,k])$vectors[,1:(v[k])]
AA[,,k] <- g.vec %*% t(g.vec)
}
H <- apply(AA, 1:2, sum)
list(H = H, AA = AA)
}
#internal function to calculate AA and H
MCMC.H <- array(, c(n, n, MCMCsamp))
dimnames(MCMC.H) <- list(dimnames(Gs)[[1]], dimnames(Gs)[[1]],
dimnames(Gs)[[4]])
MCMC.AA <- array(, c(n, n, m, MCMCsamp))
dimnames(MCMC.AA) <- list(dimnames(Gs)[[1]], dimnames(Gs)[[1]],
dimnames(Gs)[[3]], dimnames(Gs)[[4]])
for (i in 1:MCMCsamp){
kr <- h(Gs[,,,i], v = vec)
MCMC.H[,,i] <- kr$H
MCMC.AA[,,,i] <- kr$AA
}
#calculate AA and H for the ith MCMC sample of the G array
avH <- apply(MCMC.H, 1:2, mean)
rownames(avH) <- dimnames(Gs)[[1]]
colnames(avH) <- dimnames(Gs)[[1]]
#calculate the posterior mean H
avAA <- apply(MCMC.AA, 1:3, mean)
dimnames(avAA) <- list(dimnames(Gs)[[1]], dimnames(Gs)[[1]],
dimnames(Gs)[[3]])
#calculate the posterior mean AA
avH.vec <- eigen(avH)$vectors
#eigenanalysis of posterior mean H
proj<- function(a, b) t(b) %*% a %*% b
#internal function to do projection
avH.theta <- matrix(, n, m)
for (i in 1:n){
for (i in 1:n){
avH.theta[i,] <- acos(sqrt(apply(avAA, 3, proj, b = avH.vec[,i])))
* (180/pi)
}
}
#angles between the eigenvectors posterior mean H and the posterior
mean subspaces of each population
MCMC.H.val <- matrix(, MCMCsamp, n)
colnames(MCMC.H.val) <- paste("h", 1:n, sep="")
for (i in 1:n){
MCMC.H.val[,i] <- apply(MCMC.H, 3, proj, b = avH.vec[,i])
}
#posterior distribution of the genetic variance for the eigenvectors
of posterior mean H
MCMC.H.theta <- array(, c(n, m, MCMCsamp))
rownames(MCMC.H.theta) <- paste("h", 1:n, sep="")
colnames(MCMC.H.theta) <- dimnames(Gs)[[3]]
for(i in 1:n){
for(j in 1:MCMCsamp){
MCMC.H.theta[i,,j] <- acos(sqrt(apply(MCMC.AA[,,,j], 3, proj, b
= avH.vec[,i]))) * (180/pi)
}
}
#posterior distribution of the angles between the eigenvectors of
posterior mean H and the MCMC samples of the subspaces of each population
list(avAA = avAA, avH = avH, MCMC.AA = MCMC.AA, MCMC.H = MCMC.H,
MCMC.H.val = MCMC.H.val, MCMC.H.theta = MCMC.H.theta)
}
#END
The arguments passed to kr.subspace are:
Gs
The G array. Must be of the order n x n x m x MCMCsamp
vec
A vector indicating the number of eigenvectors of each G to include in the construction
of H. Must have the same number of elements as there are matrices to compare
The line below applies the kr.subspace function to the first four eigenvectors of the observed G
array, then stores the results in MCMC.kr.
MCMCG.kr <- kr.subspace(Garray, vec = rep(n/2,m))
MCMC.kr is a list with 3 slots:
$avAA
Posterior mean AAT
$avH
Posterior mean H
$MCMC.AA
MCMC samples of AAT
$MCMC.H
MCMC samples of H
$MCMC.H.val
MCMC samples of the eigenvalues of H
$MCMC.H.theta
MCMC samples of the angles between the eigenvectors of posterior mean H
and the MCMC samples of AAT
Because the eigenvalues of H are bounded between zero and m, to provide a hypothesis test
that identifies significant common subspaces we need to generate a sensible null model. The null
model we use assumes the G are sampled from the same population, and hence the randomised G will
have all subspaces in common up to sampling error. Thus, to compare our observed and null model we
will apply the kr.subspace function to the first four eigenvectors of the randomised G array, and plot
the eigenvalues of H for the observed and randomised data.
MCMCG.kr.rand <- kr.subspace(rand.Garray, vec = rep(n/2,m))
Figure 3. Posterior mean and 95% HPD intervals for the eigenvalues of H for the first four
eigenvectors of the observed and randomised G arrays.
The comparison of the eigenvalues of H for the first four eigenvectors of the observed and
randomised G arrays shows that our populations have shared subspaces (figure 3).
To examine the trait combinations that underlie the common subspaces of the observed G
matrices, we can examine the eigenvectors of the posterior mean H.
round(eigen(MCMCG.kr$avH)$vectors, 3)
#<
[1,]
[2,]
[3,]
[4,]
[5,]
[6,]
[7,]
[8,]
#>
[,1]
[,2]
[,3]
[,4]
[,5]
[,6]
[,7]
[,8]
-0.087 0.089 0.082 0.122 -0.106 0.419 0.874 -0.115
-0.081 0.038 0.097 0.407 -0.742 -0.507 0.082 0.056
-0.064 0.051 -0.105 -0.891 -0.350 -0.188 0.163 -0.055
-0.211 0.337 0.744 -0.121 0.243 -0.194 0.069 0.414
-0.200 0.189 0.055 -0.031 -0.466 0.684 -0.386 0.294
-0.280 0.373 0.241 0.022 -0.008 0.025 -0.213 -0.823
-0.834 -0.542 -0.041 0.006 0.089 -0.036 0.006 0.022
-0.352 0.637 -0.596 0.095 0.177 -0.158 0.068 0.212
Then we can inspect how close the subspaces of the populations are to the eigenvectors of H
we can examine the posterior mean angles of the eigenvectors of H and the AAT for each population
round(apply(MCMCG.kr$MCMC.H.theta, 1:2, mean), 1)
#<
h1
h2
h3
h4
h5
h6
h7
h8
#>
b1
4.4
14.5
24.9
40.0
46.0
70.5
78.8
78.2
b2
3.6
12.8
18.6
31.9
55.9
75.5
80.0
79.4
c1
5.8
11.4
25.0
33.5
51.4
71.7
79.8
79.5
c2
7.9
9.3
15.7
35.6
58.7
72.1
79.8
78.5
m1
7.2
10.0
18.9
42.3
47.8
72.6
80.0
80.0
m2
9.2
16.4
39.6
57.0
40.6
42.1
74.2
82.0
In our second example, rather than using the first four eigenvectors of each G to construct H,
we will use the minimum number of eigenvectors required to include >90% of variance in the posterior
mean G of each population in the construction of H. To calculate the number of eigenvectors required
to satisfy our >90% of the variance in the posterior mean G criteria we can use the following script.
val <- matrix(, n, m)
for (i in 1:m){
avG <- apply(Garray, 1:3, mean)
val[,i] <round(cumsum(t(eigen(avG[,,i])$values))/sum(eigen(avG[,,i])$values)*100)
}
n.vec <- apply(ifelse(round(val,1) < 90, 1, 0), 2, sum)+1
We can now apply the kr.subspace function to the observed and randomised G arrays and use
n.vec to index the number of eigenvectors required to satisfy our >90% of the variance in the posterior
mean G criteria.
MCMCG.kr1 <- kr.subspace(Garray, vec = n.vec)
MCMCG.kr.rand1 <- kr.subspace(rand.Garray, vec = n.vec)
Comparison of the Krzanowski subspaces for the second example below (Figure 4 and tables)
with the results for the first example above, shows that overall the results are similar although there
appears to be greater similarity of subspaces for our second example. We will make no
recommendations on the criteria that researchers should use when deciding the number of
eigenvectors to include, however we stress that care must be taken when deciding on the number of
eigenvectors to include in the construction of H.
Figure 4. Posterior mean and 95% HPD intervals for the eigenvalues of H for the number of
eigenvectors required to include >90% of the variation the posterior mean G in the construction of H.
round(eigen(MCMCG.kr1$avH)$vectors, 3)
#eigenvectors of H
#<
[,1]
[,2]
[,3]
[,4]
[,5]
[1,] -0.087 0.085 -0.081 -0.118 0.193
[2,] -0.088 0.045 -0.086 -0.355 0.696
[3,] -0.065 0.075 0.151 0.905 0.266
[4,] -0.208 0.342 -0.749 0.126 -0.255
[5,] -0.203 0.186 -0.035 0.057 0.534
[6,] -0.280 0.373 -0.240 -0.014 0.021
[7,] -0.832 -0.544 0.034 -0.001 -0.095
[8,] -0.353 0.631 0.586 -0.143 -0.220
#>
[,6]
[,7]
[,8]
0.236 0.616 0.702
-0.601 0.029 -0.100
-0.248 0.068 0.103
-0.144 0.310 -0.286
0.695 -0.041 -0.386
0.022 -0.696 0.488
-0.029 0.018 -0.014
-0.125 0.179 -0.131
round(apply(MCMCG.kr1$MCMC.H.theta, 1:2, mean), 1)
#Vector angles
#<
b1
b2
c1
c2
m1
m2
h1 3.0 3.5 4.2 4.2 3.5 6.7
h2 9.9 12.7 7.5 4.9 5.0 11.5
h3
h4
h5
h6
h7
h8
#>
14.5
20.4
21.2
61.7
73.4
75.3
18.6
31.1
56.3
75.7
79.7
80.4
13.5
15.3
23.0
63.4
75.4
76.6
7.5
11.6
16.3
32.6
60.9
61.7
7.3
11.5
11.9
23.8
65.9
68.9
23.6
37.6
34.6
35.5
67.6
66.1
Method 3. The genetic covariance tensor
Here we apply the method described in Hine et al. (2009) to calculate the fourth-order
covariance tensor of a set of second-order G.
#required packages
library(gdata);library(matrixcalc);library(MCMCglmm)
#START
covtensor <- function(Gs){
if (dim(Gs)[[1]] != dim(Gs)[[2]]){
stop("G array must be of order n x n x m x MCMCsamp")
}
if (is.na(dim(Gs)[4])) {
stop("There are no MCMCsamples")
}
neigten <- n*(n+1)/2
#Number of eigentensors
MCMC.S <- array(,c(neigten, neigten, MCMCsamp))
dimnames(MCMC.S) <- list(paste("e", 1:neigten, sep=""), paste("e",
1:neigten, sep=""))
for (k in 1:MCMCsamp){
MCMCG <- Gs[,,,k]
MCMCvarmat <- t(apply(MCMCG, 3, diag))
#find the variances of the kth G and store them
MCMCcovmat <- t(apply(MCMCG, 3, lowerTriangle))
#find the covariances of the kth G and store them
MCMC.S[1:n,1:n, k] <- cov(MCMCvarmat, MCMCvarmat)
#fill the upper left quadrant of the kth S
MCMC.S[(n+1):neigten,(n+1):neigten, k] <- 2*cov(MCMCcovmat,
MCMCcovmat)
#fill the lower right quadrant of the kth S
MCMC.S[1:n,(n+1):neigten, k] <- sqrt(2)*cov(MCMCvarmat,
MCMCcovmat)
#fill the upper right quadrant of the kth S
MCMC.S[(n+1):neigten,1:n, k] <- sqrt(2)*cov(MCMCcovmat,
MCMCvarmat)
#fill the lower left quadrant of the kthS
}
av.S <- apply(MCMC.S, 1:2, mean)
#posterior mean S
av.S.val <- eigen(av.S)$values
#eigenvalues of posterior mean S
av.S.vec <- eigen(av.S)$vectors
#eigenvalues of posterior mean S
eTmat <- array(, c(n, n, neigten))
dimnames(eTmat) <- list(traitnames, traitnames, paste("E",
1:neigten, sep=""))
for (i in 1:neigten){
emat <- matrix(0, n, n)
lowerTriangle(emat) <- 1/sqrt(2)*av.S.vec[(n+1):neigten,i]
emat <- emat + t(emat)
diag(emat) <- av.S.vec[1:n,i]
eTmat[,,i] <- emat
}
#construct the second-order eigentensors of posterior mean S
eT.eigen <- array(, c(n+1, n, neigten))
for (i in 1:neigten){
eT.eigen[1,,i] <- t(eigen(eTmat[,,i])$values)
#Eigenvalues of the ith eigentensor
eT.eigen[2:(n+1),,i] <- eigen(eTmat[,,i])$vectors
#Eigenvectors of the ith eigentensor
eT.eigen[,,i] <- eT.eigen[,order(abs(eT.eigen[1,,i]),
decreasing = T), i]
}
MCMC.S.val <- matrix(, MCMCsamp, neigten)
colnames(MCMC.S.val) <- paste("E", 1:neigten, sep="")
for (i in 1:MCMCsamp){
for(j in 1:neigten){
MCMC.S.val[i,j] <- t(av.S.vec[,j]) %*% MCMC.S[,,i] %*%
av.S.vec[,j]
}
}
#posterior distribution of the genetic variance for the
eigenvectors of posterior mean S
av.G.coord <- array(, c(m, neigten, 1))
dimnames(av.G.coord) <- list(Gnames, paste("E", 1:neigten,
sep=""))
for (i in 1:neigten){
av.G.coord[,i,] <- apply((apply(Gs, 1:3, mean)) , 3,
frobenius.prod, y = eTmat[,,i])
}
#Coordinates of the jth avG for the eigentensors of
posterior mean S
MCMC.G.coord <- array(, c(m, neigten, MCMCsamp))
dimnames(MCMC.G.coord) <- list(Gnames, paste("E",
1:neigten, sep=""))
for (i in 1:neigten){
MCMC.G.coord[,i,] <- apply(Gs, 3:4, frobenius.prod, y =
eTmat[,,i])
}
#Coordinates of the kth MCMC sample of the jth G for the
eigentensors of posterior mean S
tensor.summary <- data.frame(rep(av.S.val,each=n),
t(data.frame(eT.eigen)))
colnames(tensor.summary) <- c("S.eigval", "eT.val", traitnames)
rownames(tensor.summary)<- paste(paste("e", rep(1:neigten,
each=n), sep=""), rep(1:n,neigten), sep=".")
list(tensor.summary = tensor.summary, av.S = av.S, eTmat = eTmat,
av.G.coord = av.G.coord, MCMC.S = MCMC.S, MCMC.S.val = MCMC.S.val,
MCMC.G.coord = MCMC.G.coord)
}
#END
The arguments passed to covtensor are:
Gs
The G array. Must be of the order n x n x m x MCMCsamp
The line below applies the covtensor function to the observed G array, then stores the results
in MCMC.covtensor.
MCMC.covtensor <- covtensor(Garray)
MCMC.covtensor is a list with 6 slots:
$tensor.summary
Summary of the covariance tensor for the posterior mean S
From left-to-right the columns of $tensor.summary are the
eigenvalues of the tensor (S.eigval), the eigenvalues of
eigentensors (eT.val), and the eigenvectors of eigentensors.
Eigenvectors of eigentensors are stored as rows with the trait
loadings identified by the column names. The eigenvectors of
eigentensors are ordered in terms of the absolute value of
eT.val
$av.S
Posterior mean S
$eTmat
Eigentensors of the posterior mean S. The rows and columns
of $eTmat identify the elements of an eigentensor. The third
dimension of $eTmat identifies the eigentensor.
$avG.coord
Coordinates of the posterior mean Gs in the space of the
eigentensors of the posterior mean S.
$MCMC.S
S for each MCMC sample of the set of G
$MCMC.S.val
Variance of the eigentensors for each MCMC sample of the
second-order representation of the fourth-order tensor
$MCMC.G.coord
Coordinates of each MCMC sample of G in the space of the
eigentensors of the posterior mean S.
The line below calculates the maximum number of nonzero eigentensors.
nnonzero <- min(n*(n+1)/2,m-1)
To examine the significance of the variance captured by the non-zero eigentensors we will use
the randomised G array to generate a null distribution of the variance among G. As we have done in
the examples above, we will apply the covtensor function to the randomised G array and store the
results in MCMC.covtensor.rand
MCMC.covtensor.rand <- covtensor(rand.Garray)
We can then examine the posterior means and 95% HPD intervals of the eigenvalues for the
nonzero eigentensors for the observed and randomised G arrays.
HPD.eT.val <cbind(HPDinterval(as.mcmc(MCMC.covtensor$MCMC.S.val[,1:nnonzero]),
prob=0.95),
HPDinterval(as.mcmc(MCMC.covtensor.rand$MCMC.S.val[,1:nnonzero]),
prob=0.95))
round(HPD.eT.val, 3)
#<
lower upper lower
E1 0.072 9.278 0.002
E2 0.089 1.103 0.001
E3 0.010 0.378 0.000
E4 0.001 0.211 0.000
E5 0.003 0.108 0.000
#>
upper
0.134
0.015
0.012
0.010
0.009
Figure 5. Eigenvalues of the non-zero eigentensors for posterior mean S, and 95% HPD
intervals of the eigenvalues of the non-zero eigentensors of S for each MCMC sample of the observed
and randomised G arrays.
In Figure 5 we can see that 95% HPD intervals of the observed E1 overlap the 95% HPD
intervals of E1 for the randomised data. Conversely, for E2, the 95% HPD intervals of the observed data
do not overlap those of the randomised data indicating that this dimension of the tensor describes
significant variation among G matrices. For E3 E4 and E5 the 95% HPD intervals of the observed and
randomised data do overlap. Therefore, it appears that E1 describes trait combinations that differ
most among G but there is also large uncertainty in this dimension. To examine these trait
combinations for E1 and E2 we can examine the first 16 (i.e. n*2) rows of the $tensor.summary.
round(MCMC.covtensor$tensor.summary[1:(n*2),2:dim(MCMC.covtensor$tensor.s
ummary)[2]], 3)
#<
eT.val
lc2
lc3
lc4
lc5
lc6
lc7
lc8
lc9
e1.1 -0.993 -0.089 -0.081 -0.097 -0.161 -0.223 -0.297 -0.816 -0.384
e1.2 0.106 0.263 -0.948 -0.113 -0.047 0.109 0.022 0.023 0.059
e1.3 0.050 -0.155 -0.099 0.032 -0.212 -0.257 -0.405 0.568 -0.606
e1.4 0.010 -0.511 -0.180 0.463 -0.410 -0.273 -0.098 -0.021 0.490
e1.5 0.004 0.720 0.167 0.493 -0.411 0.085 -0.183 -0.035 0.012
e1.6 -0.004 0.121 0.154 -0.721 -0.540 -0.099 -0.157 0.093 0.329
e1.7 0.001 -0.323 0.011 0.018 -0.404 0.824 0.075 -0.040 -0.215
e1.8 0.000 -0.036 0.009 -0.009 0.368 0.318 -0.821 0.004 0.295
e2.1 -0.990 0.249 -0.951 -0.129 -0.064 0.079 -0.031 -0.076 -0.013
e2.2 -0.120 0.388 0.031 -0.107 0.377 0.147 0.261 0.774 0.078
e2.3 0.056 -0.015 -0.028 0.070 0.064 -0.185 -0.244 0.197 -0.926
e2.4 -0.045 0.843 0.241 0.249 -0.163 0.169 -0.163 -0.289 -0.066
e2.5 0.021 -0.122 0.014 0.046 -0.799 0.355 -0.155 0.440 0.013
e2.6 0.012 -0.206 -0.018 0.197 0.223 0.814 0.311 -0.211 -0.255
e2.7 -0.010 -0.071 -0.181 0.906 -0.017 -0.253 0.218 0.140 0.097
e2.8 0.002 -0.123 -0.052 0.207 0.366 0.239 -0.822 0.122 0.240
#>
Next, we will examine the contribution of each population to the eigenvalues of the tensor by
plotting the coordinates of each G in the space of eigentensors E1 and E2.
Figure 6. Coordinates of the posterior mean G matrices and 95% HPD intervals of the
coordinates of the MCMC samples in the space of E1 and E2 for the posterior mean G of each
population.
In figure 6 we see that for E1 the b populations (b1 and b2) have large absolute values for the
coordinates of the posterior mean G, but also that these populations have a wide posterior density
intervals. For E2 on the other hand, it appears as that the m2 population is driving most of the
variation in this dimension. Furthermore, it is clear that the uncertainty surrounding the estimates of
the coordinates for E2 is less than for the coordinates of E1.
Last, to examine the contribution of specific trait combinations to coordinated changes among
G, we can project the eigenvectors of eigentensors on the observed G array. This projection yields
estimates of the genetic variance in the direction of the eigenvectors of eigentensors for each
population. The first eigenvector of the first eigentensor (e 11) and the first eigenvector of the second
eigentensor (e21) describe 85% and 79% of the variation in the first two eigentensors of the posterior
mean S (see the $tensor.summary). Hence, by projecting e 11 and e21on the observed G array we
can calculate the genetic variance in each population in the direction of the greatest variation among
G. To project eigenvectors of eigentensors on the observed G array we can use the lines of script
below.
e11 <c(as.numeric(MCMC.covtensor$tensor.summary[1,3:dim(MCMC.covtensor$tensor.
summary)[2]]))
#e11 vector
e21 <c(as.numeric(MCMC.covtensor$tensor.summary[(n+1),3:dim(MCMC.covtensor$ten
sor.summary)[2]]))
#e21 vector
proj<- function(G, b) t(b) %*% G %*% (b)
#Function to do projection
e11.proj
#genetic
e21.proj
#genetic
<- apply(Garray, 3:4, proj, b
variance along e1, 1 for each
<- apply(Garray, 3:4, proj, b
variance along e1, 1 for each
= e11)
MCMC sample of each replicate line
= e21)
MCMC sample of each replicate line
Figure 7. Posterior mean and 95% HPD interval for the genetic variance along the direction of
e11 and e21 for each replicate line.
In figure 7 we see that the b populations have high genetic variance in the direction of e11 but
also that there is a lot of uncertainty on these estimates of genetic variance. Conversely, in Figure 7e21
we see that the m2 population has high genetic variance in the direction e21, but the uncertainty in
the estimates of the genetic variation in this direction for the remaining populations is low.
Method 4. The decomposition of the multivariate breeder’s equation
When there is sufficient information to generate an estimate of β , we can use the well-known
breeders equation to identify differences among G matrices. Here we will use the sexual selection
gradient (beta) which is the non-normalized version of the Iss gradient presented in Hine et al. (2011).
beta <- c(-0.917,0.028,-0.163,-0.918,-2.083,3.472,4.936,-2.949)
Now that we have identified the direction along which we wish to examine differences among
our G matrices we can write the function to carry out the spectral decomposition of G.
#required packages
library(MCMCglmm)
#START
delta.Z <- function(Gs, B){
avG <- apply(Gs, 1:3, mean) #Calculate avG
avG.vec <- array(, c(n, n, m))
for (j in 1:m){
avG.vec[,,j] <- eigen(avG[,,j])$vectors
#Eigenvectors of the jth aveG
}
S.decompG <- function(e, G, b) (t(e) %*% G %*% e) %*% t(e %*% b) %*% e
#Function to calculate delta Z based on the spectral decomposition of a
G matrix
avG.Mv.Z <- array(, c(n, n, m))
dimnames(avG.Mv.Z) <- list(traitnames, traitnames, Gnames)
for (i in 1:n){
for (j in 1:m){
avG.Mv.Z[,i,j] <- S.decompG(avG.vec[,,j][,i], avG[,,j], B)
#Apply S.decompG to the ith eigenvector of the jth aveG
}
}
if(is.na(dim(Gs)[4])) {warning("There are no MCMCsamples"); MCMCG.Z <"NA"} else {
MCMC.Mv.Z <- array(,c(n, n, m, MCMCsamp))
dimnames(MCMC.Mv.Z) <- list(traitnames, traitnames, Gnames)
for (i in 1:n){
for (j in 1:m){
for (k in 1:MCMCsamp){
MCMC.Mv.Z[,i,j,k] <- S.decompG(avG.vec[,,j][,i], Gs[,,j,k], B)
#Apply S.decompG to the ith eigenvector of the jth G for the
kth MCMC sample
}
}
}
}
list(avG.Mv.Z = avG.Mv.Z, MCMC.Mv.Z = MCMC.Mv.Z)
}
#END
The arguments passed to delta.Z are:
Gs
The G array. Must be of the order n x n x m x MCMCsamp
B
The selection gradient. Must have the same number of elements as there are traits.
The line below applies the delta.Z function to the observed G array, assuming a known
selection gradient, then stores the results in MCMCdelta.Z.
MCMCdelta.Z <- delta.Z(Garray, beta)
MCMCdelta.Z is a list with 2 slots:
$avG.Mv.Z
Predicted response to selection along each axis of spectral decomposition of
the posterior mean G
$MCMC.Mv.Z
Predicted response to selection for each MCMC sample along each axis of
spectral decomposition the posterior mean G
From the output of delta.Z we could examine the overlap between 95% HPD intervals of
predicted responses to selection for all possible trait and population combinations, but given the
number of traits and the number of matrices this task can become tedious quickly. So, to identify traits
where the 95% HPD intervals of predicted responses to selection did not overlap between pairwise
combinations of populations we can use the following lines.
avG.Z <- apply(MCMCdelta.Z$avG.Mv.Z, 3, rowSums)
MCMC.Z <- apply(MCMCdelta.Z$MCMC.Mv.Z, 3:4, rowSums)
prs <- cbind(rep(1:m, each = m), 1:m)
prs.comp <- prs[prs[,1] < prs[,2], , drop = FALSE]
#setting up an index for HPD comparisons
Z.score <-matrix(, n, ((m^2 - m)/2))
rownames(Z.score)<-traitnames
colnames(Z.score) <- c(paste(Gnames[prs.comp[,1]], ".vs.",
Gnames[prs.comp[,2]], sep = ""))
#empty matrix to store the results
for (i in 1:n){
HPD.int <- HPDinterval(as.mcmc(t(MCMC.Z[i,,])), prob = 0.95)
Z.score[i,] <- ifelse(HPD.int[prs.comp[,1],1] >
HPD.int[prs.comp[,2],2] | HPD.int[prs.comp[,2],1] >
HPD.int[prs.comp[,1],2],1,0)
}
The object Z.score contains the results of all pair wise comparisons of delta Z for each trait
scored as: 0 if the 95% HPD intervals overlapped for a pair of replicate lines; or as 1 if the 95% HPD
intervals did not overlap for a pair of replicate lines.
Z.score
#<
b1.vs.b2 b1.vs.c1 b1.vs.c2 b1.vs.m1 b1.vs.m2 b2.vs.c1 b2.vs.c2
lc2
0
0
1
0
0
0
1
lc3
0
0
0
0
0
0
0
lc4
0
0
1
0
0
0
0
lc5
0
0
0
0
0
0
0
lc6
0
0
1
0
0
0
1
lc7
0
0
0
0
0
0
0
lc8
0
0
0
0
0
0
0
lc9
0
0
0
0
0
0
0
b2.vs.m1 b2.vs.m2 c1.vs.c2 c1.vs.m1 c1.vs.m2 c2.vs.m1 c2.vs.m2
lc2
0
0
0
0
0
0
0
lc3
0
0
0
0
0
0
0
lc4
0
0
0
0
0
0
0
lc5
0
0
0
0
0
0
0
lc6
0
0
0
0
0
0
0
lc7
0
0
0
0
0
0
0
lc8
0
0
0
0
0
0
0
lc9
0
0
0
0
0
0
0
m1.vs.m2
lc2
0
lc3
0
lc4
0
lc5
0
lc6
0
lc7
0
lc8
0
lc9
0
#>
The table above suggests that for our observed G array and our known β only lc2, lc4 and lc6
differ in their predicted response to selection. Furthermore, it appears that differences in the response
to selection are only significant for some pair wise comparisons (e.g. b1 vs. c2 for lc2). To see these
differences more clearly we can examine 95% HPD intervals of Δz for the lc2, lc4 and lc6 traits for these
populations.
sig.G <- cbind(1:n, ifelse(rowSums(Z.score) > 0, 1, 0))
sig.G <- subset(sig.G,sig.G[,2] == 1)
#index for the traits with significantly different predicted response to
selection among populations
HPD.deltaZ <- array(, c(m, 2, dim(sig.G)[1]))
dimnames(HPD.deltaZ) <- list(Gnames, c("lower", "upper"),
dimnames(sig.G)[[1]])
for (i in 1:dim(sig.G)[1]){
HPD.deltaZ[,,i] <- HPDinterval(as.mcmc(t(MCMC.Z[sig.G[i,1],,])))
}
round(HPD.deltaZ, 3)
#<
, , lc2
lower upper
b1 0.077 1.455
b2 0.081 2.190
c1 -0.176 0.554
c2 -0.276 0.007
m1 -0.424 0.425
m2 -0.916 0.569
, , lc4
lower upper
b1 0.162 1.442
b2 -0.031 2.337
c1 0.062 0.947
c2 -0.149 0.094
m1 -0.183 0.481
m2 -0.030 0.349
, , lc6
lower upper
b1 0.384 4.027
b2 -0.018 5.181
c1 -0.328 1.539
c2 -0.789 -0.025
m1 -0.800 1.078
m2 -0.671 0.862
#>
Figure 8. Posterior mean and 95% HPD interval for the predicted response to selection in traits
where we found significant pair wise differences among replicate populations. From left to right, the
plots correspond to traits: lc2, lc4 and lc6.
In figure 8 we can see that selection in the direction of β is likely to result in a greater change
in the trait means of lc2 and lc6 in the b1, and b2 populations compared with the c2 population. In the
lc4 trait however, selection along β is only likely to result in differences in the trait means among the
b1 and c2 populations. We can now examine the contribution of each of the eigenvectors of G to these
differences in the response to selection. Again, to concentrate on comparisons where we found
significant differences in Δz among populations, we can use the following script to generate an index
and plot the results.
sig.t <- cbind(1:(n*((m^2 - m)/2)), rep(1:n, ((m^2 - m)/2)),
matrix(rep(prs.comp, each = n), ncol = 2))
sig.t <- sig.t[c(which(Z.score > 0)),]
sig.t <- sig.t[order(sig.t[,2]),2:4]
#sets up an index of the traits and matrices that resulted in significant
differences in predicted response to selection
Figure 9. Posterior means and 95% HPD intervals for the predicted response to selection along
the eigenvectors of G for traits where we found significant pairwise differences among populations.
Black, white and grey symbols denote the b1, b2 and c2 populations respectively
In Figure 9 we can see that although significant differences in the response to selection can be
present in more than one axis of the greatest bias in the response to selection is along the direction of
gmax.
References
Hadfield J. D. 2010. MCMC Methods for Multi-Response Generalized Linear Mixed Models: The
MCMCglmm R Package. Journal of Statistical Software 33: 1-22.
Hansen T. F., D. Houle 2008. Measuring and comparing evolvability and constraint in multivariate
characters. J Evol Biol 21: 1201-1219.
Hine E., S. F. Chenoweth, H. D. Rundle, M. W. Blows 2009. Characterizing the evolution of genetic
variance using genetic covariance tensors. Phil Trans R Soc Lond B Biol Sci 364: 1567-1578.
Hine E., K. McGuigan, M. W. Blows 2011. Natural selection stops the evolution of male attractiveness.
Proc Natl Acad Sci USA 108: 3659-3664.
Krzanowski W. J. 1979. Between groups comparision of principal components. J Am Stat Assoc 74: 703707.
Example script for figures
Figure 1
par(mfrow=c(1,2))
HPD1 <- HPDinterval(as.mcmc(MCMC.R.proj$G.proj[,,3]))
plot(1:m,colMeans(MCMC.R.proj$G.proj[,,3]),yaxs =
"r",ylim=c(0,ceiling(max(HPD1))),xlab="",ylab="Va",pch=16,cex=1,xaxt="n",
frame.plot=F)
axis(1,at=1:m,labels=Gnames)
arrows(1:m,colMeans(MCMC.R.proj$G.proj[,,3]),1:m,HPD1[,1],length=0.1,angl
e = 90)
arrows(1:m,colMeans(MCMC.R.proj$G.proj[,,3]),1:m,HPD1[,2],length=0.1,angl
e=90)
mtext("A",side=3,at=0,font=2)
HPD2 <- HPDinterval(as.mcmc(MCMC.R.proj$G.proj[,,5]))
plot(1:m,colMeans(MCMC.R.proj$G.proj[,,5]),ylim=c(0,ceiling(max(HPD2))),x
lab="",ylab="Va",pch=16,cex=1,xaxt="n",frame.plot=F)
axis(1,at=1:m,labels=Gnames)
arrows(1:m,colMeans(MCMC.R.proj$G.proj[,,5]),1:m,HPD2[,1],length=0.1,angl
e=90)
arrows(1:m,colMeans(MCMC.R.proj$G.proj[,,5]),1:m,HPD2[,2],length=0.1,angl
e=90)
mtext("B",side=3,at=0,font=2)
Figure 2
par(mfrow=c(3,3))
for (i in 1:n){
plot(1:m,colMeans(R.vec.proj[,,i]),ylab="Va",xlab="",pch=16,xaxt="n",fram
e.plot=F,xlim=c(0,7),ylim=c(0,ceiling(max(HPD.R.vec.proj[,,i]))))
axis(1,at=1:m,labels=Gnames)
arrows(1:m,colMeans(R.vec.proj[,,i]),1:m,HPD.R.vec.proj[,1,i],length=0.1,
angle=90)
arrows(1:m,colMeans(R.vec.proj[,,i]),1:m,HPD.R.vec.proj[,2,i],
length=0.1,angle=90)
}
Figure 3
HPD.H.val <- cbind(HPDinterval(as.mcmc(MCMCG.kr$MCMC.H.val)),
HPDinterval(as.mcmc(MCMCG.kr.rand$MCMC.H.val)))
par(mfrow=c(1,1))
plot((1:n)0.1,colMeans(MCMCG.kr$MCMC.H.val),type="p",xlab="",ylab="lamda",pch=16,ce
x=1,xaxt="n",frame.plot=F,ylim=c(0,m),xlim=c(0.5,8.5))
axis(1,at=1:8,labels=c(paste("h",rep(1:n),sep="")))
points((1:n)+0.1,colMeans(MCMCG.kr.rand$MCMC.H.val),type="p",pch=1,cex=1)
arrows((1:n)-0.1,colMeans(MCMCG.kr$MCMC.H.val),(1:n)0.1,HPD.H.val[,1],length=0.1,angle=90)
arrows((1:n)-0.1,colMeans(MCMCG.kr$MCMC.H.val),(1:n)0.1,HPD.H.val[,2],length=0.1,angle=90)
arrows((1:n)+0.1,colMeans(MCMCG.kr.rand$MCMC.H.val),(1:n)+0.1,HPD.H.val[,
3],length=0.1,angle=90,lty=5)
arrows((1:n)+0.1,colMeans(MCMCG.kr.rand$MCMC.H.val),(1:n)+0.1,HPD.H.val[,
4],length=0.1,angle=90,lty=5)
legend(5.5,6,legend=c("observed","randomised"),lty=c(1,5),pch=c(16,1),cex
=1,bty="n")
Figure 4
HPD.H.val1 <- cbind(HPDinterval(as.mcmc(MCMCG.kr1$MCMC.H.val)),
HPDinterval(as.mcmc(MCMCG.kr.rand1$MCMC.H.val)))
par(mfrow=c(1,1))
plot((1:n)0.1,colMeans(MCMCG.kr1$MCMC.H.val),type="p",xlab="",ylab="lamda",pch=16,c
ex=1,xaxt="n",frame.plot=F,ylim=c(0,m),xlim=c(0.5,8.5))
axis(1,at=1:8,labels=c(paste("h",rep(1:n),sep="")))
points((1:n)+0.1,colMeans(MCMCG.kr.rand1$MCMC.H.val),type="p",pch=1,cex=1
)
arrows((1:n)-0.1,colMeans(MCMCG.kr1$MCMC.H.val),(1:n)0.1,HPD.H.val1[,1],length=0.1,angle=90)
arrows((1:n)-0.1,colMeans(MCMCG.kr1$MCMC.H.val),(1:n)0.1,HPD.H.val1[,2],length=0.1,angle=90)
arrows((1:n)+0.1,colMeans(MCMCG.kr.rand1$MCMC.H.val),(1:n)+0.1,HPD.H.val1
[,3],length=0.1,angle=90,lty=5)
arrows((1:n)+0.1,colMeans(MCMCG.kr.rand1$MCMC.H.val),(1:n)+0.1,HPD.H.val1
[,4],length=0.1,angle=90,lty=5)
legend(5.5,6,legend=c("observed","randomised"),lty=c(1,5),pch=c(16,1),cex
=1,bty="n")
Figure 5
par(mfrow=c(1,1))
plot((1:nnonzero)0.2,unique(MCMC.covtensor$tensor.summary[1:(n*nnonzero),1]),xlab="",ylab=
"alpha",pch=16,cex=1,xaxt="n",frame.plot=F,xlim=c(0.5,5.5),ylim=c(0,max(H
PD.eT.val)))
axis(1,at=1:nnonzero,labels=c(paste("E",rep(1:nnonzero),sep="")))
points((1:nnonzero)+0.2,
unique(MCMC.covtensor.rand$tensor.summary[1:(n*nnonzero),1]),pch=1,cex=1)
arrows((1:nnonzero)-0.2,
unique(MCMC.covtensor$tensor.summary[1:(n*nnonzero),1]),(1:nnonzero)0.2,HPD.eT.val[,1],length=0.1,angle=90)
arrows((1:nnonzero)-0.2,
unique(MCMC.covtensor$tensor.summary[1:(n*nnonzero),1]),(1:nnonzero)0.2,HPD.eT.val[,2],length=0.1,angle=90)
arrows((1:nnonzero)+0.2,
unique(MCMC.covtensor.rand$tensor.summary[1:(n*nnonzero),1]),(1:nnonzero)
+0.2,HPD.eT.val[,3],length=0.1,angle=90,lty=5)
arrows((1:nnonzero)+0.2,
unique(MCMC.covtensor.rand$tensor.summary[1:(n*nnonzero),1]),(1:nnonzero)
+0.2,HPD.eT.val[,4],length=0.1,angle=90,lty=5)
legend(3.5,8,legend=c("observed","randomised"),lty=c(1,5),pch=c(16,1),cex
=1,bty="n")
Figure 6
HPD.tensor.coord <- array(,c(m,2,nnonzero))
dimnames(HPD.tensor.coord) <- list(Gnames,c("lower","upper"),
paste("E",1:5,sep=" "))
for (i in 1:m){
for (j in 1:nnonzero){
HPD.tensor.coord[i,,j] <HPDinterval(as.mcmc(MCMC.covtensor$MCMC.G.coord[i,j,]),prob=0.95)[1:2]
}
}
par(mfrow=c(1,2))
for (k in 1:2){
plot(1:m,MCMC.covtensor$av.G.coord[,k,],ylab="",xlab="",pch=16,xaxt="n",f
rame.plot=F,xlim=c(0.5,6.5),ylim=c(floor(min(HPD.tensor.coord[,,k])),ceil
ing(max(HPD.tensor.coord[,,k]))),main = "")
axis(1,at=1:m,labels=Gnames)
arrows(1:m,MCMC.covtensor$av.G.coord[,k,],1:m,HPD.tensor.coord[,1,k],leng
th=0.1,angle=90)
arrows(1:m,MCMC.covtensor$av.G.coord[,k,],1:m,HPD.tensor.coord[,2,k],leng
th=0.1,angle=90)
mtext(dimnames(MCMC.covtensor$av.G.coord)[[2]][k],side=3,at=0,font=2)
}
Figure 7
HPD.e11 <- HPDinterval(t(as.mcmc(e11.proj)),prob = 0.95)
HPD.e21 <- HPDinterval(t(as.mcmc(e21.proj)),prob = 0.95)
par(mfrow=c(1,2))
plot(1:m,rowMeans(e11.proj),ylab="lamda",xlab="",pch=16,cex =
1,xaxt="n",frame.plot=F,xlim=c(0,7),ylim=c(0,ceiling(max(HPD.e11))))
axis(1,at=1:m,labels=Gnames)
arrows(1:m,rowMeans(e11.proj),1:m,HPD.e11[,1],length=0.1,angle=90)
arrows(1:m,rowMeans(e11.proj),1:m,HPD.e11[,2],length=0.1,angle=90)
mtext("e11",side=3,at=0,font=2)
plot(1:m,rowMeans(e21.proj),ylab="lamda",xlab="",pch=16,cex=1,xaxt="n",fr
ame.plot=F,xlim=c(0,7),ylim=c(0,ceiling(max(HPD.e21))))
axis(1,at=1:m,labels=Gnames)
arrows(1:m,rowMeans(e21.proj),1:m,HPD.e21[,1],length=0.1,angle=90)
arrows(1:m,rowMeans(e21.proj),1:m,HPD.e21[,2],length=0.1,angle=90)
mtext("e21",side=3,at=0,font=2)
Figure 8
par(mfrow=c(1,3))
for (k in 1:dim(sig.G)[1]){
plot(1:m,avG.Z[sig.G[k,1],],ylab="delta.Z",xlab="",pch=16,xaxt="n",frame.
plot=F,ylim=c(floor(min(HPD.deltaZ[,,k])),ceiling(max(HPD.deltaZ[,,k]))))
axis(1,at=1:m,labels=Gnames)
arrows(1:m,avG.Z[sig.G[k,1],],1:m,HPD.deltaZ[,1,k],length=0.1,angle=90)
arrows(1:m,avG.Z[sig.G[k,1],],1:m,HPD.deltaZ[,2,k],length=0.1,angle=90)
mtext(rownames(sig.G)[k],side=3,at=0,font=2)
}
Figure 9
par(mfrow=c(1,3))
for (i in 1:dim(sig.G)[1]){
t.index <- unique(as.numeric(sig.t[c(which(sig.t[,1]==sig.G[i,1])),2:3]))
HPD.deltaZ.vec <- array(,c(length(t.index),2,n))
for (k in 1:n){
HPD.deltaZ.vec[,,k] <HPDinterval(as.mcmc(t(MCMCdelta.Z$MCMC.Mv.Z[sig.G[i,1],k,c(t.index),])))
}
if(length(t.index)==2) {
plot(1:n0.2,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[1]],ylab="delta.Z",xlab="",p
ch=16,xaxt="n",frame.plot=F,ylim=c(-1,6),xlim=c(0,9))
axis(1,at=1:n,labels=c("gmax",paste("g",2:n,sep="")))
arrows(1:n-0.2,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[1]],1:n0.2,HPD.deltaZ.vec[1,1,],length=0.1,angle=90)
arrows(1:n-0.2,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[1]],1:n0.2,HPD.deltaZ.vec[1,2,],length=0.1,angle=90)
points(1:n,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[2]],
pch=21,bg="grey")
arrows(1:n,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[2]],1:n,HPD.deltaZ.ve
c[2,1,],length=0.1,angle=90,lty=4)
arrows(1:n,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[2]],1:n,HPD.deltaZ.ve
c[2,2,],length=0.1,angle=90,lty=4)
mtext(rownames(sig.G)[i],side=3,at=0,font=2)
}
if(length(t.index)==3) {
plot(1:n0.2,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[1]],ylab="delta.Z",xlab="",p
ch=16,xaxt="n",frame.plot=F,ylim=c(-1,6),xlim=c(0,9))
axis(1,at=1:n,labels=c("gmax",paste("g",2:n,sep="")))
arrows(1:n-0.2,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[1]],1:n0.2,HPD.deltaZ.vec[1,1,],length=0.1,angle=90)
arrows(1:n-0.2,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[1]],1:n0.2,HPD.deltaZ.vec[1,2,],length=0.1,angle=90)
points(1:n,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[2]],pch=1)
arrows(1:n,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[2]],1:n,HPD.deltaZ.ve
c[2,1,],length=0.1,angle=90,lty=4)
arrows(1:n,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[2]],1:n,HPD.deltaZ.ve
c[2,2,],length=0.1,angle=90,lty=4)
points(1:n,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[3]],pch=21,bg="grey")
arrows(1:n,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[3]],1:n,HPD.deltaZ.ve
c[3,1,],length=0.1,angle=90,lty=5)
arrows(1:n,MCMCdelta.Z$avG.Mv.Z[sig.G[i,1],,t.index[3]],1:n,HPD.deltaZ.ve
c[3,2,],length=0.1,angle=90,lty=5)
mtext(rownames(sig.G)[i],side=3,at=0,font=2)
}
}
Download