ggplot2 Heatmap Exercises in R: 20 Practice Problems

Twenty practice problems on heatmaps in ggplot2: geom_tile, geom_raster, color scales, reordering, labels, correlation matrices.

RRun this once before any exercise
library(ggplot2) library(dplyr) library(tidyr) library(tibble)

  

Exercise 1: Basic geom_tile

Difficulty: Beginner.

Show solution
RInteractive R
df <- expand.grid(x = 1:5, y = 1:5) df$z <- runif(25) ggplot(df, aes(x, y, fill = z)) + geom_tile()

  

Exercise 2: geom_raster (faster)

Difficulty: Intermediate.

Show solution
RInteractive R
df <- expand.grid(x = 1:50, y = 1:50) df$z <- runif(nrow(df)) ggplot(df, aes(x, y, fill = z)) + geom_raster()

  

Exercise 3: Two-color gradient

Difficulty: Intermediate.

Show solution
RInteractive R
df <- expand.grid(x = 1:5, y = 1:5); df$z <- runif(25) ggplot(df, aes(x, y, fill = z)) + geom_tile() + scale_fill_gradient(low = "white", high = "red")

  

Exercise 4: Diverging gradient

Difficulty: Intermediate.

Show solution
RInteractive R
df <- expand.grid(x = 1:5, y = 1:5); df$z <- df$x - df$y ggplot(df, aes(x, y, fill = z)) + geom_tile() + scale_fill_gradient2(low = "blue", mid = "white", high = "red", midpoint = 0)

  

Exercise 5: Viridis fill

Difficulty: Intermediate.

Show solution
RInteractive R
df <- expand.grid(x = 1:5, y = 1:5); df$z <- runif(25) ggplot(df, aes(x, y, fill = z)) + geom_tile() + scale_fill_viridis_c()

  

Exercise 6: Correlation matrix heatmap

Difficulty: Advanced.

Show solution
RInteractive R
cor_mat <- cor(mtcars) cor_df <- as.data.frame(cor_mat) |> tibble::rownames_to_column("v1") |> pivot_longer(-v1, names_to = "v2", values_to = "cor") ggplot(cor_df, aes(v1, v2, fill = cor)) + geom_tile() + scale_fill_gradient2(low = "blue", mid = "white", high = "red", midpoint = 0)

  

Exercise 7: Add cell value labels

Difficulty: Intermediate.

Show solution
RInteractive R
df <- expand.grid(x = 1:3, y = 1:3); df$z <- 1:9 ggplot(df, aes(x, y, fill = z)) + geom_tile() + geom_text(aes(label = z), color = "white")

  

Exercise 8: Reverse y axis

Difficulty: Intermediate.

Show solution
RInteractive R
df <- expand.grid(x = 1:5, y = 1:5); df$z <- runif(25) ggplot(df, aes(x, y, fill = z)) + geom_tile() + scale_y_reverse()

  

Exercise 9: Square aspect ratio

Difficulty: Intermediate.

Show solution
RInteractive R
df <- expand.grid(x = 1:5, y = 1:5); df$z <- runif(25) ggplot(df, aes(x, y, fill = z)) + geom_tile() + coord_equal()

  

Exercise 10: Order rows/cols by hierarchical clustering

Difficulty: Advanced.

Show solution
RInteractive R
m <- cor(mtcars) order <- hclust(dist(m))$order m_ord <- m[order, order] m_long <- as.data.frame(m_ord) |> tibble::rownames_to_column("v1") |> pivot_longer(-v1, names_to = "v2", values_to = "cor") |> mutate(v1 = factor(v1, levels = rownames(m_ord)), v2 = factor(v2, levels = colnames(m_ord))) ggplot(m_long, aes(v1, v2, fill = cor)) + geom_tile() + scale_fill_gradient2(low = "blue", mid = "white", high = "red")

  

Exercise 11: Tile with white grid

Difficulty: Intermediate.

Show solution
RInteractive R
df <- expand.grid(x = 1:5, y = 1:5); df$z <- runif(25) ggplot(df, aes(x, y, fill = z)) + geom_tile(color = "white", linewidth = 1)

  

Exercise 12: Tile from a count table

Difficulty: Advanced.

Show solution
RInteractive R
diamonds |> count(cut, color) |> ggplot(aes(cut, color, fill = n)) + geom_tile() + scale_fill_viridis_c()

  

Exercise 13: Mask diagonal

Difficulty: Advanced.

Show solution
RInteractive R
m <- cor(mtcars[, 1:5]) m[lower.tri(m, diag = FALSE)] <- NA df <- as.data.frame(m) |> tibble::rownames_to_column("v1") |> pivot_longer(-v1, names_to = "v2", values_to = "cor") |> na.omit() ggplot(df, aes(v1, v2, fill = cor)) + geom_tile() + scale_fill_gradient2(low = "blue", high = "red")

  

Exercise 14: Limit color range

Difficulty: Advanced.

Show solution
RInteractive R
df <- expand.grid(x = 1:5, y = 1:5); df$z <- runif(25) ggplot(df, aes(x, y, fill = z)) + geom_tile() + scale_fill_gradient(low = "white", high = "red", limits = c(0, 1))

  

Exercise 15: Annotate cells with formatted numbers

Difficulty: Advanced.

Show solution
RInteractive R
m <- cor(mtcars[, 1:5]) df <- as.data.frame(m) |> tibble::rownames_to_column("v1") |> pivot_longer(-v1, names_to = "v2", values_to = "cor") ggplot(df, aes(v1, v2, fill = cor)) + geom_tile() + geom_text(aes(label = sprintf("%.2f", cor)), color = "black", size = 3) + scale_fill_gradient2(low = "blue", high = "red")

  

Exercise 16: Faceted heatmap

Difficulty: Advanced.

Show solution
RInteractive R
df <- expand.grid(x = 1:3, y = 1:3, group = c("A","B")) df$z <- runif(nrow(df)) ggplot(df, aes(x, y, fill = z)) + geom_tile() + facet_wrap(~ group)

  

Exercise 17: Time-vs-day calendar heatmap

Difficulty: Advanced.

Show solution
RInteractive R
df <- expand.grid(day = 1:7, hour = 0:23) df$count <- sample(0:50, nrow(df), replace = TRUE) ggplot(df, aes(hour, day, fill = count)) + geom_tile() + scale_fill_viridis_c() + scale_y_reverse()

  

Exercise 18: Theme cleanup

Difficulty: Advanced.

Show solution
RInteractive R
df <- expand.grid(x = 1:5, y = 1:5); df$z <- runif(25) ggplot(df, aes(x, y, fill = z)) + geom_tile() + theme_minimal() + theme(panel.grid = element_blank())

  

Exercise 19: Combine with text and color

Difficulty: Advanced.

Show solution
RInteractive R
df <- data.frame(team = rep(c("A","B","C"), each = 3), metric = rep(c("M1","M2","M3"), 3), val = round(runif(9), 2)) ggplot(df, aes(metric, team, fill = val)) + geom_tile(color = "white") + geom_text(aes(label = val), color = "black") + scale_fill_viridis_c() + theme_minimal()

  

Exercise 20: Custom legend position

Difficulty: Intermediate.

Show solution
RInteractive R
df <- expand.grid(x = 1:5, y = 1:5); df$z <- runif(25) ggplot(df, aes(x, y, fill = z)) + geom_tile() + theme(legend.position = "top")

  

What to do next

  • ggplot2-Exercises (shipped), broader practice.
  • ggplot2-Color-Scales-Exercises (shipped), palette focus.