3

I have a made a heatmap in R using ggplot.

Example

# Libraries
library(tidyverse)

# Create data frame
df <- data.frame(test = rep(c("testA-01", "testA-02", "testA-03", "testB-01", "testB-02", "testB-03", "testC-01", "testC-02", "testC-03"),3), 
                 time = c( rep(0,9), rep(1, 9), rep(2, 9) ), 
                 score = sample(1:10, 27, replace = TRUE) )

# Create heatmap
ggplot(data = df, mapping = aes(x = time, y = test)) +
  geom_tile(mapping = aes(fill = score, width=0.9, height=0.9)) +
  scale_fill_gradientn(limits = c(1,10), colours=c("grey95", "grey40", "red"), na.value = "white" ) +
  scale_y_discrete(name = "Test", limits = c("testC-03", "testC-02", "testC-01", "testB-03", "testB-02", "testB-01", "testA-03",
                                                "testA-02", "testA-01")) +
  theme_classic()

This lead to the following plot:

enter image description here

I would like to bundle the labels on the y-axis, so that I do not repeat "Test[letter]" three times for each test. I am able to do it manually, however, I thought maybe it is possible to use ggplot. The first part of the solution is to remove the "Test[letter]" part from the limits of scale_y_discrete(). Next I would like to add the labels vertically and grouped per test on the y-axis (preferably with a vertical line grouping the tests), like this:

Expected Result enter image description here

Is this possible in ggplot? And if so, how do you do this?

user213544
  • 2,046
  • 3
  • 22
  • 52
  • 2
    This should get you going: [Axis labels on two lines with nested x variables (year below months)](https://stackoverflow.com/questions/44616530/axis-labels-on-two-lines-with-nested-x-variables-year-below-months) – Henrik Jun 19 '19 at 07:56
  • @Henrik Thanks for your suggestion, I was able to figure out how to add 'two labels' per axis (posted as answer below). However, I am not sure how to add a vertical line outside the plot, that groups the variables per facet. Any ideas? – user213544 Jun 20 '19 at 13:01
  • Nice plot! I understand you request, but you may also consider a more minimalistic alternative where you create a tiny gap between panels, e.g. `panel.spacing = unit(0.1, "cm")` (or whatever value you think looks good in the final rendered plot). Then axis itself becomes the vertical line, and an additional line may be redundant. But that's just my personal, minimalistic approach to data-ink ratio. Good luck! – Henrik Jun 20 '19 at 13:33

1 Answers1

4

Some rearrangements of the dataframe eases the plotting:

df <- data.frame(batch = c( rep("TestA",9), rep("TestB", 9), rep("TestC", 9) ), 
                 test = rep(c(1,2,3),9), 
                 time = rep(c(0,0,0,1,1,1,2,2,2),3), 
                 score = sample(1:10, 27, replace = TRUE) )

Plot

With the facet_grid() function it is possible to facet the data in the plot. Using the annotation_custom() function of ggplot and coord_cartesian(), I was able to add 'grouping' lines.

library(tidyverse)
library(grid)

ggplot(data = df, mapping = aes(x = time, y = test)) +
geom_tile(mapping = aes(fill = score, width=0.9, height=0.9)) +
scale_fill_gradientn(limits = c(1,10), colours=c("grey95", "grey40", "red"), na.value = "white" ) +
theme_classic() +
scale_y_reverse() +
facet_grid(batch ~ ., space="free_x", scales="free_y", switch="y") +
theme(strip.placement = "outside",
      strip.background = element_rect(fill=NA,colour=NA),
      panel.spacing=unit(0,"cm"), axis.title.y = element_blank()) +
annotation_custom(grob = linesGrob(), xmin = -0.75, xmax = -0.75, ymin = -3.25, ymax = -0.75) +
coord_cartesian(clip="off") 

enter image description here

user213544
  • 2,046
  • 3
  • 22
  • 52