#' Compute a dotplot with the results of a group-wise DE analysis.
#'
#' @inheritParams doc_function
#' @param de_genes \strong{\code{\link[tibble]{tibble}}} | DE genes matrix resulting of running `Seurat::FindAllMarkers()`.
#' @param top_genes \strong{\code{\link[base]{numeric}}} | Top N differentially expressed (DE) genes by group to retrieve.
#' @param p.cutoff \strong{\code{\link[base]{numeric}}} | Cutoff to use for adjusted p.value to filter significant genes.
#'
#' @return A dotplot composed of 3 main panels: -log10(adjusted p-value), log2(FC) and mean expression by cluster.
#' @export
#'
#' @example /man/examples/examples_do_GroupwiseDEPlot.R
do_GroupwiseDEPlot <- function(sample,
de_genes,
group.by = NULL,
assay = NULL,
slot = "data",
number.breaks = 5,
dot.scale = 8,
top_genes = 5,
p.cutoff = 0.05,
flip = FALSE,
plot.title = NULL,
plot.subtitle = NULL,
plot.caption = NULL,
xlab = NULL,
ylab = NULL,
use_viridis = FALSE,
colors.use = NULL,
viridis.direction = -1,
viridis.palette = "G",
sequential.direction = 1,
sequential.palette = "YlGnBu",
diverging.palette = "RdBu",
diverging.direction = -1,
legend.position = "bottom",
legend.title = NULL,
legend.width = 1,
legend.length = 7.5,
legend.framewidth = 0.5,
legend.tickwidth = 0.5,
legend.framecolor = "grey50",
legend.tickcolor = "white",
legend.ncol = NULL,
legend.nrow = NULL,
legend.byrow = FALSE,
legend.type = "colorbar",
font.size = 14,
font.type = "sans",
axis.text.x.angle = 45,
min.cutoff = NA,
max.cutoff = NA,
enforce_symmetry = FALSE,
na.value = "grey75",
border.color = "black",
plot.title.face = "bold",
plot.subtitle.face = "plain",
plot.caption.face = "italic",
axis.title.face = "bold",
axis.text.face = "plain",
legend.title.face = "bold",
legend.text.face = "plain"){
# Add lengthy error messages.
withr::local_options(.new = list("warning.length" = 8170))
check_suggests(function_name = "do_GroupwiseDEPlot")
# Check if the sample provided is a Seurat object.
check_Seurat(sample = sample)
logical_list <- list("use_viridis" = use_viridis,
"enforce_symmetry" = enforce_symmetry,
"flip" = flip,
"legend.byrow" = legend.byrow)
check_type(parameters = logical_list, required_type = "logical", test_function = is.logical)
# Check numeric parameters.
numeric_list <- list("number.breaks" = number.breaks,
"top_genes" = top_genes,
"viridis.direction" = viridis.direction,
"legend.width" = legend.width,
"legend.length" = legend.length,
"legend.framewidth" = legend.framewidth,
"legend.tickwidth" = legend.tickwidth,
"font.size" = font.size,
"axis.text.x.angle" = axis.text.x.angle,
"min.cutoff" = min.cutoff,
"max.cutoff" = max.cutoff,
"dot.scale" = dot.scale,
"legend.nrow" = legend.nrow,
"legend.ncol" = legend.ncol)
check_type(parameters = numeric_list, required_type = "numeric", test_function = is.numeric)
# Check character parameters.
character_list <- list("group.by" = group.by,
"slot" = slot,
"legend.position" = legend.position,
"legend.framecolor" = legend.framecolor,
"legend.tickcolor" = legend.tickcolor,
"legend.type" = legend.type,
"font.type" = font.type,
"viridis.palette" = viridis.palette,
"sequential.palette" = sequential.palette,
"na.value" = na.value,
"border.color" = border.color,
"plot.title.face" = plot.title.face,
"plot.subtitle.face" = plot.subtitle.face,
"plot.caption.face" = plot.caption.face,
"axis.title.face" = axis.title.face,
"axis.text.face" = axis.text.face,
"legend.title" = legend.title,
"legend.title.face" = legend.title.face,
"legend.text.face" = legend.text.face,
"xlab" = xlab,
"ylab" = ylab,
"plot.title" = plot.title,
"plot.subtitle" = plot.subtitle,
"plot.caption" = plot.caption)
check_type(parameters = character_list, required_type = "character", test_function = is.character)
`%>%` <- magrittr::`%>%`
`:=` <- rlang::`:=`
check_colors(legend.framecolor, parameter_name = "legend.framecolor")
check_colors(legend.tickcolor, parameter_name = "legend.tickcolor")
check_colors(na.value, parameter_name = "na.value")
check_colors(border.color, parameter_name = "border.color")
check_parameters(parameter = legend.position, parameter_name = "legend.position")
check_parameters(parameter = viridis.palette, parameter_name = "viridis.palette")
check_parameters(parameter = sequential.palette, parameter_name = "sequential.palette")
check_parameters(plot.title.face, parameter_name = "plot.title.face")
check_parameters(plot.subtitle.face, parameter_name = "plot.subtitle.face")
check_parameters(plot.caption.face, parameter_name = "plot.caption.face")
check_parameters(axis.title.face, parameter_name = "axis.title.face")
check_parameters(axis.text.face, parameter_name = "axis.text.face")
check_parameters(legend.title.face, parameter_name = "legend.title.face")
check_parameters(legend.text.face, parameter_name = "legend.text.face")
check_parameters(viridis.direction, parameter_name = "viridis.direction")
check_parameters(sequential.direction, parameter_name = "sequential.direction")
check_parameters(diverging.direction, parameter_name = "diverging.direction")
# Check the assay.
out <- check_and_set_assay(sample = sample, assay = assay)
sample <- out[["sample"]]
assay <- out[["assay"]]
# Check group.by.
out <- check_group_by(sample = sample,
group.by = group.by,
is.heatmap = FALSE)
sample <- out[["sample"]]
group.by <- out[["group.by"]]
values <- unique(sample@meta.data[, group.by])
data.values <- unique(de_genes$cluster)
# Check that group.by works with input de_genes.
assertthat::assert_that(sum(values %in% data.values) == length(data.values))
if (base::isFALSE(enforce_symmetry)){
colors.gradient.exp <- compute_continuous_palette(name = ifelse(isTRUE(use_viridis), viridis.palette, sequential.palette),
use_viridis = use_viridis,
direction = ifelse(isTRUE(use_viridis), viridis.direction, sequential.direction),
enforce_symmetry = enforce_symmetry)
colors.gradient.fc <- compute_continuous_palette(name = "YlOrRd",
use_viridis = FALSE,
direction = ifelse(isTRUE(use_viridis), viridis.direction, sequential.direction),
enforce_symmetry = enforce_symmetry)
colors.gradient.pval <- compute_continuous_palette(name = "PuBuGn",
use_viridis = FALSE,
direction = ifelse(isTRUE(use_viridis), viridis.direction, sequential.direction),
enforce_symmetry = enforce_symmetry)
} else {
colors.gradient.exp <- compute_continuous_palette(name = diverging.palette,
use_viridis = FALSE,
direction = diverging.direction,
enforce_symmetry = enforce_symmetry)
colors.gradient.fc <- compute_continuous_palette(name = "BrBG",
use_viridis = FALSE,
direction = diverging.direction,
enforce_symmetry = enforce_symmetry)
colors.gradient.pval <- compute_continuous_palette(name = "PuOr",
use_viridis = FALSE,
direction = diverging.direction,
enforce_symmetry = enforce_symmetry)
}
if (is.null(colors.use)){
colors.use <- generate_color_scale(names_use = if (is.factor(sample@meta.data[, group.by])) {levels(sample@meta.data[, group.by])} else {sort(unique(sample@meta.data[, group.by]))})
} else {
check_colors(colors.use, parameter_name = "colors.use")
check_consistency_colors_and_names(sample = sample, colors = colors.use, grouping_variable = group.by)
colors.use <- colors.use[unique(sample@meta.data[, group.by])]
}
magnitude <- ifelse(slot == "data", "avg_log2FC", "avg_diff")
specificity <- "p_val_adj"
data.use <- de_genes %>%
dplyr::arrange(.data[[specificity]], dplyr::desc(.data[[magnitude]])) %>%
dplyr::group_by(.data$cluster) %>%
dplyr::filter(.data[[specificity]] <= p.cutoff) %>%
dplyr::slice_head(n = top_genes)
gene.order <- data.use$gene %>% unique()
data.use <- data.use %>%
dplyr::rename("{group.by}" := "cluster") %>%
dplyr::select(dplyr::all_of(c("gene", group.by, magnitude, specificity))) %>%
dplyr::group_by(.data$gene) %>%
dplyr::arrange(dplyr::desc(.data[[magnitude]])) %>%
dplyr::slice_head(n = 1) %>%
dplyr::ungroup() %>%
dplyr::mutate("p.adj.log10.minus" := -log10(.data[[specificity]])) %>%
dplyr::arrange(dplyr::desc(.data[[magnitude]]), dplyr::desc(.data$p.adj.log10.minus)) %>%
dplyr::select(-dplyr::all_of(c(specificity)))
# Workaround parameter deprecation.
if (base::isTRUE(utils::packageVersion("Seurat") < "4.9.9")){
data <- Seurat::GetAssayData(object = sample,
assay = assay,
slot = slot)
} else {
data <- SeuratObject::LayerData(object = sample,
assay = assay,
layer = slot)
}
expr.data <- data[data.use$gene, , drop = FALSE] %>%
as.data.frame() %>%
tibble::rownames_to_column(var = "gene") %>%
tidyr::pivot_longer(cols = -"gene",
names_to = "Cell",
values_to = "Expression") %>%
dplyr::left_join(y = {sample@meta.data %>%
dplyr::select(dplyr::all_of(c(group.by))) %>%
tibble::rownames_to_column(var = "Cell") %>%
dplyr::mutate("Groups.use" = .data[[group.by]]) %>%
dplyr::select(-dplyr::all_of(c(group.by)))},
by = "Cell")
data.use <- expr.data %>%
dplyr::mutate("logical" = ifelse(.data$Expression == 0, 0, 1)) %>%
dplyr::group_by(.data$gene, .data$Groups.use) %>%
dplyr::summarise("Avg.Exp" = mean(.data$Expression, na.rm = TRUE),
"N.Exp" = sum(.data$logical),
"N" = dplyr::n()) %>%
dplyr::mutate("P.Exp" = (.data$N.Exp / .data$N) * 100) %>%
dplyr::left_join(y = {data.use %>%
dplyr::mutate("Groups.use" = .data[[group.by]]) %>%
dplyr::select(-dplyr::all_of(c(group.by)))},
by = c("Groups.use", "gene")) %>%
dplyr::select(dplyr::all_of(c("gene", "Groups.use", "Avg.Exp", "P.Exp", magnitude, "p.adj.log10.minus")))
if (is.factor(sample@meta.data[, group.by])){
order.use <- rev(levels(sample@meta.data[, group.by]))
} else {
order.use <- rev(sort(unique(sample@meta.data[, group.by])))
}
data.use <- data.use %>%
dplyr::mutate("gene" = factor(.data$gene, levels = gene.order)) %>%
dplyr::mutate("Groups.use" = factor(.data$Groups.use, levels = order.use))
# Define cutoffs.
range.data.exp <- c(min(data.use[, "Avg.Exp"], na.rm = TRUE),
max(data.use[, "Avg.Exp"], na.rm = TRUE))
out <- check_cutoffs(min.cutoff = min.cutoff,
max.cutoff = max.cutoff,
limits = range.data.exp)
range.data.exp <- out$limits
scale.setup.exp <- compute_scales(sample = sample,
feature = NULL,
assay = assay,
reduction = NULL,
slot = slot,
number.breaks = number.breaks,
min.cutoff = min.cutoff,
max.cutoff = max.cutoff,
flavor = "Seurat",
enforce_symmetry = enforce_symmetry,
from_data = TRUE,
limits.use = range.data.exp)
range.data.fc <- c(min(data.use[, magnitude], na.rm = TRUE),
max(data.use[, magnitude], na.rm = TRUE))
scale.setup.fc <- compute_scales(sample = sample,
feature = NULL,
assay = assay,
reduction = NULL,
slot = slot,
number.breaks = number.breaks,
min.cutoff = NA,
max.cutoff = NA,
flavor = "Seurat",
enforce_symmetry = enforce_symmetry,
from_data = TRUE,
limits.use = range.data.fc)
range.data.pval <- c(-log10(p.cutoff),
max(data.use[, "p.adj.log10.minus"], na.rm = TRUE))
scale.setup.pval <- compute_scales(sample = sample,
feature = NULL,
assay = assay,
reduction = NULL,
slot = slot,
number.breaks = number.breaks,
min.cutoff = NA,
max.cutoff = NA,
flavor = "Seurat",
enforce_symmetry = enforce_symmetry,
from_data = TRUE,
limits.use = range.data.pval)
# Modify values
if (!is.na(min.cutoff)){
data.use$Avg.Exp <- ifelse(data.use$Avg.Exp <= min.cutoff, min.cutoff, data.use$Avg.Exp)
}
if (!is.na(max.cutoff)){
data.use$Avg.Exp <- ifelse(data.use$Avg.Exp >= max.cutoff, max.cutoff, data.use$Avg.Exp)
}
# Plot
p1 <- data.use %>%
ggplot2::ggplot(mapping = ggplot2::aes(x = if (base::isFALSE(flip)){.data$gene} else {.data$Groups.use},
y = if (base::isFALSE(flip)){.data$Groups.use} else {.data$gene},
fill = .data$Avg.Exp,
size = .data$P.Exp)) +
ggplot2::geom_point(color = "black", shape = 21) +
ggplot2::scale_size_continuous(range = c(0, dot.scale)) +
ggplot2::scale_fill_gradientn(colors = colors.gradient.exp,
na.value = na.value,
name = if (is.null(legend.title)){"Avg. Expression"} else {legend.title},
breaks = scale.setup.exp$breaks,
labels = scale.setup.exp$labels,
limits = scale.setup.exp$limits) +
ggplot2::labs(title = plot.title,
subtitle = plot.subtitle,
caption = plot.caption,
x = ifelse(is.null(xlab), "Genes", xlab),
y = ifelse(is.null(ylab), "", ylab)) +
ggplot2::theme_minimal(base_size = font.size) +
ggplot2::theme(axis.text.x = ggplot2::element_text(color = "black",
face = axis.text.face,
angle = get_axis_parameters(angle = axis.text.x.angle, flip = flip)[["angle"]],
hjust = get_axis_parameters(angle = axis.text.x.angle, flip = flip)[["hjust"]],
vjust = get_axis_parameters(angle = axis.text.x.angle, flip = flip)[["vjust"]]),
axis.text.y = ggplot2::element_text(face = axis.text.face, color = "black"),
axis.ticks = ggplot2::element_line(color = "black"),
axis.line = ggplot2::element_line(color = "black"),
axis.title = ggplot2::element_text(face = axis.title.face),
plot.title = ggplot2::element_text(face = plot.title.face, hjust = 0),
plot.subtitle = ggplot2::element_text(face = plot.subtitle.face, hjust = 0),
plot.caption = ggplot2::element_text(face = plot.caption.face, hjust = 1),
plot.title.position = "plot",
panel.grid = ggplot2::element_blank(),
text = ggplot2::element_text(family = font.type),
plot.caption.position = "plot",
legend.text = ggplot2::element_text(face = legend.text.face),
legend.position = legend.position,
legend.title = ggplot2::element_text(face = legend.title.face),
legend.justification = "center",
plot.margin = ggplot2::margin(t = 20, r = 0, b = 0, l = 0),
panel.grid.major = ggplot2::element_blank(),
plot.background = ggplot2::element_rect(fill = "white", color = "white"),
panel.background = ggplot2::element_rect(fill = "white", color = "white"),
legend.background = ggplot2::element_rect(fill = "white", color = "white")) +
ggplot2::guides(size = ggplot2::guide_legend(title = "Percent Expressed",
title.position = "top",
title.hjust = 0.5,
ncol = 2,
nrow = legend.nrow,
byrow = legend.byrow,
override.aes = ggplot2::aes(fill = "black")))
# Add leyend modifiers.
p1 <- modify_continuous_legend(p = p1,
# nocov start
legend.title = if (is.null(legend.title)){"Avg. Expression"} else {legend.title},
# nocov end
legend.aes = "fill",
legend.type = legend.type,
legend.position = legend.position,
legend.length = legend.length,
legend.width = legend.width,
legend.framecolor = legend.framecolor,
legend.tickcolor = legend.tickcolor,
legend.framewidth = legend.framewidth,
legend.tickwidth = legend.tickwidth)
p2 <- data.use %>%
dplyr::mutate("X_mask" = "X_label") %>%
dplyr::filter(!is.na(.data$p.adj.log10.minus)) %>%
ggplot2::ggplot(mapping = ggplot2::aes(x = if (base::isFALSE(flip)){.data$gene} else {.data$X_mask},
y = if (base::isFALSE(flip)){.data$X_mask} else {.data$gene},
fill = .data$avg_log2FC)) +
ggplot2::geom_point(color = "black", shape = 22, na.rm = TRUE, size = dot.scale) +
ggplot2::scale_fill_gradientn(colors = colors.gradient.fc,
na.value = na.value,
name = magnitude,
breaks = scale.setup.fc$breaks,
labels = scale.setup.fc$labels,
limits = scale.setup.fc$limits) +
ggplot2::labs(title = NULL,
subtitle = NULL,
caption = NULL,
x = NULL,
y = NULL) +
ggplot2::theme_minimal(base_size = font.size) +
ggplot2::theme(axis.text.x = ggplot2::element_blank(),
axis.text.y = ggplot2::element_blank(),
axis.ticks = ggplot2::element_blank(),
axis.line = ggplot2::element_blank(),
axis.title = ggplot2::element_text(face = axis.title.face),
plot.title = ggplot2::element_text(face = plot.title.face, hjust = 0),
plot.subtitle = ggplot2::element_text(face = plot.subtitle.face, hjust = 0),
plot.caption = ggplot2::element_text(face = plot.caption.face, hjust = 1),
plot.title.position = "plot",
panel.grid = ggplot2::element_blank(),
text = ggplot2::element_text(family = font.type),
plot.caption.position = "plot",
legend.text = ggplot2::element_text(face = legend.text.face),
legend.position = legend.position,
legend.title = ggplot2::element_text(face = legend.title.face),
legend.justification = "center",
plot.margin = ggplot2::margin(t = 0, r = 0, b = 0, l = 0, unit = "null"),
panel.grid.major = ggplot2::element_blank(),
plot.background = ggplot2::element_rect(fill = "white", color = "white"),
panel.background = ggplot2::element_rect(fill = "white", color = "white"),
legend.background = ggplot2::element_rect(fill = "white", color = "white"))
# Add leyend modifiers.
p2 <- modify_continuous_legend(p = p2,
# nocov start
legend.title = expression(bold(paste("avg_", log["2"], "(FC)"))),
# nocov end
legend.aes = "fill",
legend.type = legend.type,
legend.position = legend.position,
legend.length = legend.length,
legend.width = legend.width,
legend.framecolor = legend.framecolor,
legend.tickcolor = legend.tickcolor,
legend.framewidth = legend.framewidth,
legend.tickwidth = legend.tickwidth)
p3 <- data.use %>%
dplyr::mutate("X_mask" = "X_label") %>%
dplyr::filter(!is.na(.data$p.adj.log10.minus)) %>%
ggplot2::ggplot(mapping = ggplot2::aes(x = if (base::isFALSE(flip)){.data$gene} else {.data$X_mask},
y = if (base::isFALSE(flip)){.data$X_mask} else {.data$gene},
fill = .data$p.adj.log10.minus)) +
ggplot2::geom_point(color = "black", shape = 22, na.rm = TRUE, size = dot.scale) +
ggplot2::scale_fill_gradientn(colors = colors.gradient.pval,
na.value = na.value,
name = magnitude,
breaks = scale.setup.pval$breaks,
labels = scale.setup.pval$labels,
limits = scale.setup.pval$limits) +
ggplot2::labs(title = NULL,
subtitle = NULL,
caption = NULL,
x = NULL,
y = NULL) +
ggplot2::theme_minimal(base_size = font.size) +
ggplot2::theme(axis.text.x = ggplot2::element_blank(),
axis.text.y = ggplot2::element_blank(),
axis.ticks = ggplot2::element_blank(),
axis.line = ggplot2::element_blank(),
axis.title = ggplot2::element_text(face = axis.title.face),
plot.title = ggplot2::element_text(face = plot.title.face, hjust = 0),
plot.subtitle = ggplot2::element_text(face = plot.subtitle.face, hjust = 0),
plot.caption = ggplot2::element_text(face = plot.caption.face, hjust = 1),
plot.title.position = "plot",
panel.grid = ggplot2::element_blank(),
text = ggplot2::element_text(family = font.type),
plot.caption.position = "plot",
legend.text = ggplot2::element_text(face = legend.text.face),
legend.position = legend.position,
legend.title = ggplot2::element_text(face = legend.title.face),
legend.justification = "center",
plot.margin = ggplot2::margin(t = 0, r = 0, b = 0, l = 0, unit = "null"),
panel.grid.major = ggplot2::element_blank(),
plot.background = ggplot2::element_rect(fill = "white", color = "white"),
panel.background = ggplot2::element_rect(fill = "white", color = "white"),
legend.background = ggplot2::element_rect(fill = "white", color = "white"))
# Add leyend modifiers.
p3 <- modify_continuous_legend(p = p3,
# nocov start
legend.title = expression(bold(paste("-", log["10"], "(p.adjust)"))),
# nocov end
legend.aes = "fill",
legend.type = legend.type,
legend.position = legend.position,
legend.length = legend.length,
legend.width = legend.width,
legend.framecolor = legend.framecolor,
legend.tickcolor = legend.tickcolor,
legend.framewidth = legend.framewidth,
legend.tickwidth = legend.tickwidth)
p4 <- data.use %>%
dplyr::mutate("X_mask" = "X_label",
"Groups.use" = factor(.data$Groups.use, levels = rev(order.use))) %>%
dplyr::filter(!is.na(.data$p.adj.log10.minus)) %>%
ggplot2::ggplot(mapping = ggplot2::aes(x = if (base::isFALSE(flip)){.data$gene} else {.data$X_mask},
y = if (base::isFALSE(flip)){.data$X_mask} else {.data$gene},
fill = .data$Groups.use)) +
ggplot2::geom_point(color = "black", shape = 22, na.rm = TRUE, size = dot.scale) +
ggplot2::scale_size_continuous(range = c(dot.scale, dot.scale)) +
ggplot2::scale_fill_manual(values = colors.use,
na.value = na.value,
name = group.by) +
ggplot2::labs(title = NULL,
subtitle = NULL,
caption = NULL,
x = NULL,
y = NULL) +
ggplot2::theme_minimal(base_size = font.size) +
ggplot2::theme(axis.text.x = ggplot2::element_blank(),
axis.text.y = ggplot2::element_blank(),
axis.ticks = ggplot2::element_blank(),
axis.line = ggplot2::element_blank(),
axis.title = ggplot2::element_text(face = axis.title.face),
plot.title = ggplot2::element_text(face = plot.title.face, hjust = 0),
plot.subtitle = ggplot2::element_text(face = plot.subtitle.face, hjust = 0),
plot.caption = ggplot2::element_text(face = plot.caption.face, hjust = 1),
plot.title.position = "plot",
panel.grid = ggplot2::element_blank(),
text = ggplot2::element_text(family = font.type),
plot.caption.position = "plot",
legend.text = ggplot2::element_text(face = legend.text.face),
legend.position = legend.position,
legend.title = ggplot2::element_text(face = legend.title.face),
legend.justification = "center",
plot.margin = ggplot2::margin(t = 0, r = 0, b = 0, l = 0, unit = "null"),
panel.grid.major = ggplot2::element_blank(),
plot.background = ggplot2::element_rect(fill = "white", color = "white"),
panel.background = ggplot2::element_rect(fill = "white", color = "white"),
legend.background = ggplot2::element_rect(fill = "white", color = "white")) +
ggplot2::guides(fill = ggplot2::guide_legend(title = group.by,
title.position = "top",
title.hjust = 0.5,
ncol = legend.ncol,
nrow = legend.nrow,
byrow = legend.byrow))
if (base::isFALSE(flip)){
layout <- paste(c(paste(rep("A", 1), collapse = "\n"),
paste(rep("B", 1), collapse = "\n"),
paste(rep("C", 1), collapse = "\n"),
paste(rep("D", length(order.use)), collapse = "\n"),
paste(rep("E", 2), collapse = "\n")), collapse = "\n")
} else {
first <- paste(c(rep("D", length(order.use)), "C", "B", "A"), collapse = "")
layout <- paste(c(first, first, first, first, first, paste(rep("E", nchar(first)), collapse = "")), collapse = "\n")
}
p <- patchwork::wrap_plots(A = p4,
B = p3,
C = p2,
D = p1,
E = patchwork::guide_area(),
design = layout,
guides = "collect") &
patchwork::plot_annotation(theme = ggplot2::theme(legend.position = legend.position))
# Return the final heatmap.
return(p)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.