diff --git a/DESCRIPTION b/DESCRIPTION index e48a997..585c84a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: CancerEvolutionVisualization Title: Publication Quality Phylogenetic Tree Plots -Version: 2.1.1 -Date: 2024-07-30 +Version: 2.1.0 +Date: 2024-07-31 Authors@R: c( person("Paul Boutros", role = "cre", email = "PBoutros@mednet.ucla.edu"), person("Adriana Salcedo", role = "aut"), @@ -19,10 +19,8 @@ Depends: gridExtra, gtable, Imports: - plyr, grDevices, utils, - stringr, BoutrosLab.plotting.general Suggests: testthat, diff --git a/NAMESPACE b/NAMESPACE index 51d41bd..c8e9d06 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,13 +1,11 @@ import(grid) import(gridExtra) import(gtable) -import(plyr) import(BoutrosLab.plotting.general) importFrom("graphics", "par", "strheight", "strwidth") importFrom("grDevices", "dev.list", "rainbow") importFrom("utils", "read.table", "vi", "head") -importFrom("stringr", "str_replace_all") importFrom("stats", "setNames", "aggregate", "reshape") importFrom("grDevices", "col2rgb") diff --git a/NEWS.md b/NEWS.md index 478a582..9d9b4a9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# CancerEvolutionVisualization 2.1.0 (2024-07-30) +# CancerEvolutionVisualization 2.1.0 (2024-07-31) ## Added * Optional "spread" column to control node/branch spacing @@ -9,8 +9,14 @@ * Fixed angle calculation bug where child angles do not follow their parent angle, instead moving "downward" at 0 degrees. * Updated package metadata and README +<<<<<<< HEAD:NEWS.md * Set default parameters for heatmaps, defaulting too BPG defaults unless necessary * Updated changelog format to NEWS.md Markdown format +======= +* Refactored use of plyr/dplyr and stringr functions to remove dependencies +* Set default parameters for heatmaps, defaulting to BPG defaults unless necessary + +>>>>>>> 2424b7934e815dcc02cce5482c1b1c16bf319a09:NEWS # CancerEvolutionVisualization 2.0.1 (2023-11-17) diff --git a/R/add.segs.R b/R/add.segs.R index a4fc155..eab529f 100644 --- a/R/add.segs.R +++ b/R/add.segs.R @@ -1,99 +1,3 @@ -add.segs3 <- function( - tree, - v, - offset = 0, - node.radius = 0, - scale.x.real = NULL - ) { - - # Calculate offset based on line width - offset <- offset / scale.x.real / 2; - - tree.segs.adjusted <- tree.segs <- adply( - tree, - .margins = 1, - .fun = function(x) { - if (x$parent == -1) { - basey <- 0; - basex <- 0; - } else { - basey <- v$y[v$id == x$parent]; - basex <- v$x[v$id == x$parent]; - } - - tipy <- basey + x$length1 * cos(x$angle); - tipx <- basex + x$length1 * sin(x$angle); - - return(data.frame(basex, basey, tipx, tipy)); - } - ); - - tree.out <- list(); - - second.tree.segs.adjusted <- NULL; - - if (length(grep('length', colnames(tree))) == 4) { - tree.segs.adjusted <- adply( - tree.segs, - .margins = 1, - .fun = function(r) { - offset.x <- offset * cos(r$angle); - offset.y <- offset * sin(r$angle); - - if (r$angle > 0) { - basey <- r$basey + offset.y; - tipy <- r$tipy + offset.y; - } else { - basey <- r$basey + offset.y; - tipy <- r$tipy + offset.y; - } - - basex <- r$basex - offset.x; - tipx <- r$tipx - offset.x; - - return(data.frame(basex, basey, tipx, tipy)); - } - ); - - tree.segs.adjusted <- tree.segs.adjusted[which(!(tree.segs.adjusted$basey == tree.segs.adjusted$tipy & tree.segs.adjusted$basex == tree.segs.adjusted$tipx)), ] - - second.tree.segs <- tree.segs; - second.tree.segs$tipy <- second.tree.segs$basey + second.tree.segs$length2.c * cos(second.tree.segs$angle); - second.tree.segs$tipx <- second.tree.segs$basex + second.tree.segs$length2.c * sin(second.tree.segs$angle); - - second.tree.segs.adjusted <- adply( - second.tree.segs, - .margins = 1, - .fun = function(r) { - offset.x <- offset * cos(r$angle); - offset.y <- offset * sin(r$angle); - - if (r$angle > 0) { - basey <- r$basey - offset.y; - tipy <- r$tipy - offset.y; - } else { - basey <- r$basey - offset.y; - tipy <- r$tipy - offset.y; - } - - basex <- r$basex + offset.x; - tipx <- r$tipx + offset.x; - - return(data.frame(basex, basey, tipx, tipy)); - } - ); - - second.tree.segs.adjusted <- second.tree.segs.adjusted[which(!(second.tree.segs.adjusted$basey == second.tree.segs.adjusted$tipy & second.tree.segs.adjusted$basex == second.tree.segs.adjusted$tipx)),] - } - - tree.out <- list( - tree.segs = tree.segs.adjusted, - tree.segs2 = second.tree.segs.adjusted - ); - - return(tree.out); - } - get.seg.coords <- function( tree, v, @@ -105,78 +9,62 @@ get.seg.coords <- function( # Calculate offset based on the line width offset <- offset / scale1 / 2; - tree.segs <- adply( + tree.segs <- apply( tree, - .margins = 1, - .fun = function(x) { - if (x$parent == -1) { + MARGIN = 1, + FUN = function(x) { + if (x['parent'] == -1) { basey <- 0; basex <- 0; } else { - basey <- v$y[v$id == x$parent]; - basex <- v$x[v$id == x$parent]; + basey <- v$y[v$id == x['parent']]; + basex <- v$x[v$id == x['parent']]; } - tipy <- basey + x$length1 * cos(x$angle); - tipx <- basex + x$length1 * sin(x$angle); + tipy <- basey + x['length1'] * cos(x['angle']); + tipx <- basex + x['length1'] * sin(x['angle']); - return(data.frame(basex, basey, tipx, tipy)); + data.frame( + basex = basex, + basey = basey, + tipx = tipx, + tipy = tipy + ); } ); + tree.segs <- as.data.frame(do.call('rbind', tree.segs)); + rownames(tree.segs) <- rownames(tree); + tree.segs <- cbind(tree, tree.segs); - tree.out <- list(); second.tree.segs.adjusted <- NULL; - tree.segs.adjusted <- adply( - tree.segs, - .margins = 1, - .fun = function(r) { - offset.x <- offset * cos(r$angle); - offset.y <- offset * sin(r$angle); - - if (r$angle > 0) { - basey <- r$basey + offset.y; - tipy <- r$tipy + offset.y; - } else { - basey <- r$basey + offset.y; - tipy <- r$tipy + offset.y; - } - - basex <- r$basex - offset.x; - tipx <- r$tipx - offset.x; + tree.segs.adjusted <- tree.segs; + offset.x <- offset * cos(tree.segs.adjusted$angle); + offset.y <- offset * sin(tree.segs.adjusted$angle); - return(data.frame(basex, basey, tipx, tipy)); - } - ); + tree.segs.adjusted$basey <- tree.segs.adjusted$basey + offset.y; + tree.segs.adjusted$tipy <- tree.segs.adjusted$tipy + offset.y; + tree.segs.adjusted$basex <- tree.segs.adjusted$basex - offset.x; + tree.segs.adjusted$tipx <- tree.segs.adjusted$tipx - offset.x; if (length(grep('length',colnames(tree))) == 4) { - second.tree.segs <- tree.segs; - second.tree.segs$tipy <- second.tree.segs$basey + second.tree.segs$length2.c * cos(second.tree.segs$angle); - second.tree.segs$tipx <- second.tree.segs$basex + second.tree.segs$length2.c * sin(second.tree.segs$angle); - - - second.tree.segs.adjusted <- adply( - second.tree.segs, - .margins = 1, - .fun = function(r) { - offset.x <- offset * cos(r$angle); - offset.y <- offset * sin(r$angle); - - if (r$angle > 0) { - basey <- r$basey - offset.y; - tipy <- r$tipy - offset.y; - } else { - basey <- r$basey - offset.y; - tipy <- r$tipy - offset.y; - } - - basex <- r$basex + offset.x; - tipx <- r$tipx + offset.x; - - return(data.frame(basex, basey, tipx, tipy)); - } + second.tree.segs.adjusted <- tree.segs; + second.tree.segs.adjusted$tipy <- ( + second.tree.segs.adjusted$basey + + second.tree.segs.adjusted$length2.c + * cos(second.tree.segs.adjusted$angle) + ); + second.tree.segs.adjusted$tipx <- ( + second.tree.segs.adjusted$basex + + second.tree.segs.adjusted$length2.c + * sin(second.tree.segs.adjusted$angle) ); + second.tree.segs.adjusted$basey <- second.tree.segs.adjusted$basey - offset.y; + second.tree.segs.adjusted$tipy <- second.tree.segs.adjusted$tipy - offset.y; + second.tree.segs.adjusted$basex <- second.tree.segs.adjusted$basex + offset.x; + second.tree.segs.adjusted$tipx <- second.tree.segs.adjusted$tipx + offset.x; + second.tree.segs.adjusted <- second.tree.segs.adjusted[ which(second.tree.segs.adjusted$basey != second.tree.segs.adjusted$tipy), ]; } diff --git a/R/add.text.R b/R/add.text.R index 2832858..85c0225 100644 --- a/R/add.text.R +++ b/R/add.text.R @@ -61,18 +61,11 @@ check.overlap <- function( node.text.xrange <- c(left, right); - node.segs <- adply( - tree.max.adjusted[, c('tip', 'parent', 'x', 'y')], - .margins = 1, - .fun = function(w) { - data.frame( - y0 = (w$y + node.radius), - y1 = (w$y - node.radius), - x0 = (w$x - node.radius), - x1 = (w$x + node.radius) - ); - } - ); + node.segs <- tree.max.adjusted[, c('tip', 'parent', 'x', 'y')]; + node.segs$y0 <- tree.max.adjusted$y + node.radius; + node.segs$y1 <- tree.max.adjusted$y - node.radius; + node.segs$x0 <- tree.max.adjusted$x - node.radius; + node.segs$x1 <- tree.max.adjusted$x + node.radius; line.intercept <- logical(length = nrow(tree.max.adjusted)); node.intercept <- logical(length = nrow(tree.max.adjusted)); @@ -503,98 +496,56 @@ add.text2 <- function( # Radius in native units node.radius <- node.radius / scale; node.text <- node.text[node.text$node %in% tree$tip, ]; - node.list <- alply( - seq_len(nrow(tree)), - .margins = 1, - .fun = function(x) { - return(character()) - } - ); - node.text.col <- node.list; - node.text.fontface <- node.list; - - a_ply( - seq_len( - nrow(node.text)), - .margins = 1, - .fun = function(x) { - text.row <- node.text[x, ]; - pos <- which(tree$tip == text.row$node); - text.value <- text.row$name; - - if (length(grep('_', text.value)) > 0) { - text.split <- strsplit(text.value, split = '_')[[1]]; - node.text.value <- text.split[1]; - amp <- text.split[2]; - call <- paste0(node.text.value, '^\'A', amp, '\''); - text.value <- parse(text = call); - } + node.list <- data.frame(row.names = rownames(tree)); + node.text.col <- node.text.fontface <- lapply - node.list[[pos]] <<- c(node.list[[pos]], text.value); - - node.text.col[[pos]] <<- c( - node.text.col[[pos]], - if (!is.na(text.row$col)) text.row$col else 'black' - ); - - node.text.fontface[[pos]] <<- c( - node.text.fontface[[pos]], - if (!is.na(text.row$fontface)) text.row$fontface else 'plain' - ); - } - ); - - tree.max <- adply( + tree.max.adjusted <- apply( tree, - .margins = 1, - .fun = function(x) { - if (x$parent == -1) { + MARGIN = 1, + FUN = function(x) { + if (x['parent'] == -1) { basex <- 0; basey <- 0; } else { - basex <- v$x[v$id == x$parent]; - basey <- v$y[v$id == x$parent]; + basex <- v$x[v$id == x['parent']]; + basey <- v$y[v$id == x['parent']]; } - tipx <- v$x[v$id == x$tip]; - tipy <- v$y[v$id == x$tip]; + tipx <- v$x[v$id == x['tip']]; + tipy <- v$y[v$id == x['tip']]; return(data.frame(basex, basey, tipx, tipy)); } ); - - #the length of the visible line segments - tree.max.adjusted <- adply( - tree.max, - .margins = 1, - .fun = function(x) { - if (x$tipx == x$basex) { - #straight line - basex <- x$basex; - tipx <- x$tipx; - basey <- x$basey + node.radius; - tipy <- x$tipy - node.radius; - } else if (x$tipx > x$basex) { - basey <- x$basey + node.radius * cos(x$angle); - tipy <- x$tipy - node.radius * cos(x$angle); - basex <- x$basex + node.radius * sin(x$angle); - tipx <- x$tipx - node.radius * sin(x$angle); - } else if (x$tipx < x$basex) { - basey <- x$basey + node.radius * cos(x$angle); - tipy <- x$tipy - node.radius * cos(x$angle); - basex <- x$basex + node.radius * sin(x$angle); - tipx <- x$tipx - node.radius * sin(x$angle); - } - if (x$parent == -1) { - basex <- basey <- 0; - } - - return(data.frame(basex,basey,tipx,tipy)); - } + tree.max.adjusted <- do.call('rbind', tree.max.adjusted); + rownames(tree.max.adjusted) <- rownames(tree); + tree.max.adjusted <- cbind(tree, tree.max.adjusted); + tree.max <- tree.max.adjusted; + + # 1 if positive angle, -1 if negative (or 0 degrees) + angle.modifier <- (tree.max.adjusted$angle > 0) * 2 - 1; + + # Length of the visible line segments + tree.max.adjusted$basex <- ( + tree.max.adjusted$basex + + angle.modifier * node.radius * sin(tree.max.adjusted$angle) + ); + tree.max.adjusted$tipx <- ( + tree.max.adjusted$tipx - + -angle.modifier * node.radius * sin(tree.max.adjusted$angle) + ); + tree.max.adjusted$basey <- ( + tree.max.adjusted$basey + + angle.modifier * node.radius * cos(tree.max.adjusted$angle) + ); + tree.max.adjusted$tipy <- ( + tree.max.adjusted$tipy - + -angle.modifier * node.radius * cos(tree.max.adjusted$angle) ); - #push a viewport the same size as the final panel so we can do calculations based on absolute size units + # Push a viewport the same size as the final panel + # to perform calculations using absolute size units if (!is.null(clone.out)) { pushViewport(clone.out$vp); } else { diff --git a/R/adjust.tree.R b/R/adjust.tree.R index 220ab3e..4f29ffa 100644 --- a/R/adjust.tree.R +++ b/R/adjust.tree.R @@ -1,29 +1,26 @@ -adjust.lengths <- function(x, cols, node.df) { - out.df <- x; - - for (column in cols) { - if (x[1, column] > 0) { - length.adj <- x[1, column]; +adjust.lengths <- function(x, length.cols, node.df) { + adjusted <- list(); + for (column in length.cols) { + if (x[column] > 0) { + length.adj <- x[column]; # Max - if (x[1, column] == x[1, cols[length(cols)]]) { - length.adj <- length.adj + node.df$node.radius[node.df$id == x$tip]; + if (x[column] == x[length.cols[length(length.cols)]]) { + length.adj <- length.adj + node.df$node.radius[node.df$id == x['tip']]; } - if (x$parent != -1) { - length.adj <- length.adj + node.df$node.radius[node.df$id == x$parent]; + if (x['parent'] != -1) { + length.adj <- length.adj + node.df$node.radius[node.df$id == x['parent']]; } - } else { length.adj <- 0; } var.name <- paste0(names(x)[column], '.adj'); - out.df <- cbind(out.df, length.adj); - colnames(out.df)[ncol(out.df)] <- var.name; + adjusted[var.name] <- length.adj; } - return(out.df); + return(as.data.frame(adjusted)); } adjust.branch.lengths <- function(node.df, tree, node.radius, scale1) { @@ -35,13 +32,14 @@ adjust.branch.lengths <- function(node.df, tree, node.radius, scale1) { node.df$node.radius[node.df$id == -1] <- 0; length.cols <- grep('length', colnames(tree)); - tree.adj <- adply( + tree.adj <- apply( tree, - .margins = 1, - .fun = function(x) { - adjust.lengths(x, length.cols, node.df); - } + MARGIN = 1, + FUN = function(x) adjust.lengths(x, length.cols, node.df) ); + tree.adj <- do.call('rbind', tree.adj); + rownames(tree.adj) <- rownames(tree); + tree.adj <- cbind(tree, tree.adj); tree$length <- tree.adj$length.adj; tree$length1 <- tree.adj$length1.adj; @@ -49,26 +47,3 @@ adjust.branch.lengths <- function(node.df, tree, node.radius, scale1) { return(tree); } - -adjust.tree <- function(in.tree.node.radius, tree.in, node.radius, scale.x.real) { - if (is.null(in.tree.node.radius$node.radius)) { - node.radius <- node.radius / scale.x.real; - in.tree.node.radius$node.radius <- rep(node.radius, nrow(in.tree.node.radius)); - } - - in.tree.node.radius$node.radius[in.tree.node.radius$id == -1] <- 0; - length.cols <- grep('length', colnames(tree.in)); - tree.adj <- adply( - tree.in, - .margins = 1, - .fun = function(x) { - adjust.lengths(x, length.cols, in.tree.node.radius); - } - ); - - tree.in$length <- tree.adj$length.adj; - tree.in$length1 <- tree.adj$length1.adj; - tree.in$length2.c <- tree.adj$length2.c.adj; - - return(tree.in); - } diff --git a/tests/testthat/helper-compare.R b/tests/testthat/helper-compare.R index b929b71..0d175d4 100644 --- a/tests/testthat/helper-compare.R +++ b/tests/testthat/helper-compare.R @@ -13,7 +13,7 @@ compare.trees <- function(example, test) { } get.axis.keys <- function(x) { - stringr::str_subset(x$childrenOrder, 'axis'); + x$childrenOrder[grepl('axis', x$childrenOrder)]; } # Grob comparisons @@ -172,7 +172,7 @@ compare.trees <- function(example, test) { test.polygon.grobs <- function(example, test) { get.polygon.keys <- function(x) { - stringr::str_subset(x$childrenOrder, 'polygon') + x$childrenOrder[grepl('polygon', x$childrenOrder)]; } compare.polygons <- function(x, y) {