#' @include dpt.r utils.r
NULL
#' Plot DPT
#'
#' Plots diffusion components from a Diffusion Map and the accompanying Diffusion Pseudo Time (\code{\link{DPT}})
#'
#' @param x A \code{\link{DPT}} object.
#' @param y,root Root branch ID. Will be used as the start of the DPT. (default: lowest branch ID)
#' (If longer than size 1, will be interpreted as \code{c(root, branches)})
#' @param paths_to Numeric Branch IDs. Are used as target(s) for the path(s) to draw.
#' @param dcs The dimensions to use from the DiffusionMap
#' @param divide If \code{col_by = 'branch'}, this specifies which branches to divide. (see \code{\link{branch_divide}})
#' @param w_width Window width for smoothing the path (see \code{\link[smoother]{smth.gaussian}})
#' @param col_by Color by 'dpt' (DPT starting at \code{branches[[1]]}), 'branch', or a veriable of the data.
#' @param col_path Colors for the path or a function creating n colors
#' @param col_tip Color for branch tips
#' @param ... Graphical parameters supplied to \code{\link{plot.DiffusionMap}}
#' @param col See \code{\link{plot.DiffusionMap}}. This overrides \code{col_by}
#' @param legend_main See \code{\link{plot.DiffusionMap}}.
#'
#' @return The return value of the underlying call is returned, i.e. a scatterplot3d or rgl object for 3D plots.
#'
#' @aliases plot.DPT
#'
#' @examples
#' data(guo_norm)
#' dm <- DiffusionMap(guo_norm)
#' dpt <- DPT(dm)
#' plot(dpt)
#' plot(dpt, 2L, col_by = 'branch')
#' plot(dpt, 1L, 2:3, col_by = 'num_cells')
#' plot(dpt, col_by = 'DPT3')
#'
#' @importFrom graphics plot points
#' @importFrom methods is setMethod
#' @importFrom scales colour_ramp rescale
#' @importFrom utils capture.output
#' @importFrom rlang .data
#' @importFrom ggplot2 geom_path geom_point scale_colour_identity
#' @export
plot.DPT <- function( # nolint: cyclocomp_linter.
x, root = NULL,
paths_to = integer(0L),
dcs = 1:2,
divide = integer(0L),
w_width = .1,
col_by = 'dpt',
col_path = rev(palette()),
col_tip = 'red',
...,
col = NULL,
legend_main = col_by
) {
dpt <- x
dpt_flat <- branch_divide(dpt, divide)
if (!is.null(root) && length(root) < 1L) stop('root needs to be specified')
root <-
if (is.null(root)) min(dpt_flat@branch[, 1], na.rm = TRUE)
else as.integer(root)
paths_to <- as.integer(paths_to)
if (length(root) > 1L && length(paths_to) > 0L)
stop('(length(root), length(paths_to)) needs to be (1, 0-n) or (2-n, 0), but is (', length(root), ', ', length(paths_to), ')')
stopifnot(length(dcs) %in% 2:3)
if (length(root) > 1L && length(paths_to) == 0L) {
paths_to <- root[-1]
root <- root[[1]]
}
pt_vec <- dpt_for_branch(dpt_flat, root)
evs <- flipped_dcs(dpt@dm, dcs)
plot_paths <- function(p, ..., rescale) {
plot_points <- get_plot_fn(p)
rescale_fun <-
if (is.null(rescale)) identity
else function(x) rescale_mat(x, rescale)
for (b in seq_along(paths_to)) {
idx <- dpt@branch[, 1] %in% c(root, paths_to[[b]])
path <- average_path(pt_vec[idx], evs[idx, ], w_width)
p <- plot_points(p, rescale_fun(path), type = 'l', col = col_path[[b]], ...)
}
tips <- evs[dpt_flat@tips[, 1], ]
p <- plot_points(p, rescale_fun(tips), col = col_tip, ...)
if (!is(p, 'ggplot')) p
else p + scale_colour_identity(
name = 'Path and Tips', guide = 'legend',
breaks = c(col_path[seq_along(paths_to)], col_tip),
labels = c(sprintf('Path to %s', paths_to), 'Tips'))
}
col <-
if (!is.null(col)) col
else switch(col_by,
dpt = pt_vec,
branch = ,
Branch = dpt_flat@branch[, 1],
dpt[[col_by]])
legend_main <- switch(legend_main, dpt = 'DPT', branch = 'Branch', legend_main)
args <- list(
dpt@dm, dcs,
plot_more = plot_paths,
legend_main = legend_main,
col = col,
...)
if (!identical(Sys.getenv('LOG_LEVEL'), '')) message('Args:\n', paste(capture.output(print(args)), collapse = '\n'))
do.call(plot, args)
}
#' @rdname plot.DPT
#' @export
setMethod('plot', c('DPT', 'numeric'), function(x, y, ...) plot.DPT(x, y, ...))
#' @rdname plot.DPT
#' @export
setMethod('plot', c('DPT', 'missing'), function(x, y, ...) {
args <- list(...)
root <- args$root # may be NULL
args$root <- NULL
do.call(plot.DPT, c(list(x, root), args))
})
#' @importFrom graphics plot
#' @importFrom smoother smth.gaussian
average_path <- function(pt, x, w_width = .1) {
stopifnot(identical(nrow(x), length(pt)))
as.data.frame(apply(x[order(pt), ], 2, function(col) smth.gaussian(col, w_width, tails = TRUE)))
}
get_plot_fn <- function(p) {
if (is(p, 'ggplot')) { # ggplot
function(p2, dat, type = 'p', col, ...) {
xy <- colnames(dat)
geom <- switch(type, p = geom_point, l = geom_path, stop)
p2 + geom(aes(.data[[xy[[1L]]]], .data[[xy[[2L]]]], colour = .data$Path), data.frame(dat, Path = col))
}
} else if (is.list(p) && 'points3d' %in% names(p)) {# scatterplot3d
function(p2, ...) {
p2$points3d(...)
p2
}
} else if (is(p, 'rglHighlevel')) { # rgl
function(p2, x, y = NULL, z = NULL, type = 'p', ...) {
switch(type, p = rgl::points3d, l = rgl::lines3d, stop)(x, y, z, ...)
p2
}
} else {
stop('unknown p passed to plot_more (class(es): ', paste(class(p), collapse = ', '), ')')
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.