]> git.donarmstrong.com Git - ape.git/blobdiff - R/plot.phylo.R
a few bug fixes especially in plot.phylo()
[ape.git] / R / plot.phylo.R
index 4ee98b654f3cf4fe19544439c2dba81c7ab0aa96..69f08660f1afa189e9461ed00f51b330d78baf71 100644 (file)
@@ -1,8 +1,8 @@
-## plot.phylo.R (2009-09-23)
+## plot.phylo.R (2011-02-11)
 
 ##   Plot Phylogenies
 
-## Copyright 2002-2009 Emmanuel Paradis
+## Copyright 2002-2011 Emmanuel Paradis
 
 ## This file is part of the R-package `ape'.
 ## See the file ../COPYING for licensing issues.
@@ -62,12 +62,12 @@ plot.phylo <- function(x, type = "phylogram", use.edge.length = TRUE,
 
     phyloORclado <- type %in% c("phylogram", "cladogram")
     horizontal <- direction %in% c("rightwards", "leftwards")
+    xe <- x$edge # to save
     if (phyloORclado) {
         ## we first compute the y-coordinates of the tips.
         phyOrder <- attr(x, "order")
         ## make sure the tree is in cladewise order:
         if (is.null(phyOrder) || phyOrder != "cladewise") {
-            xe <- x$edge
             x <- reorder(x) # fix from Klaus Schliep (2007-06-16)
             if (!identical(x$edge, xe)) {
                 ## modified from Li-San Wang's fix (2007-01-23):
@@ -130,8 +130,7 @@ plot.phylo <- function(x, type = "phylogram", use.edge.length = TRUE,
         } else  {
             xx <- .nodeDepthEdgelength(Ntip, Nnode, z$edge, Nedge, z$edge.length)
         }
-    }
-    if (type == "fan") {
+    } else switch(type, "fan" = {
         ## if the tips are not in the same order in tip.label
         ## and in edge[, 2], we must reorder the angles: we
         ## use `xx' to store temporarily the angles
@@ -149,9 +148,7 @@ plot.phylo <- function(x, type = "phylogram", use.edge.length = TRUE,
         }
         xx <- r*cos(theta)
         yy <- r*sin(theta)
-
-    }
-    if (type == "unrooted") {
+    }, "unrooted" = {
         nb.sp <- .nodeDepth(Ntip, Nnode, z$edge, Nedge)
         XY <- if (use.edge.length)
             unrooted.xy(Ntip, Nnode, z$edge, z$edge.length, nb.sp)
@@ -160,8 +157,7 @@ plot.phylo <- function(x, type = "phylogram", use.edge.length = TRUE,
         ## rescale so that we have only positive values
         xx <- XY$M[, 1] - min(XY$M[, 1])
         yy <- XY$M[, 2] - min(XY$M[, 2])
-    }
-    if (type == "radial") {
+    }, "radial" = {
         X <- .nodeDepth(Ntip, Nnode, z$edge, Nedge)
         X[X == 1] <- 0
         ## radius:
@@ -171,7 +167,7 @@ plot.phylo <- function(x, type = "phylogram", use.edge.length = TRUE,
         Y <- .nodeHeight(Ntip, Nnode, z$edge, Nedge, yy)
         xx <- X * cos(Y)
         yy <- X * sin(Y)
-    }
+    })
     if (phyloORclado) {
         if (!horizontal) {
             tmp <- yy
@@ -202,28 +198,23 @@ plot.phylo <- function(x, type = "phylogram", use.edge.length = TRUE,
                     tmp <- if (show.tip.label) max(xx.tips + strWi/alp) else max(xx.tips)
                 }
                 x.lim[2] <- tmp
-                if (direction == "leftwards") xx <- x.lim[2] - xx #max(xx[ROOT] + tmp)
-#                  else max(xx[1:Ntip] + tmp)
             } else x.lim <- c(1, Ntip)
-        }
-        if (type == "fan") {
+        } else switch(type, "fan" = {
             if (show.tip.label) {
                 offset <- max(nchar(x$tip.label) * 0.018 * max(yy) * cex)
                 x.lim <- c(min(xx) - offset, max(xx) + offset)
             } else x.lim <- c(min(xx), max(xx))
-        }
-        if (type == "unrooted") {
+        }, "unrooted" = {
             if (show.tip.label) {
                 offset <- max(nchar(x$tip.label) * 0.018 * max(yy) * cex)
                 x.lim <- c(0 - offset, max(xx) + offset)
             } else x.lim <- c(0, max(xx))
-        }
-        if (type == "radial") {
+        }, "radial" = {
             if (show.tip.label) {
                 offset <- max(nchar(x$tip.label) * 0.03 * cex)
                 x.lim <- c(-1 - offset, 1 + offset)
             } else x.lim <- c(-1, 1)
-        }
+        })
     } else if (length(x.lim) == 1) {
         x.lim <- c(0, x.lim)
         if (phyloORclado && !horizontal) x.lim[1] <- 1
@@ -234,6 +225,8 @@ plot.phylo <- function(x, type = "phylogram", use.edge.length = TRUE,
             if (show.tip.label) -1 - max(nchar(x$tip.label) * 0.03 * cex)
             else -1
     }
+    ## mirror the xx:
+    if (phyloORclado && direction == "leftwards") xx <- x.lim[2] - xx
     if (is.null(y.lim)) {
         if (phyloORclado) {
             if (horizontal) y.lim <- c(1, Ntip) else {
@@ -252,27 +245,23 @@ plot.phylo <- function(x, type = "phylogram", use.edge.length = TRUE,
                     tmp <- if (show.tip.label) max(yy.tips + strWi/alp) else max(yy.tips)
                 }
                 y.lim[2] <- tmp
-                if (direction == "downwards") yy <- y.lim[2] - yy
             }
-        }
-        if (type == "fan") {
+        } else switch(type, "fan" = {
             if (show.tip.label) {
                 offset <- max(nchar(x$tip.label) * 0.018 * max(yy) * cex)
                 y.lim <- c(min(yy) - offset, max(yy) + offset)
             } else y.lim <- c(min(yy), max(yy))
-        }
-        if (type == "unrooted") {
+        }, "unrooted" = {
             if (show.tip.label) {
                 offset <- max(nchar(x$tip.label) * 0.018 * max(yy) * cex)
                 y.lim <- c(0 - offset, max(yy) + offset)
             } else y.lim <- c(0, max(yy))
-        }
-        if (type == "radial") {
+        }, "radial" = {
             if (show.tip.label) {
                 offset <- max(nchar(x$tip.label) * 0.03 * cex)
                 y.lim <- c(-1 - offset, 1 + offset)
             } else y.lim <- c(-1, 1)
-        }
+        })
     } else if (length(y.lim) == 1) {
         y.lim <- c(0, y.lim)
         if (phyloORclado && horizontal) y.lim[1] <- 1
@@ -281,12 +270,13 @@ plot.phylo <- function(x, type = "phylogram", use.edge.length = TRUE,
         if (type == "radial")
           y.lim[1] <- if (show.tip.label) -1 - max(nchar(x$tip.label) * 0.018 * max(yy) * cex) else -1
     }
+    ## mirror the yy:
+    if (phyloORclado && direction == "downwards") yy <- y.lim[2] - yy
     if (phyloORclado && root.edge) {
         if (direction == "leftwards") x.lim[2] <- x.lim[2] + x$root.edge
         if (direction == "downwards") y.lim[2] <- y.lim[2] + x$root.edge
     }
-    ## fix by Klaus Schliep (2008-03-28):
-    asp <- if (type %in% c("fan", "radial")) 1 else NA
+    asp <- if (type %in% c("fan", "radial", "unrooted")) 1 else NA # fixes by Klaus Schliep (2008-03-28 and 2010-08-12)
     plot(0, type = "n", xlim = x.lim, ylim = y.lim, ann = FALSE, axes = FALSE, asp = asp, ...)
     if (is.null(adj))
         adj <- if (phyloORclado && direction == "leftwards") 1 else 0
@@ -343,6 +333,7 @@ plot.phylo <- function(x, type = "phylogram", use.edge.length = TRUE,
              "upwards" = segments(xx[ROOT], 0, xx[ROOT], x$root.edge),
              "downwards" = segments(xx[ROOT], yy[ROOT], xx[ROOT], yy[ROOT] + x$root.edge))
     if (show.tip.label) {
+        if (is.expression(x$tip.label)) underscore <- TRUE
         if (!underscore) x$tip.label <- gsub("_", " ", x$tip.label)
 
         if (phyloORclado)
@@ -368,30 +359,31 @@ plot.phylo <- function(x, type = "phylogram", use.edge.length = TRUE,
                 srt <- 180*XY$axe/pi
                 srt[as.logical(adj)] <- srt[as.logical(adj)] - 180
                 ## `srt' takes only a single value, so can't vectorize this:
+                ## (and need to 'elongate' these vectors:)
+                font <- rep(font, length.out = Ntip)
+                tip.color <- rep(tip.color, length.out = Ntip)
+                cex <- rep(cex, length.out = Ntip)
                 for (i in 1:Ntip)
-                  text(xx[i], yy[i], cex = cex, x$tip.label[i], adj = adj[i],
-                       font = font, srt = srt[i], col = tip.color[i])
+                  text(xx[i], yy[i], cex = cex[i], x$tip.label[i], adj = adj[i],
+                       font = font[i], srt = srt[i], col = tip.color[i])
             }
         }
         if (type %in% c("fan", "radial")) {
-            xx.scaled <- xx[1:Ntip]
-            if (type == "fan") { # no need if type == "radial"
-                maxx <- max(abs(xx.scaled))
-                if (maxx > 1) xx.scaled <- xx.scaled/maxx
-            }
-            angle <- acos(xx.scaled)*180/pi
-            s1 <- angle > 90 & yy[1:Ntip] > 0
-            s2 <- angle < 90 & yy[1:Ntip] < 0
-            s3 <- angle > 90 & yy[1:Ntip] < 0
-            angle[s1] <- angle[s1] + 180
-            angle[s2] <- -angle[s2]
-            angle[s3] <- 180 - angle[s3]
+            xx.tips <- xx[1:Ntip]
+            ## using atan2 considerably facilitates things compared to acos...
+            angle <- atan2(yy[1:Ntip], xx.tips)*180/pi
+            s <- xx.tips < 0
+            angle[s] <- angle[s] + 180
             adj <- numeric(Ntip)
-            adj[xx[1:Ntip] < 0] <- 1
+            adj[xx.tips < 0] <- 1
             ## `srt' takes only a single value, so can't vectorize this:
+            ## (and need to 'elongate' these vectors:)
+            font <- rep(font, length.out = Ntip)
+            tip.color <- rep(tip.color, length.out = Ntip)
+            cex <- rep(cex, length.out = Ntip)
             for (i in 1:Ntip)
-              text(xx[i], yy[i], x$tip.label[i], font = font, cex = cex,
-                   srt = angle[i], adj = adj[i], col = tip.color[i])
+                text(xx[i], yy[i], x$tip.label[i], font = font[i], cex = cex[i],
+                     srt = angle[i], adj = adj[i], col = tip.color[i])
         }
     }
     if (show.node.label)
@@ -404,7 +396,7 @@ plot.phylo <- function(x, type = "phylogram", use.edge.length = TRUE,
               label.offset = label.offset, x.lim = x.lim, y.lim = y.lim,
               direction = direction, tip.color = tip.color,
               Ntip = Ntip, Nnode = Nnode)
-    assign("last_plot.phylo", c(L, list(edge = x$edge, xx = xx, yy = yy)),
+    assign("last_plot.phylo", c(L, list(edge = xe, xx = xx, yy = yy)),
            envir = .PlotPhyloEnv)
     invisible(L)
 }
@@ -432,18 +424,9 @@ phylogram.plot <- function(edge, Ntip, Nnode, xx, yy, horizontal,
     }
     ## ... et un trait horizontal partant de chaque tip et chaque noeud
     ##  vers la racine
-###    sq <- c(1:Ntip, nodes[-1])
-###    y0h <- yy[sq]
-###    x1h <- xx[sq]
-###    ## match() is very useful here becoz each element in edge[, 2] is
-###    ## unique (not sure this is so useful in edge[, 1]; needs to be checked)
-###    ## `pos' gives for each element in `sq' its index in edge[, 2]
-###    pos <- match(sq, edge[, 2])
-###    x0h <- xx[edge[pos, 1]]
     x0h <- xx[edge[, 1]]
     x1h <- xx[edge[, 2]]
     y0h <- yy[edge[, 2]]
-### donc plus besoin de 'pos' ni 'sq'
 
     nc <- length(edge.color)
     nw <- length(edge.width)
@@ -458,7 +441,7 @@ phylogram.plot <- function(edge, Ntip, Nnode, xx, yy, horizontal,
         edge.color <- rep(edge.color, length.out = Nedge)
         edge.width <- rep(edge.width, length.out = Nedge)
         edge.lty <- rep(edge.lty, length.out = Nedge)
-        DF <- data.frame(edge.color, edge.width, edge.lty)
+        DF <- data.frame(edge.color, edge.width, edge.lty, stringsAsFactors = FALSE)
         color.v <- rep("black", Nnode)
         width.v <- rep(1, Nnode)
         lty.v <- rep(1, Nnode)
@@ -496,44 +479,6 @@ phylogram.plot <- function(edge, Ntip, Nnode, xx, yy, horizontal,
         }
     }
 
-###    ## function dispatching the features to the vertical edges
-###    foo <- function(edge.feat, default) {
-###        e <- unique(edge.feat)
-###        if (length(e) == 1) return(rep(e, Nnode))
-###        else {
-###            feat.v <- rep(default, Nnode)
-###            for (i in 1:Nnode) {
-###                br <- NodeInEdge1[[i]]
-###                if (length(br) > 2) {
-###                    x <- unique(edge.feat[br])
-###                    if (length(x) == 1) feat.v[i] <- x
-###                } else {
-###                    if (edge.feat[br[1]] == edge.feat[br[2]])
-###                        feat.v[i] <- edge.feat[br[1]]
-###                    else {
-###                        feat.v[i] <- edge.feat[br[2]]
-###                        ## add a new line:
-###                        y0v <<- c(y0v, y0v[i])
-###                        y1v <<- c(y1v, yy[i + Ntip])
-###                        x0v <<- c(x0v, x0v[i])
-###                        feat.v <- c(feat.v, edge.feat[br[1]])
-###                        ## shorten the line:
-###                        y0v[i] <<- yy[i + Ntip]
-###                    }
-###                }
-###            }
-###        }
-###        feat.v
-###    }
-###    color.v <- foo(edge.color, "black")
-###    width.v <- foo(edge.width, 1)
-###    lty.v <- foo(edge.lty, 1)
-
-###    ## we need to reorder:
-###    edge.width <- edge.width[pos]
-###    edge.color <- edge.color[pos]
-###    edge.lty <- edge.lty[pos]
-
     if (horizontal) {
         segments(x0h, y0h, x1h, y0h, col = edge.color, lwd = edge.width, lty = edge.lty) # draws horizontal lines
         segments(x0v, y0v, x0v, y1v, col = color.v, lwd = width.v, lty = lty.v) # draws vertical lines
@@ -648,5 +593,5 @@ plot.multiPhylo <- function(x, layout = 1, ...)
         par(ask = TRUE)
         on.exit(par(ask = FALSE))
     }
-    for (i in x) plot(i, ...)
+    for (i in 1:length(x)) plot(x[[i]], ...)
 }