Reputation: 110054
I've seen heatmaps with values made in various R graphics systems including lattice and base like this:
I tend to use ggplot2
a bit and would like to be able to make a heatmap with the corresponding cell values plotted. Here's the heat map and an attempt using geom_text
:
library(reshape2, ggplot2)
dat <- matrix(rnorm(100, 3, 1), ncol=10)
names(dat) <- paste("X", 1:10)
dat2 <- melt(dat, id.var = "X1")
p1 <- ggplot(dat2, aes(as.factor(Var1), Var2, group=Var2)) +
geom_tile(aes(fill = value)) +
scale_fill_gradient(low = "white", high = "red")
p1
#attempt
labs <- c(apply(round(dat[, -2], 1), 2, as.character))
p1 + geom_text(aes(label=labs), size=1)
Normally I can figure out the x and y values to pass but I don't know in this case since this info isn't stored in the data set. How can I place the text on the heatmap?
Upvotes: 62
Views: 84427
Reputation: 305
If you want to use ggplot2
to create a heatmap plot. I have created a package named ggalign
Specifically, it can split the heatmap into facet groups and ensure the proper alignment of the dendrogram even after faceting.
For this question, we can easily plot the heatmap and dendrogram.
library(ggalign)
#> Loading required package: ggplot2
set.seed(10)
dat <- matrix(rnorm(100, 3, 1), ncol = 10)
names(dat) <- paste("X", 1:10)
ggheatmap(dat) +
scale_fill_viridis_c() +
hmanno("t", size = unit(3, "cm"), free_spaces = "l") +
align_dendro() +
hmanno("l", size = unit(3, "cm")) +
align_dendro(aes(color = branch), k = 3) +
scale_x_reverse(expand = expansion())
Created on 2024-09-04 with reprex v2.1.0
~
~
A more complex heatmap example from the ComplexHeatmap can be created:
expr <- read_example("gene_expression.rds")
mat <- as.matrix(expr[, grep("cell", colnames(expr))])
base_mean <- rowMeans(mat)
mat_scaled <- t(apply(mat, 1, scale))
type <- gsub("s\\d+_", "", colnames(mat))
ggstack(data = mat_scaled) +
# group stack rows into 5 groups
align_kmeans(centers = 5L) +
# add a block plot for each group in the stack
ggpanel(size = unit(1, "cm")) +
geom_tile(aes(x = 1, fill = factor(.panel))) +
scale_fill_brewer(palette = "Dark2", name = "Kmeans group") +
scale_x_continuous(breaks = NULL, name = NULL) +
# add a heatmap plot in the stack
ggheatmap() +
hmanno(free_spaces = "l") +
scale_y_continuous(breaks = NULL) +
scale_fill_viridis_c() +
# add dendrogram for this heatmap
hmanno("t") +
align_dendro() +
# add a block for the heatmap column
ggalign(data = type, size = unit(1, "cm")) +
geom_tile(aes(y = 1, fill = factor(value))) +
scale_y_continuous(breaks = NULL, name = NULL) +
scale_fill_brewer(palette = "Set1", name = "type") +
# reset the heatmap active context into the heatmap body
hmanno() +
# add another heatmap in the stack
ggheatmap(base_mean) +
# set the heatmap body width
hmanno(width = unit(2, "cm")) +
scale_y_continuous(breaks = NULL) +
scale_x_continuous(name = "base mean", breaks = FALSE) +
scale_fill_gradientn(colours = c("#2600D1FF", "white", "#EE3F3FFF")) +
# set the active context of the heatmap to the top
# and set the size of the top stack
hmanno("t", size = unit(4, "cm")) +
# add box plot in the heatmap top
ggalign() +
geom_boxplot(aes(y = value, fill = factor(.extra_panel))) +
scale_x_continuous(expand = expansion(), breaks = NULL) +
scale_fill_brewer(palette = "Dark2", guide = "none") +
theme(axis.title.y = element_blank()) +
# we move into the stack layout
stack_active() +
# add a point plot
ggalign(data = expr$length, size = unit(2, "cm")) +
geom_point(aes(x = value)) +
labs(x = "length") +
theme(
panel.border = element_rect(fill = NA),
axis.text.x = element_text(angle = -60, hjust = 0)
) +
# add another heatmap
ggheatmap(expr$type) +
# set the heatmap body width, and remove the spaces in the y-axis
hmanno(width = unit(2, "cm"), free_spaces = "y") +
scale_fill_brewer(palette = "Set3", name = "gene type") +
scale_x_continuous(breaks = NULL, name = "gene type") +
# add barplot in the top annotation
hmanno("t") +
ggalign(limits = FALSE) +
geom_bar(
aes(.extra_panel, fill = factor(value)),
position = position_fill()
) +
scale_x_discrete() +
scale_y_continuous(expand = expansion()) +
scale_fill_brewer(palette = "Set3", name = "gene type", guide = "none") &
theme(plot.margin = margin())
Upvotes: 1
Reputation: 110054
Key is to add a row identifier to the data and shape it "longer".
edit Dec 2022 to make code reproducible with R 4.2.2 / ggplot2 3.4.0 and reflect changes in tidyverse semantics
library(ggplot2)
library(tidyverse)
dat <- matrix(rnorm(100, 3, 1), ncol = 10)
## the matrix needs names
names(dat) <- paste("X", 1:10)
## convert to tibble, add row identifier, and shape "long"
dat2 <-
dat %>%
as_tibble() %>%
rownames_to_column("Var1") %>%
pivot_longer(-Var1, names_to = "Var2", values_to = "value") %>%
mutate(
Var1 = factor(Var1, levels = 1:10),
Var2 = factor(gsub("V", "", Var2), levels = 1:10)
)
#> Warning: The `x` argument of `as_tibble.matrix()` must have unique column names if
#> `.name_repair` is omitted as of tibble 2.0.0.
#> ℹ Using compatibility `.name_repair`.
ggplot(dat2, aes(Var1, Var2)) +
geom_tile(aes(fill = value)) +
geom_text(aes(label = round(value, 1))) +
scale_fill_gradient(low = "white", high = "red")
Created on 2022-12-31 with reprex v2.0.2
Upvotes: 118
Reputation: 340
There is another simpler way to make heatmaps with values. You can use pheatmap to do this.
dat <- matrix(rnorm(100, 3, 1), ncol=10)
names(dat) <- paste("X", 1:10)
install.packages('pheatmap') # if not installed already
library(pheatmap)
pheatmap(dat, display_numbers = T)
This will give you a plot like this
If you want to remove clustering and use your color scheme you can do
pheatmap(dat, display_numbers = T, color = colorRampPalette(c('white','red'))(100), cluster_rows = F, cluster_cols = F, fontsize_number = 15)
You can also change the fontsize, format, and color of the displayed numbers.
Upvotes: 15