]> git.donarmstrong.com Git - ape.git/blob - R/bind.tree.R
new mixedFontLabel() + bug fix in rTraitCont.c
[ape.git] / R / bind.tree.R
1 ## bind.tree.R (2010-05-25)
2
3 ##    Bind Trees
4
5 ## Copyright 2003-2010 Emmanuel Paradis
6
7 ## This file is part of the R-package `ape'.
8 ## See the file ../COPYING for licensing issues.
9
10 `+.phylo` <- function(x, y)
11 {
12     p <- if (is.null(x$root.edge)) 0 else x$root.edge
13     bind.tree(x, y, position = p)
14 }
15
16 bind.tree <- function(x, y, where = "root", position = 0, interactive = FALSE)
17 {
18     nx <- length(x$tip.label)
19     mx <- x$Nnode
20     ROOTx <- nx + 1L
21     ny <- length(y$tip.label)
22     my <- y$Nnode
23
24     if (interactive) {
25         lastPP <- get("last_plot.phylo", envir = .PlotPhyloEnv)
26         if (lastPP$type != "phylogram" || lastPP$direction != "rightwards")
27             stop("you must plot tree 'x' as a 'rightward phylogram'")
28         cat("Click where you want to graft tree 'y'...\n")
29         xy <- locator(1)
30         d <- abs(xy$y - lastPP$yy)
31         d[lastPP$xx - xy$x < 0] <- Inf
32         where <- which.min(d)
33         position <- lastPP$xx[where] - xy$x
34         if (position < 0) position <- 0
35         cat("The following parameters are used:\n")
36         cat("  where =", where, " position =", position, "\n")
37     } else {
38         if (where == 0 || where == "root") where <- ROOTx
39         if (position < 0) position <- 0
40         if (where > nx + mx)
41             stop("argument 'where' out of range for tree 'x'")
42     }
43
44     ## check whether both trees have branch lengths:
45     switch(is.null(x$edge.length) + is.null(y$edge.length) + 1L,
46            wbl <- TRUE, {
47                x$edge.length <- y$edge.length <- NULL
48                wbl <- FALSE
49                warning("one tree has no branch lengths, they have been ignored")
50            },
51            wbl <- FALSE)
52
53     yHasNoRootEdge <- is.null(y$root.edge)
54     xHasNoRootEdge <- is.null(x$root.edge)
55
56     ## find the row of 'where' before renumbering
57     if (where == ROOTx) case <- 1 else {
58         i <- which(x$edge[, 2] == where)
59         case <- if (where <= nx) 2 else 3
60     }
61     ## case = 1 -> y is bound on the root of x
62     ## case = 2 -> y is bound on a tip of x
63     ## case = 3 -> y is bound on a node of x
64
65     ## check that 'position' is correct
66     if (position) {
67         if (!wbl)
68             stop("'position' is non-null but trees have no branch lengths")
69         if (case == 1) {
70             if (xHasNoRootEdge)
71                 stop("tree 'x' has no root edge")
72             if (position > x$root.edge)
73                 stop("'position' is larger than x's root edge")
74         } else {
75             if (x$edge.length[i] < position)
76                 stop("'position' is larger than the branch length")
77         }
78     }
79
80     ## the special of substituting two tips:
81     if (case == 2 && ny == 1 && !position) {
82         x$tip.label[x$edge[i, 2]] <- y$tip.label
83         if (wbl)
84             x$edge.length[i] <- x$edge.length[i] + y$edge.length
85         return(x)
86     }
87
88     x <- reorder(x)
89     y <- reorder(y)
90
91 ### because in all situations internal nodes need to be renumbered,
92 ### they are changed to negatives first, and nodes that eventually
93 ### will be added will be numbered sequentially
94
95     nodes <- x$edge > nx
96     x$edge[nodes] <- -(x$edge[nodes] - nx) # -1, ..., -mx
97     nodes <- y$edge > ny
98     y$edge[nodes] <- -(y$edge[nodes] - ny + mx) #  -(mx+1), ..., -(mx+my)
99     ROOT <- -1L # may change later
100     next.node <- -(mx + my) - 1L
101
102     ## renumber now the tips in y:
103     new.nx <- if (where <= nx && !position) nx - 1L else nx
104     y$edge[!nodes] <- y$edge[!nodes] + new.nx
105
106     ## if 'y' as a root edge, use it:
107     if (!yHasNoRootEdge) {
108         y$edge <- rbind(c(0, y$edge[1]), y$edge)
109         ##                ^ will be filled later
110         next.node <- next.node - 1L
111         if (wbl) y$edge.length <- c(y$root.edge, y$edge.length)
112     }
113
114     switch(case, { # case = 1
115         if (position) {
116             x$root.edge <- x$root.edge - position
117             x$edge <- rbind(c(next.node, x$edge[1]), x$edge)
118             ROOT <- next.node
119             if (wbl) x$edge.length <- c(position, x$edge.length)
120         }
121         if (yHasNoRootEdge) {
122             j <- which(y$edge[, 1] == y$edge[1])
123             y$edge[j, 1] <- ROOT
124         } else y$edge[1] <- ROOT
125         x$edge <- rbind(x$edge, y$edge)
126         if (wbl)
127             x$edge.length <- c(x$edge.length, y$edge.length)
128     }, { # case = 2
129         if (position) {
130             x$edge[i, 2] <- next.node
131             x$edge <- rbind(x$edge[1:i, ], c(next.node, where), x$edge[-(1:i), ])
132             if (wbl) {
133                 x$edge.length[i] <- x$edge.length[i] - position
134                 x$edge.length <- c(x$edge.length[1:i], position, x$edge.length[-(1:i)])
135             }
136             i <- i + 1L
137             if (yHasNoRootEdge) {
138                 j <- which(y$edge[, 1] == y$edge[1])
139                 y$edge[j, 1] <- x$edge[i, 1]
140             } else y$edge[1] <- x$edge[i, 1]
141         } else {
142             if (yHasNoRootEdge) x$edge[i, 2] <- y$edge[1]
143             else {
144                 ## the root edge of y is fused with the terminal edge of x
145                 if (wbl) y$edge.length[1] <- y$edge.length[1] + x$edge.length[i]
146                 y$edge[1] <- x$edge[i, 1]
147                 ## delete i-th edge in x:
148                 x$edge <- x$edge[-i, ]
149                 i <- i - 1L
150                 if (wbl) x$edge.length <- x$edge.length[-i]
151             }
152             x$tip.label <- x$tip.label[-where]
153             ## renumber the tips that need to:
154             ii <- which(x$edge[, 2] > where & x$edge[, 2] <= nx)
155             x$edge[ii, 2] <- x$edge[ii, 2] - 1L
156         }
157         x$edge <- rbind(x$edge[1:i, ], y$edge, x$edge[-(1:i), ])
158         if (wbl)
159             x$edge.length <- c(x$edge.length[1:i], y$edge.length, x$edge.length[-(1:i)])
160     }, { # case = 3
161         if (position) {
162             if (yHasNoRootEdge) {
163                 j <- which(y$edge[, 1] == y$edge[1])
164                 y$edge[j, 1] <- next.node
165             } else y$edge[1] <- next.node
166             x$edge <- rbind(x$edge[1:i, ], c(next.node, x$edge[i, 2]), x$edge[-(1:i), ])
167             x$edge[i, 2] <- next.node
168             if (wbl) {
169                 x$edge.length[i] <- x$edge.length[i] - position
170                 x$edge.length <- c(x$edge.length[1:i], position, x$edge.length[-(1:i)])
171             }
172             i <- i + 1L
173         } else {
174             if (yHasNoRootEdge) {
175                 j <- which(y$edge[, 1] == y$edge[1])
176                 y$edge[j, 1] <- x$edge[i, 2]
177             } else y$edge[1] <- x$edge[i, 2]
178         }
179         x$edge <- rbind(x$edge[1:i, ], y$edge, x$edge[-(1:i), ])
180         if (wbl)
181             x$edge.length <- c(x$edge.length[1:i], y$edge.length, x$edge.length[-(1:i)])
182     })
183
184     x$tip.label <- c(x$tip.label, y$tip.label)
185
186     if (is.null(x$node.label)) {
187         if (!is.null(y$node.label))
188             x$node.label <- c(rep(NA, mx), y$node.label)
189     } else {
190         x$node.label <-
191             if (is.null(y$node.label)) c(x$node.label, rep(NA, my))
192             else c(x$node.label, y$node.label)
193     }
194
195     n <- length(x$tip.label)
196     x$Nnode <- dim(x$edge)[1] + 1L - n
197
198     ## update the node labels before renumbering (this adds NA for
199     ## the added nodes, and drops the label for those deleted)
200     if (!is.null(x$node.label))
201         x$node.label <- x$node.label[-unique(x$edge[, 1])]
202
203     ## renumber nodes:
204     newNb <- integer(x$Nnode)
205     newNb[-ROOT] <- n + 1L
206     sndcol <- x$edge[, 2] < 0
207     ## executed from right to left, so newNb is modified before x$edge:
208     x$edge[sndcol, 2] <- newNb[-x$edge[sndcol, 2]] <-
209         (n + 2):(n + x$Nnode)
210     x$edge[, 1] <- newNb[-x$edge[, 1]]
211
212     if (!is.null(x$node.label))
213         x$node.label <- x$node.label[newNb[newNb == 0] - n]
214
215     x
216 }