Nothing
#' @rdname pbHeatmap
#' @title Heatmap of cluster-sample pseudobulks
#'
#' @description ...
#'
#' @param x a \code{\link[SingleCellExperiment]{SingleCellExperiment}}.
#' @param y a list of DS analysis results as returned by
#' \code{\link{pbDS}} or \code{\link{mmDS}}.
#' @param k character vector; specifies which cluster ID(s) to retain.
#' Defaults to \code{levels(x$cluster_id)}.
#' @param g character vector; specifies which genes to retain.
#' Defaults to considering all genes.
#' @param c character string; specifies which contrast/coefficient to retain.
#' Defaults to \code{names(y$table)[1]}.
#' @param top_n single numeric; number of genes to retain per cluster.
#' @param fdr,lfc single numeric; FDR and logFC cutoffs to filter results by.
#' The specified FDR threshold is applied to \code{p_adj.loc} values.
#' @param sort_by character string specifying
#' a numeric results table column to sort by;
#' \code{"none"} to retain original ordering.
#' @param decreasing logical; whether to sort
#' in decreasing order of \code{sort_by}.
#' @param assay character string; specifies which assay to use;
#' should be one of \code{assayNames(x)}.
#' @param fun function to use as summary statistic,
#' e.g., mean, median, sum (depending on the input assay).
#' @param normalize logical; whether to apply a z-normalization
#' to each row (gene) of the cluster-sample pseudobulk data.
#' @param col character vector of colors or color mapping function
#' generated with \code{\link[circlize]{colorRamp2}}. Passed to
#' argument \code{col} in \code{\link[ComplexHeatmap]{Heatmap}}
#' (see \code{?ComplexHeatmap::Heatmap} for details).
#' @param row_anno,col_anno logical; whether to render
#' annotations of cluster and group IDs, respectively.
#'
#' @return a \code{\link{HeatmapList-class}} object.
#'
#' @examples
#' data(sce)
#'
#' # compute pseudobulks & run DS analysis
#' pb <- aggregateData(sce)
#' res <- pbDS(pb)
#'
#' # cluster-sample expression means
#' pbHeatmap(sce, res)
#'
#' # include only a single cluster
#' pbHeatmap(sce, res, k = "B cells")
#'
#' # plot specific gene across all clusters
#' pbHeatmap(sce, res, g = "ISG20")
#'
#' @author Helena L Crowell
#'
#' @importFrom ComplexHeatmap Heatmap columnAnnotation rowAnnotation
#' @importFrom dplyr bind_rows filter_
#' @importFrom grid gpar
#' @importFrom purrr map
#' @importFrom scales hue_pal
#' @importFrom viridis viridis
#' @export
pbHeatmap <- function(x, y,
k = NULL, g = NULL, c = NULL,
top_n = 20, fdr = 0.05, lfc = 1,
sort_by = "p_adj.loc", decreasing = FALSE,
assay = "logcounts", fun = mean, normalize = TRUE,
col = viridis(10), row_anno = TRUE, col_anno = TRUE) {
# check validity of input arguments
.check_sce(x, req_group = TRUE)
.check_arg_assay(x, assay)
.check_args_pbHeatmap(as.list(environment()))
#.check_res(x, y)
# defaults for NULL arguments
if (is.null(k)) k <- levels(x$cluster_id)
if (is.null(c)) c <- names(y$table)[1]
# subset specified contrast/coef & cluster(s)
y <- y$table[[c]][k]
y <- y[!vapply(y, is.null, logical(1))]
# filter results
if (!is.null(g)) y <- lapply(y, filter_, ~gene %in% g)
y <- lapply(y, filter_, ~p_adj.loc < fdr, ~abs(logFC) > lfc)
# get cluster IDs & nb. of clusters
nk <- length(names(kids) <- kids <- names(y))
# subset 'top_n' results
if (is.null(top_n)) {
ns <- vapply(y, nrow, numeric(1))
} else {
ns <- vapply(y, function(u) min(nrow(u), top_n), numeric(1))
}
# re-order results
if (sort_by == "none") {
y <- lapply(kids, function(k)
y[[k]][seq_len(ns[k]), ])
} else {
vs <- map(y, sort_by)
os <- lapply(vs, order, decreasing = decreasing)
y <- lapply(kids, function(k) {
o <- os[[k]][seq_len(ns[k])]
y[[k]][o, ]
})
}
y <- bind_rows(y)
# subset 'assay' data
es <- assays(x)[[assay]]
es <- es[unlist(y$gene), , drop = FALSE]
# compute cluster-sample summary values (e.g., means)
cells_by_ks <- .split_cells(x)
xs <- t(mapply(function(g, k)
vapply(cells_by_ks[[k]], function(cs)
fun(es[g, cs]), numeric(1)),
g = y$gene, k = y$cluster_id))
if (normalize) xs <- .z_norm(xs)
# plotting -----------------------------------------------------------------
# row & column annotation
lgd_aes <- list(labels_gp = gpar(fontsize = 6),
title_gp = gpar(fontface = "bold", fontsize = 8))
if (row_anno & nk > 1) {
cols <- .cluster_colors
if (nk > length(cols))
cols <- colorRampPalette(cols)(nk)
cols <- setNames(cols[seq_len(nk)], kids)
row_anno <- rowAnnotation(
df = data.frame(cluster_id = y$cluster_id),
col = list(cluster_id = cols),
gp = gpar(col = "white"),
show_annotation_name = FALSE,
annotation_legend_param = lgd_aes)
} else {
row_anno <- NULL
}
ei <- metadata(x)$experiment_info
m <- match(levels(x$sample_id), ei$sample_id)
if (col_anno) {
cols <- setNames(hue_pal()(nlevels(x$group_id)), levels(x$group_id))
col_anno <- columnAnnotation(
df = data.frame(group_id = ei$group_id[m]),
col = list(group_id = cols),
gp = gpar(col = "white"),
show_annotation_name = FALSE,
annotation_legend_param = lgd_aes)
} else {
col_anno <- NULL
}
Heatmap(matrix = xs, col = col,
name = sprintf("%s%s %s",
c("", "z-normalized\n")[normalize + 1],
deparse(substitute(fun)), assay),
row_title = NULL, column_title = NULL,
cluster_rows = FALSE, cluster_columns = FALSE,
left_annotation = row_anno, top_annotation = col_anno,
split = y$cluster_id, column_split = ei$group_id[m],
heatmap_legend_param = lgd_aes,
row_names_gp = gpar(fontsize = 6),
column_names_gp = gpar(fontsize = 8),
column_title_gp = gpar(fontface = "bold", fontsize = 10))
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.