]> git.donarmstrong.com Git - ape.git/blob - R/pic.R
final commit for ape 3.0-8
[ape.git] / R / pic.R
1 ## pic.R (2013-02-18)
2
3 ##   Phylogenetically Independent Contrasts
4
5 ## Copyright 2002-2013 Emmanuel Paradis
6
7 ## This file is part of the R-package `ape'.
8 ## See the file ../COPYING for licensing issues.
9
10 pic <- function(x, phy, scaled = TRUE, var.contrasts = FALSE, rescaled.tree = FALSE)
11 {
12     if (!inherits(phy, "phylo")) stop("object 'phy' is not of class \"phylo\"")
13     if (is.null(phy$edge.length)) stop("your tree has no branch lengths")
14     nb.tip <- length(phy$tip.label)
15     nb.node <- phy$Nnode
16     if (nb.node != nb.tip - 1)
17         stop("'phy' is not rooted and fully dichotomous")
18     if (length(x) != nb.tip)
19         stop("length of phenotypic and of phylogenetic data do not match")
20     if (any(is.na(x)))
21         stop("missing data in 'x': you may consider removing the species with missing data from your tree with the function 'drop.tip'.")
22
23     phy <- reorder(phy, "postorder")
24     phenotype <- numeric(nb.tip + nb.node)
25
26     if (is.null(names(x))) {
27         phenotype[1:nb.tip] <- x
28     } else {
29         if (all(names(x) %in% phy$tip.label))
30           phenotype[1:nb.tip] <- x[phy$tip.label]
31         else {
32             phenotype[1:nb.tip] <- x
33             warning("the names of argument 'x' and the tip labels of the tree did not match: the former were ignored in the analysis.")
34         }
35     }
36
37     ## No need to copy the branch lengths: they are rescaled
38     ## in the C code, so it's important to leave the default
39     ## `DUP = TRUE' of .C.
40     ans <- .C("pic", as.integer(nb.tip), as.integer(nb.node),
41               as.integer(phy$edge[, 1]), as.integer(phy$edge[, 2]),
42               as.double(phy$edge.length), as.double(phenotype),
43               double(nb.node), double(nb.node),
44               as.integer(var.contrasts), as.integer(scaled),
45               PACKAGE = "ape")
46
47     contr <- ans[[7]]
48     lbls <-
49         if (is.null(phy$node.label)) as.character(1:nb.node + nb.tip)
50         else phy$node.label
51     if (var.contrasts) {
52         contr <- cbind(contr, ans[[8]])
53         dimnames(contr) <- list(lbls, c("contrasts", "variance"))
54     } else names(contr) <- lbls
55     if (rescaled.tree) {
56         phy$edge.length <- ans[[5]]
57         contr <- list(contr = contr, rescaled.tree = phy)
58     }
59     contr
60 }
61
62 pic.ortho <- function(x, phy, var.contrasts = FALSE, intra = FALSE)
63 {
64     n <- length(x)
65     m <- n - 1L # number of nodes
66     phy <- reorder(phy, "postorder")
67     xx <- unlist(lapply(x, mean)) # 'x' in Felsenstein's paper
68     xx <- c(xx, numeric(m))
69     delta.v <- numeric(n + m)
70     s <- 1/unlist(lapply(x, length))
71     s <- c(s, numeric(m))
72     contrast <- var.cont <- numeric(m)
73
74     i <- 1L
75     while (i < m + n) {
76         d1 <- phy$edge[i, 2]
77         d2 <- phy$edge[i + 1L, 2]
78         a <- phy$edge[i, 1]
79         tmp1 <- 1/(phy$edge.length[i] + delta.v[d1])
80         tmp2 <- 1/(phy$edge.length[i + 1L] + delta.v[d2])
81         xx[a] <- (tmp1 * xx[d1] + tmp2 * xx[d2])/(tmp1 + tmp2)
82         delta.v[a] <- 1/(tmp1 + tmp2)
83         f1 <- tmp1/(tmp1 + tmp2)
84         f2 <- tmp2/(tmp1 + tmp2)
85         s[a] <- f1*f1 * s[d1] + f2*f2 * s[d2]
86         tmp <- 1/(s[d1] + s[d2])
87         contrast[a - n] <- (xx[d1] - xx[d2]) * sqrt(tmp)
88         var.cont[a - n] <- (1/tmp1 + 1/tmp2) * tmp
89         i <- i + 2L
90     }
91
92     lbls <-
93         if (is.null(phy$node.label)) as.character(1:m + n)
94         else phy$node.label
95
96     if (var.contrasts) {
97         contrast <- cbind(contrast, var.cont)
98         dimnames(contrast) <- list(lbls, c("contrasts", "variance"))
99     } else names(contrast) <- lbls
100
101     if (intra) {
102         intraspe.ctr <- function(x) {
103             k <- length(x) - 1L
104             if (!k) return(NULL)
105             ctr <- numeric(k)
106             ctr[1L] <- x[1L] - x[2L]
107             if (k > 1)
108                 for (i in 2:k)
109                     ctr[i] <- x[i + 1L] - mean(x[1:i])
110             sqrt((1:k)/(1:k + 1)) * ctr
111         }
112         tmp <- lapply(x, intraspe.ctr)
113         names(tmp) <- phy$tip.label
114         attr(contrast, "intra") <- tmp
115     }
116
117     contrast
118 }
119
120 varCompPhylip <- function(x, phy, exec = NULL)
121 {
122     n <- Ntip(phy)
123     if (is.vector(x)) x <- as.list(x)
124     if (is.matrix(x) || is.data.frame(x)) {
125         tmpx <- vector("list", n)
126         for (i in 1:n) tmpx[[i]] <- x[i, , drop = FALSE]
127         names(tmpx) <- rownames(x)
128         x <- tmpx
129     }
130     p <- if (is.vector(x[[1]])) 1L else ncol(x[[1]])
131     if (!is.null(names(x))) x <- x[phy$tip.label]
132
133     phy <- makeLabel(phy, len = 10)
134     lbs <- phy$tip.label
135
136     ni <- sapply(x, function(xx) if (is.vector(xx)) 1L else nrow(xx))
137
138     pfx <- tempdir()
139     write.tree(phy, file = paste(pfx, "intree", sep = "/"))
140     infile <- paste(pfx, "infile", sep = "/")
141     file.create(infile)
142     cat(n, " ", p, "\n", sep = "", file = infile, append = TRUE)
143     for (i in 1:n) {
144         cat(lbs[i], file = infile, append = TRUE)
145         ## can surely be better but OK for the moment:
146         cat(paste(rep(" ", 11 - nchar(lbs[i])), collapse = ""),
147             file = infile, append = TRUE)
148         cat(ni[i], "\n", sep = "", file = infile, append = TRUE)
149         if (ni[i] == 1) {
150             cat(x[[i]], sep = " ", file = infile, append = TRUE)
151             cat("\n", file = infile, append = TRUE)
152         } else write(t(x[[i]]), file = infile, ncolumns = p, append = TRUE)
153     }
154
155     if (is.null(exec))
156         exec <-
157             if (.Platform$OS.type == "unix") "phylip contrast"
158             else "contrast"
159
160     odir <- setwd(pfx)
161     on.exit(setwd(odir))
162     if (file.exists("outfile")) unlink("outfile")
163     system(exec, intern = TRUE, input = c("W", "A", "Y"))
164     varA <- scan("outfile", skip = 7, nlines = p, quiet = TRUE)
165     varE <- scan("outfile", skip = 11 + p, nlines = p, quiet = TRUE)
166     if (p > 1) {
167         varA <- matrix(varA, p, p, byrow = TRUE)
168         varE <- matrix(varE, p, p, byrow = TRUE)
169     }
170     list(varA = varA, varE = varE)
171 }