#' @title Add Margin Annotation
#' @description This function is a wrapper of \code{aplot}, and can be used to
#' insert annotation.
#' @param plot a ggplot object.
#' @param ... annotation elements.
#' @param width,height width/height of each annotation plot.
#' @param k an integer scalar with the desired number of groups.
#' @param border,colour,color fill and border colour of the hclust bar.
#' @author Hou Yun
#' @rdname wrap_annotate
#' @references Yu G (2022). aplot: Decorate a 'ggplot' with Associated Information. R package
#' version 0.1.6, https://CRAN.R-project.org/package=aplot.
#' @export
wrap_annotate <- function(plot,
...,
width = NULL,
height = NULL,
k = 2,
colour = NULL,
border = NA,
color = NULL) {
anno <- list(...)
anno <- anno[names(anno)[names(anno) %in% c("r", "l", "t", "b")]]
if (empty(anno)) {
return(plot)
}
if (is.null(width)) {
width <- 0.2
}
if (is.null(height)) {
height <- 0.2
}
if (is.numeric(width)) {
width <- rep_len(width, length(anno$l) + length(anno$r))
width <- list(l = width[seq_along(anno$l)],
r = width[seq_along(anno$r) + length(anno$l)])
} else {
width$l <- width$l %||% 0.2
width$r <- width$r %||% 0.2
width$l <- rep_len(width$l, length(anno$l))
width$r <- rep_len(width$r, length(anno$r))
}
if (is.numeric(height)) {
height <- rep_len(height, length(anno$t) + length(anno$b))
height <- list(t = height[seq_along(anno$t)],
b = height[seq_along(anno$b) + length(anno$t)])
} else {
height$t <- height$t %||% 0.2
height$b <- height$b %||% 0.2
height$t <- rep_len(height$t, length(anno$t))
height$b <- rep_len(height$b, length(anno$b))
}
anno <- lapply(anno, function(x) {
if (inherits(x, "ggplot") || identical(x, "tree") || identical(x, "hc_bar")) {
list(x)
} else {
x
}
})
nm <- names(anno)
for (ii in nm) {
ele_name <- names(anno[[ii]])
tree_id <- if (ii %in% c("r", "l")) {"row_tree"} else "col_tree"
hc <- attr(plot$data, tree_id)
for (jj in seq_along(anno[[ii]])) {
if (identical(anno[[ii]][[jj]], "tree")) {
anno[[ii]][[jj]] <- gen_tree(hc, side = ii)
}
if (identical(anno[[ii]][[jj]], "hc_bar")) {
anno[[ii]][[jj]] <- gen_hc_bar(hc,
k = k,
side = ii,
colour = colour,
border = border,
color = color)
}
if (!is.null(ele_name)) {
if (ele_name[jj] != "") {
anno[[ii]][[jj]] <- anno[[ii]][[jj]] + ggplot2::labs(tag = ele_name[jj])
}
}
if (ii %in% c("r", "l")) {
anno[[ii]][[jj]] <- suppressMessages(
anno[[ii]][[jj]] + aplot::ylim2(plot) + theme_no_axis("y")
)
} else {
anno[[ii]][[jj]] <- suppressMessages(
anno[[ii]][[jj]] + aplot::xlim2(plot) + theme_no_axis("x")
)
}
}
}
for (ii in nm) {
n <- length(anno[[ii]])
for (jj in seq_along(anno[[ii]])) {
if (ii == "r") {
plot <- plot %>% aplot::insert_right(anno[[ii]][[jj]],
width = width[[ii]][jj])
}
if (ii == "l") {
plot <- plot %>% aplot::insert_left(anno[[ii]][[n - jj + 1]],
width = width[[ii]][n - jj + 1])
}
if (ii == "t") {
plot <- plot %>% aplot::insert_top(anno[[ii]][[jj]],
height = height[[ii]][jj])
}
if (ii == "b") {
plot <- plot %>% aplot::insert_bottom(anno[[ii]][[n - jj + 1]],
height = height[[ii]][n - jj + 1])
}
}
}
plot
}
#' @noRd
gen_tree <- function(hc, side = "t") {
if (is.null(hc)) {
stop("Tree annotate cannot be added to unclustered data.", call. = FALSE)
}
if (inherits(hc, "ggtree")) {
return(hc)
}
data <- ggdendro::dendro_data(hc)$segments
max_x <- max(data$x, data$xend) + 1
max_y <- max(data$y, data$yend)
if (side == "b") {
data$y <- max_y - data$y
data$yend <- max_y - data$yend
}
if (side %in% c("r", "l")) {
data <- data.frame(x = data$yend,
xend = data$y,
y = data$xend,
yend = data$x)
data$y <- max_x - data$y
data$yend <- max_x - data$yend
if (side == "l") {
data$x <- max_y - data$x
data$xend <- max_y - data$xend
}
}
ggplot(data, aes_string(x = "x", xend = "xend", y = "y", yend = "yend")) +
ggplot2::geom_segment() +
ggplot2::theme_void()
}
#' @noRd
gen_hc_bar <- function(hc,
k = 2,
side = "x",
colour = NULL,
border = NA,
color = NULL) {
if (!inherits(hc, "hclust")) {
stop("Hclust bar annotate cannot be added to unclustered data.")
}
tree <- stats::cutree(hc, k)[hc$labels[hc$order]]
if (!is.null(color)) {
colour <- color
}
if (is.null(colour)) {
colour <- sample(grDevices::colors(TRUE), 2)
}
colour <- rep_len(colour, k)
if (side == "x") {
df <- tibble::tibble(x = names(tree),
y = "y",
fill = colour[unname(tree)])
ggplot(df, aes_string(x = "x", y = "y", fill = "fill")) +
ggplot2::geom_tile(colour = border) +
ggplot2::scale_fill_identity() +
ggplot2::scale_x_discrete(limits = names(tree)) +
ggplot2::theme_void() +
theme_no_axis(side)
} else {
df <- tibble::tibble(x = "x",
y = names(tree),
fill = colour[unname(tree)])
ggplot(df, aes_string(x = "x", y = "y", fill = "fill")) +
ggplot2::geom_tile(colour = border) +
ggplot2::scale_fill_identity() +
ggplot2::scale_y_discrete(limits = names(tree)) +
ggplot2::theme_void() +
theme_no_axis(side) +
ggplot2::theme(plot.margin = ggplot2::margin())
}
}
#' @noRd
theme_no_axis <- function(side = "x") {
no_x <- ggplot2::theme(axis.title.x = element_blank(),
axis.title.x.top = element_blank(),
axis.title.x.bottom = element_blank(),
axis.text.x = element_blank(),
axis.text.x.top = element_blank(),
axis.text.x.bottom = element_blank(),
axis.ticks.x = element_blank(),
axis.ticks.x.top = element_blank(),
axis.ticks.x.bottom = element_blank(),
axis.line.x = element_blank(),
axis.line.x.top = element_blank(),
axis.line.x.bottom = element_blank())
no_y <- ggplot2::theme(axis.title.y = element_blank(),
axis.title.y.left = element_blank(),
axis.title.y.right = element_blank(),
axis.text.y = element_blank(),
axis.text.y.left = element_blank(),
axis.text.y.right = element_blank(),
axis.ticks.y = element_blank(),
axis.ticks.y.left = element_blank(),
axis.ticks.y.right = element_blank(),
axis.line.y = element_blank(),
axis.line.y.left = element_blank(),
axis.line.y.right = element_blank())
if (side == "all") {
no_x + no_y
} else if (side == "x") {
no_x
} else {
no_y
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.