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) } }