]> git.donarmstrong.com Git - ape.git/blob - R/cophyloplot.R
new option 'rotate.tree' in plot.phylo()
[ape.git] / R / cophyloplot.R
1 ## cophyloplot.R (2010-03-18)
2
3 ##   Plots two phylogenetic trees face to
4 ##   face with the links between the tips
5
6 ## Copyright 2008-2010 Damien de Vienne
7
8 ## This file is part of the R-package `ape'.
9 ## See the file ../COPYING for licensing issues.
10
11 cophyloplot <-
12     function(x, y, assoc = NULL, use.edge.length = FALSE, space = 0,
13              length.line = 1, gap = 2, type = "phylogram", rotate = FALSE,
14              col = par("fg"), lwd = par("lwd"), lty = par("lty"),
15              show.tip.label = TRUE, font = 3, ...)
16 {
17     if (is.null(assoc)) {
18         assoc <- matrix(ncol = 2)
19         print("No association matrix specified. Links will be omitted.")
20     }
21     if (rotate == TRUE) {
22         cat("\n    Click on a node to rotate (right click to exit)\n\n")
23         repeat {
24             res <- plotCophylo2(x, y, assoc = assoc, use.edge.length = use.edge.length,
25                 space = space, length.line = length.line, gap = gap,
26                 type = type, return = TRUE, col = col, lwd=lwd, lty=lty, show.tip.label = show.tip.label,
27                 font = font)
28             click <- identify(res$c[, 1], res$c[, 2], n = 1)
29             if (click < length(res$a[, 1]) + 1) {
30                 if (click > res$N.tip.x)
31                   x <- rotate(x, click)
32             }
33             else if (click < length(res$c[, 1]) + 1) {
34                 if (click > length(res$a[, 1]) + res$N.tip.y)
35                   y <- rotate(y, click - length(res$a[, 1]))
36             }
37             plotCophylo2(x, y, assoc = assoc, use.edge.length = use.edge.length,
38                 space = space, length.line = length.line, gap = gap,
39                 type = type, return = TRUE, col = col, lwd=lwd, lty=lty, show.tip.label = show.tip.label, font = font)
40         }
41         on.exit(print("done"))
42     }
43     else plotCophylo2(x, y, assoc = assoc, use.edge.length = use.edge.length,
44         space = space, length.line = length.line, gap = gap,
45         type = type, return = FALSE, col = col, lwd=lwd, lty=lty, show.tip.label = show.tip.label, font = font)
46 }
47
48 plotCophylo2 <-
49     function (x, y, assoc = assoc, use.edge.length = use.edge.length,
50               space = space, length.line = length.line, gap = gap,
51               type = type, return = return, col = col, lwd=lwd, lty=lty,
52               show.tip.label = show.tip.label,
53               font = font, ...)
54 {
55     res <- list()
56 ###choice of the minimum space between the trees
57     left <- max(nchar(x$tip.label, type = "width")) + length.line
58     right <- max(nchar(y$tip.label, type = "width")) + length.line
59     space.min <- left + right + gap * 2
60     if ((space <= 0) || (space < space.min)) space <- space.min
61     N.tip.x <- Ntip(x)
62     N.tip.y <- Ntip(y)
63     res$N.tip.x <- N.tip.x
64     res$N.tip.y <- N.tip.y
65     a <- plotPhyloCoor(x, use.edge.length = use.edge.length, type = type)
66     res$a <- a
67     b <- plotPhyloCoor(y, use.edge.length = use.edge.length,
68                        direction = "leftwards", type = type)
69 ###for the two trees to have the extreme leaves at the same ordinate.
70     a[, 2] <- a[, 2] - min(a[, 2])
71     b[, 2] <- b[, 2] - min(b[, 2])
72     res$b <- b
73     b2 <- b
74     b2[, 1] <- b[1:nrow(b), 1] * (max(a[, 1])/max(b[, 1])) +
75         space + max(a[, 1])
76     b2[, 2] <- b[1:nrow(b), 2] * (max(a[, 2])/max(b[, 2]))
77     res$b2 <- b2
78     c <- matrix(ncol = 2, nrow = nrow(a) + nrow(b))
79     c[1:nrow(a), ] <- a[1:nrow(a), ]
80     c[nrow(a) + 1:nrow(b), 1] <- b2[, 1]
81     c[nrow(a) + 1:nrow(b), 2] <- b2[, 2]
82     res$c <- c
83     plot(c, type = "n", xlim = NULL, ylim = NULL, log = "", main = NULL,
84         sub = NULL, xlab = NULL, ylab = NULL, ann = FALSE, axes = FALSE,
85         frame.plot = FALSE)
86  ###segments for cladograms
87    if (type == "cladogram") {
88         for (i in 1:(nrow(a) - 1)) segments(a[x$edge[i, 1], 1],
89             a[x$edge[i, 1], 2], a[x$edge[i, 2], 1], a[x$edge[i,
90                 2], 2], col="red")
91         for (i in 1:(nrow(b) - 1))
92             segments(b2[y$edge[i, 1], 1], b2[y$edge[i, 1], 2],
93                      b2[y$edge[i, 2], 1], b2[y$edge[i, 2], 2])
94     }
95 ###segments for phylograms
96     if (type == "phylogram") {
97         for (i in (N.tip.x + 1):nrow(a)) {
98             l <- length(x$edge[x$edge[, 1] == i, ][, 1])
99             for (j in 1:l) {
100                 segments(a[x$edge[x$edge[, 1] == i, ][1, 1],
101                   1], a[x$edge[x$edge[, 1] == i, 2], 2][1], a[x$edge[x$edge[,
102                   1] == i, ][1, 1], 1], a[x$edge[x$edge[, 1] ==
103                   i, 2], 2][j])
104                 segments(a[x$edge[x$edge[, 1] == i, ][1, 1],
105                   1], a[x$edge[x$edge[, 1] == i, 2], 2][j], a[x$edge[x$edge[,
106                   1] == i, 2], 1][j], a[x$edge[x$edge[, 1] ==
107                   i, 2], 2][j])
108             }
109         }
110         for (i in (N.tip.y + 1):nrow(b)) {
111             l <- length(y$edge[y$edge[, 1] == i, ][, 1])
112             for (j in 1:l) {
113                 segments(b2[y$edge[y$edge[, 1] == i, ][1, 1],
114                   1], b2[y$edge[y$edge[, 1] == i, 2], 2][1],
115                   b2[y$edge[y$edge[, 1] == i, ][1, 1], 1], b2[y$edge[y$edge[,
116                     1] == i, 2], 2][j])
117                 segments(b2[y$edge[y$edge[, 1] == i, ][1, 1],
118                   1], b2[y$edge[y$edge[, 1] == i, 2], 2][j],
119                   b2[y$edge[y$edge[, 1] == i, 2], 1][j], b2[y$edge[y$edge[,
120                     1] == i, 2], 2][j])
121             }
122         }
123     }
124     if (show.tip.label) {
125         text(a[1:N.tip.x, ], cex = 0, font = font, pos = 4,
126              labels = x$tip.label)
127         text(b2[1:N.tip.y, ], cex = 1, font = font, pos = 2,
128              labels = y$tip.label)
129     }
130 ###links between associated taxa. Takes into account the size of the character strings of the taxa names.
131     lsa <- 1:N.tip.x
132     lsb <- 1:N.tip.y
133     decx <- array(nrow(assoc))
134     decy <- array(nrow(assoc))
135
136     #colors
137     if (length(col)==1) colors<-c(rep(col, nrow(assoc)))
138     else if (length(col)>=nrow(assoc)) colors<-col
139     else  colors<-c(rep(col, as.integer(nrow(assoc)/length(col))+1))
140
141     #lwd
142     if (length(lwd)==1) lwidths<-c(rep(lwd, nrow(assoc)))
143     else if (length(lwd)>=nrow(assoc)) lwidths<-lwd
144     else  lwidths<-c(rep(lwd, as.integer(nrow(assoc)/length(lwd))+1))
145
146     #lty
147     if (length(lty) == 1) ltype <- c(rep(lty, nrow(assoc)))
148     else if (length(lty) >= nrow(assoc)) ltype <- lty
149     else  ltype <- c(rep(lty, as.integer(nrow(assoc)/length(lty))+1))
150
151     for (i in 1:nrow(assoc)) {
152         if (show.tip.label) {
153             decx[i] <- strwidth(x$tip.label[lsa[x$tip.label == assoc[i, 1]]])
154             decy[i] <- strwidth(y$tip.label[lsb[y$tip.label == assoc[i, 2]]])
155         } else {
156             decx[i] <- decy[i] <- 0
157         }
158
159         segments(a[lsa[x$tip.label == assoc[i, 1]], 1] + decx[i] + gap,
160                  a[lsa[x$tip.label == assoc[i, 1]], 2],
161                  a[lsa[x$tip.label == assoc[i, 1]], 1] + gap + left,
162                  a[lsa[x$tip.label ==  assoc[i, 1]], 2],
163                  col = colors[i], lwd = lwidths[i], lty = ltype[i])
164
165         segments(b2[lsb[y$tip.label == assoc[i, 2]], 1] - (decy[i] + gap),
166                  b2[lsb[y$tip.label == assoc[i, 2]], 2],
167                  b2[lsb[y$tip.label == assoc[i, 2]], 1] - (gap + right),
168                  b2[lsb[y$tip.label ==  assoc[i, 2]], 2],
169                  col = colors[i], lwd = lwidths[i], lty = ltype[i])
170
171         segments(a[lsa[x$tip.label == assoc[i, 1]], 1] + gap + left,
172                  a[lsa[x$tip.label == assoc[i, 1]], 2],
173                  b2[lsb[y$tip.label == assoc[i, 2]], 1] - (gap + right),
174                  b2[lsb[y$tip.label == assoc[i, 2]], 2],
175                  col = colors[i], lwd = lwidths[i], lty = ltype[i])
176     }
177     if (return == TRUE)  return(res)
178 }