#' Layout a TreeAndLeaf diagram.
#'
#' This function tranforms hclust and phylo objects into tree-and-leaf
#' igraph objects.
#'
#' @param obj An object of class 'hclust' or 'phylo'.
#'
#' @return A tree-and-leaf igraph object.
#'
#' @seealso \code{\link{formatTree}}
#' @seealso \code{\link[stats:hclust]{hclust}}
#' @seealso \code{\link[ape:as.phylo]{as.phylo}}
#' @seealso \code{\link[RedeR:addGraph]{addGraph}}
#' @seealso \code{\link[RedeR:relax]{relax}}
#'
#' @examples
#' library(RedeR)
#' rdp <- RedPort()
#' hc <- hclust(dist(USArrests), "ave")
#' tal <- treeAndLeaf(hc)
#'
#' \dontrun{
#' calld(rdp)
#' addGraph(obj=rdp, tal)
#' }
#'
#' @importFrom igraph edge_betweenness is.igraph V E 'V<-' 'E<-'
#' @importFrom ape as.phylo as.igraph.phylo
#' @importFrom RedeR RedPort
#' @export
treeAndLeaf <- function(obj){
tal.checks(name="obj", para=obj)
tal <- .setTaL(obj)
return(tal)
}
# resetd(rdp)
# addGraph(rdp, tal)
#-------------------------------------------------------------------------------
.setTaL <- function(obj){
if ("hclust" %in% class(obj)){
phylo <- ape::as.phylo(obj)
gg <- ape::as.igraph.phylo(phylo, directed=FALSE)
coords <- .get.tree.coords(phylo, use.edge.length=FALSE)
} else if("phylo" %in% class(obj)){
gg <- ape::as.igraph.phylo(obj, directed=FALSE)
coords <- .get.tree.coords(obj, use.edge.length=FALSE)
} else if("ggtree" %in% class(obj)){
lpar <- obj$layers[[1]]$stat_params$layout
vpar <- c("daylight","ape","fan","equal_angle")
if(!lpar%in%vpar)
stop("Please, use one of the 'ggtree' layouts: ",
paste0(vpar, collapse = ", "),"!", call.=FALSE)
# gdata <- ggplot_build(obj)$data[[1]]
phylo <- ape::as.phylo(obj$data)
gg <- ape::as.igraph.phylo(phylo, directed=FALSE)
coords <- .get.tree.coords(phylo, use.edge.length=FALSE)
coords$layout[,] <- as.matrix(obj$data[,c("x","y")])
}
if(!all(V(gg)$name%in%rownames(coords$layout)))
stop("An unexpected error occurred while transforming the graph object!")
#--- set layout
layout <- coords$layout[V(gg)$name,]
V(gg)$coordX <- layout[,"x"]
V(gg)$coordY <- layout[,"y"]
V(gg)$isLeaf <- V(gg)$name%in%coords$phylo$tip.label
gg$centralVertex <- coords$centralVertex
#--- set edge weights
E(gg)$weight <- 0.01
bt <- igraph::edge_betweenness(gg, directed = T)
bt <- (1 - bt/max(bt))
E(gg)$weight <- bt
#--- set node and font sizes
V(gg)$nodeAlias <- V(gg)$name
V(gg)$nodeSize <- 5
V(gg)$nodeSize[V(gg)$isLeaf] <- 30
V(gg)$nodeFontSize <- 15
V(gg)$nodeFontSize[!V(gg)$isLeaf] <- 1
V(gg)$nodeColor <- "#ffcccc"
V(gg)$nodeLineColor <- "#9999ff"
V(gg)$nodeLineWidth <- 2
E(gg)$edgeColor <- "#9999ff"
E(gg)$edgeWidth <- 2
#--- set zoom
sz <- sum(V(gg)$isLeaf)
sz <- sqrt(sz)
# gg$zoom <- ceiling(max(0,100-sz))
gg$gtype <- "TreeAndLeaf"
class(gg) <- c("tal","igraph")
return(gg)
}
#-------------------------------------------------------------------------------
# This function gets coordinates from an unrooted 'phylo' objects,
# derived from a currectly not exported function from the ape package
.get.tree.coords <- function(phy, use.edge.length = FALSE){
if (is.null(phy$edge.length)) use.edge.length <- FALSE
phy <- ape::reorder.phylo(phy)
Ntip <- length(phy$tip.label)
Nedge <- dim(phy$edge)[1]
Nnode <- phy$Nnode
nb.sp <- ape::node.depth(phy)
XY <- if(use.edge.length){
.unrooted.xy(Ntip, Nnode, phy$edge, phy$edge.length, nb.sp)
} else {
.unrooted.xy(Ntip, Nnode, phy$edge, rep(1, Nedge), nb.sp)
}
xx <- XY$M[, 1] - min(XY$M[, 1])
yy <- XY$M[, 2] - min(XY$M[, 2])
layout <- cbind(x=xx,y=yy)
if(is.null(phy$node.label)) phy <- ape::makeNodeLabel(phy)
if(anyDuplicated(c(phy$tip.label, phy$node.label)))
stop("Duplicated labels!")
rownames(layout) <- c(phy$tip.label,phy$node.label)
centralVertex <- phy$node.label[1]
return(list(phylo=phy, layout=layout,centralVertex=centralVertex))
}
#-------------------------------------------------------------------------------
# This function gets coordinates from an unrooted 'phylo' objects,
# derived from a currectly not exported function from the ape package
.unrooted.xy <- function(Ntip, Nnode, edge, edge.length, nb.sp){
foo <- function(node, ANGLE, AXIS) {
ind <- which(edge[, 1] == node)
sons <- edge[ind, 2]
start <- AXIS - ANGLE/2
for (i in 1:length(sons)) {
h <- edge.length[ind[i]]
angle[sons[i]] <<- alpha <- ANGLE*nb.sp[sons[i]]/nb.sp[node]
axis[sons[i]] <<- beta <- start + alpha/2
start <- start + alpha
xx[sons[i]] <<- h*cos(beta) + xx[node]
yy[sons[i]] <<- h*sin(beta) + yy[node]
}
for (i in sons)
if (i > Ntip) foo(i, angle[i], axis[i])
}
Nedge <- dim(edge)[1]
yy <- xx <- numeric(Ntip + Nnode)
axis <- angle <- numeric(Ntip + Nnode)
foo(Ntip + 1L, 2*pi, 0)
M <- cbind(xx, yy)
axe <- axis[1:Ntip]
axeGTpi <- axe > pi
axe[axeGTpi] <- axe[axeGTpi] - 2*pi
list(M = M, axe = axe)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.