diff --git a/DESCRIPTION b/DESCRIPTION index f06e1fae..6a59d0b0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -35,6 +35,7 @@ Collate: 'htanno-group.R' 'htanno-kmeans.R' 'htanno-reorder.R' + 'htanno-title.R' 'import-standalone-assert.R' 'import-standalone-cli.R' 'import-standalone-obj-type.R' diff --git a/NAMESPACE b/NAMESPACE index f76a8b9a..3980c4aa 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -75,6 +75,7 @@ export(htanno_gg) export(htanno_group) export(htanno_kmeans) export(htanno_reorder) +export(htanno_title) export(is.ggheatmap) export(unit) exportMethods("&") diff --git a/R/ggheat.R b/R/ggheat.R index b11b3221..dd83f9d6 100644 --- a/R/ggheat.R +++ b/R/ggheat.R @@ -81,6 +81,7 @@ ggheat.matrix <- function(data, mapping = NULL, theme( plot.background = element_blank(), panel.border = element_blank(), + strip.text = element_blank(), strip.background = element_blank() ) if (ncol(data) > 10L) { diff --git a/R/htanno-dendrogram.R b/R/htanno-dendrogram.R index 2b5da19a..32ec4a10 100644 --- a/R/htanno-dendrogram.R +++ b/R/htanno-dendrogram.R @@ -179,7 +179,7 @@ HtannoDendro <- ggplot2::ggproto("HtannoDendro", HtannoProto, if (!is.null(panels)) panels <- factor(panels, unique(panels[index])) list(panels, index) }, - ggplot = function(self, panels, index, mapping, segment_params) { + ggplot = function(self, mapping, segment_params) { ans <- ggplot2::ggplot(mapping = mapping) + rlang::inject(ggplot2::geom_segment( mapping = aes( diff --git a/R/htanno-gg.R b/R/htanno-gg.R index 227d2009..8e0c8535 100644 --- a/R/htanno-gg.R +++ b/R/htanno-gg.R @@ -44,7 +44,7 @@ gganno_left <- function(...) htanno_gg(position = "left", ...) gganno_right <- function(...) htanno_gg(position = "right", ...) HtannoGG <- ggplot2::ggproto("HtannoGG", HtannoProto, - ggplot = function(self, panels, index, mapping) { + ggplot = function(self, mapping) { ans <- ggplot2::ggplot(mapping = mapping) + ggplot2::theme_bw() diff --git a/R/htanno-title.R b/R/htanno-title.R new file mode 100644 index 00000000..51ffa7fe --- /dev/null +++ b/R/htanno-title.R @@ -0,0 +1,81 @@ +#' Draw Heatmap rows/columns titles +#' @param titles A character of titles, must be of length with the same number +#' of heatmap rows/columns panels. +#' @param ... Additional arguments passed to [geom_text][ggplot2::geom_text]. +#' @inheritParams ggplot2::ggplot +#' @inheritParams htanno +#' @inherit htanno return +#' @examples +#' small_mat <- matrix(rnorm(81), nrow = 9) +#' ggheat(small_mat) + +#' htanno_group( +#' sample(letters[1:4], ncol(small_mat), replace = TRUE), +#' position = "top" +#' ) + +#' htanno_title() +#' @export +htanno_title <- function(titles = NULL, ..., mapping = aes(), + size = unit(1, "cm"), + set_context = TRUE, order = NULL, name = NULL, + position = NULL) { + assert_mapping(mapping) + htanno(HtannoTitle, + params = list( + mapping = mapping, titles = titles, + text_params = rlang::list2(...) + ), + labels = NULL, labels_nudge = NULL, + position = position, size = size, data = NULL, + set_context = set_context, + order = order, name = name + ) +} + +HtannoTitle <- ggplot2::ggproto("HtannoTitle", HtannoProto, + ggplot = function(self, mapping, text_params) { + ans <- ggplot2::ggplot(mapping = mapping) + + rlang::inject(ggplot2::geom_text(!!!text_params)) + + ggplot2::theme_void() + add_default_mapping(ans, switch_position( + .subset2(self, "position"), + aes(x = 0L, y = .data$.y, label = .data$.label), + aes(y = 0L, x = .data$.x, label = .data$.label) + )) + }, + draw = function(self, panels, index, titles) { + position <- .subset2(self, "position") + axis <- to_coord_axis(position) + coords <- data_frame0(.panel = panels[index], .index = index) + coords[[paste0(".", axis)]] <- seq_along(index) + formula <- rlang::new_formula( + rlang::sym(paste0(".", axis)), + quote(.panel) + ) + plot <- .subset2(self, "plot") + data <- stats::aggregate(formula, data = coords, median) + if (is.null(titles)) { + titles <- as.character(data$.panel) + } else if (length(titles) != nlevels(panels)) { + cli::cli_abort( + sprintf( + "{.arg titles} must be of length of %s %s %s (%d)", + "the same number with heatmap", + to_matrix_axis(position), "panels", nlevels(panels) + ), + call = .subset2(self, "call") + ) + } else if (!is.atomic(titles)) { + cli::cli_abort( + "{.arg titles} must be an atomic vector", + call = .subset2(self, "call") + ) + } else if (rlang::is_named(titles)) { + titles <- titles[as.character(data$.panel)] + } else { + titles <- as.character(titles) + } + data$.label <- titles + plot$data <- data + plot + } +) diff --git a/R/initialize-htanno.R b/R/initialize-htanno.R index 707f8a4c..30192207 100644 --- a/R/initialize-htanno.R +++ b/R/initialize-htanno.R @@ -169,9 +169,7 @@ initialize_htanno_layout <- function(object, heatmap, object_name) { ggplot_params <- params[ intersect(names(params), htanno_method_params(object$ggplot)) ] - p <- rlang::inject( - object$ggplot(new_panels, new_index, !!!ggplot_params) - ) + p <- rlang::inject(object$ggplot(!!!ggplot_params)) # set the default theme for all annotation if (ggplot2::is.ggplot(p)) { p <- p + theme( diff --git a/man/htanno_title.Rd b/man/htanno_title.Rd new file mode 100644 index 00000000..e3e66d17 --- /dev/null +++ b/man/htanno_title.Rd @@ -0,0 +1,56 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/htanno-title.R +\name{htanno_title} +\alias{htanno_title} +\title{Draw Heatmap rows/columns titles} +\usage{ +htanno_title( + titles = NULL, + ..., + mapping = aes(), + size = unit(1, "cm"), + set_context = TRUE, + order = NULL, + name = NULL, + position = NULL +) +} +\arguments{ +\item{titles}{A character of titles, must be of length with the same number +of heatmap rows/columns panels.} + +\item{...}{Additional arguments passed to \link[ggplot2:geom_text]{geom_text}.} + +\item{mapping}{Default list of aesthetic mappings to use for plot. +If not specified, must be supplied in each layer added to the plot.} + +\item{size}{Annotation size, can be a \link[grid:unit]{unit} object.} + +\item{set_context}{A logical value of length \code{2} indicates whether to set the +active context to the \code{position} for the \link[=ggheat]{ggheatmap} and whether to +set the active context to current annotation for the annotation list in +\link[=ggheat]{ggheatmap} when added.} + +\item{order}{Annotation order, must be an single integer.} + +\item{name}{A string of the annotation name.} + +\item{position}{A string of the annotation position, possible values are +\code{"top"}, \code{"left"}, \code{"bottom"}, and \code{"right"}. If \code{NULL}, the active context +of \code{ggheatmap} will be used.} +} +\value{ +A new \code{Class} object. +} +\description{ +Draw Heatmap rows/columns titles +} +\examples{ +small_mat <- matrix(rnorm(81), nrow = 9) +ggheat(small_mat) + + htanno_group( + sample(letters[1:4], ncol(small_mat), replace = TRUE), + position = "top" + ) + + htanno_title() +} diff --git a/tests/testthat/_snaps/htanno/dendro_cutree.png b/tests/testthat/_snaps/htanno/dendro_cutree.png index 47da59e7..4e63f5d4 100644 Binary files a/tests/testthat/_snaps/htanno/dendro_cutree.png and b/tests/testthat/_snaps/htanno/dendro_cutree.png differ diff --git a/tests/testthat/_snaps/htanno/dendro_left_between_group_reorder.png b/tests/testthat/_snaps/htanno/dendro_left_between_group_reorder.png index ad86df07..7304a5b3 100644 Binary files a/tests/testthat/_snaps/htanno/dendro_left_between_group_reorder.png and b/tests/testthat/_snaps/htanno/dendro_left_between_group_reorder.png differ diff --git a/tests/testthat/_snaps/htanno/dendro_top_between_group.png b/tests/testthat/_snaps/htanno/dendro_top_between_group.png index 49ab144d..b4745746 100644 Binary files a/tests/testthat/_snaps/htanno/dendro_top_between_group.png and b/tests/testthat/_snaps/htanno/dendro_top_between_group.png differ diff --git a/tests/testthat/_snaps/htanno/group_bottom.png b/tests/testthat/_snaps/htanno/group_bottom.png index 37cfc387..ef809147 100644 Binary files a/tests/testthat/_snaps/htanno/group_bottom.png and b/tests/testthat/_snaps/htanno/group_bottom.png differ diff --git a/tests/testthat/_snaps/htanno/group_left.png b/tests/testthat/_snaps/htanno/group_left.png index 748ce7ba..2b15cb0b 100644 Binary files a/tests/testthat/_snaps/htanno/group_left.png and b/tests/testthat/_snaps/htanno/group_left.png differ diff --git a/tests/testthat/_snaps/htanno/group_right.png b/tests/testthat/_snaps/htanno/group_right.png index 748ce7ba..2b15cb0b 100644 Binary files a/tests/testthat/_snaps/htanno/group_right.png and b/tests/testthat/_snaps/htanno/group_right.png differ diff --git a/tests/testthat/_snaps/htanno/group_top.png b/tests/testthat/_snaps/htanno/group_top.png index 37cfc387..ef809147 100644 Binary files a/tests/testthat/_snaps/htanno/group_top.png and b/tests/testthat/_snaps/htanno/group_top.png differ diff --git a/tests/testthat/_snaps/htanno/kmeans_bottom.png b/tests/testthat/_snaps/htanno/kmeans_bottom.png index 4d9cbdfd..ba672adb 100644 Binary files a/tests/testthat/_snaps/htanno/kmeans_bottom.png and b/tests/testthat/_snaps/htanno/kmeans_bottom.png differ diff --git a/tests/testthat/_snaps/htanno/kmeans_left.png b/tests/testthat/_snaps/htanno/kmeans_left.png index 64a18ea8..5047c5f1 100644 Binary files a/tests/testthat/_snaps/htanno/kmeans_left.png and b/tests/testthat/_snaps/htanno/kmeans_left.png differ diff --git a/tests/testthat/_snaps/htanno/kmeans_right.png b/tests/testthat/_snaps/htanno/kmeans_right.png index 53b02a05..acec4b9b 100644 Binary files a/tests/testthat/_snaps/htanno/kmeans_right.png and b/tests/testthat/_snaps/htanno/kmeans_right.png differ diff --git a/tests/testthat/_snaps/htanno/kmeans_top.png b/tests/testthat/_snaps/htanno/kmeans_top.png index 3c191a47..dbeb343f 100644 Binary files a/tests/testthat/_snaps/htanno/kmeans_top.png and b/tests/testthat/_snaps/htanno/kmeans_top.png differ diff --git a/tests/testthat/_snaps/htanno/reorder_top_within_group.png b/tests/testthat/_snaps/htanno/reorder_top_within_group.png index 510e83ad..48bbd188 100644 Binary files a/tests/testthat/_snaps/htanno/reorder_top_within_group.png and b/tests/testthat/_snaps/htanno/reorder_top_within_group.png differ