5

I am trying to create a heatmap with ggplots geom_tile. As it stands the grid lines are centered at the middle of each geom_tile. What I want is the gridlines to be aligned with the start/end of each tile. I have seen a few related posts (here, here, but all are dealing with continuous scales. In my case, both scales are discrete/factors. Any idea? Many thanks!

library(tidyverse)

my_iris <- iris %>% 
  mutate(sepal_interval=cut(Sepal.Length, 4)) %>% 
  group_by(sepal_interval, Species)

my_iris %>% 
  summarise(n_obs=n()) %>% 
  ggplot()+
  geom_tile(aes(y=Species,
                x=sepal_interval,
                fill=n_obs))+
  theme_bw()+
  theme(panel.grid = element_line(color="black"))

Created on 2020-01-28 by the reprex package (v0.3.0)

zoowalk
  • 2,018
  • 20
  • 33
  • Would adding horizontal and vertical lines similar to this: https://stackoverflow.com/questions/24099096/ggplot2-gridlines-between-discrete-values help you? – Valeri Voev Jan 28 '20 at 14:13

2 Answers2

6

I've had a lot of success using geom_rect to make my heatmaps in ggplot2. While there's a bit more data finessing on the front-end, I've found that it's more flexible and easily customizable.

my_iris <- iris %>% 
  mutate(sepal_interval=cut(Sepal.Length, 4)) %>% 
  group_by(sepal_interval, Species) %>% 
  summarise(n_obs=n()) %>%
  mutate(sepal.id = as.numeric(as.factor(sepal_interval)),
         species.id = as.numeric(as.factor(Species)))

species.key <- levels(factor(my_iris$Species))
sepal.int.key <- levels(factor(my_iris$sepal_interval))

my_iris %>%
  ggplot() +
  geom_rect(aes(xmin = sepal.id, xmax = sepal.id+1, ymin = species.id, ymax = species.id+1, fill = n_obs)) +
  theme_bw() +
  scale_x_continuous(breaks = seq(1.5, length(sepal.int.key)+0.5, 1), labels = sepal.int.key, expand = c(0,0)) +
  scale_y_continuous(breaks = seq(1.5, length(species.key) + 0.5, 1), labels = species.key, expand = c(0,0)) +
  theme(panel.grid.major.x = element_blank(),
        panel.grid.major.y = element_blank(),
        panel.ontop = TRUE,
        panel.background = element_rect(fill = "transparent"))

With the output: enter image description here

krfurlong
  • 867
  • 6
  • 17
0

I believe you are looking for some variation of:

my_iris %>% 
  summarise(n_obs=n()) %>% 
  ggplot()+
  geom_raster(aes(y=Species,
                  x=sepal_interval,
                  fill=n_obs), 
              hjust =0,
              vjust =0)+
  theme_bw()+
  theme(panel.grid = element_line(color="black")) 

I don't believe hjust and vjust arguments work with geom_tile but geom_raster is what is used in the help pages. values for hjust and vjust should be between 0 and 1, they both default to 0.5 which centers them at the point.

Justin Landis
  • 1,981
  • 7
  • 9
  • many thanks. it's pretty close but unfortuantely as far as i can see it, the labels are not centered on the middle of the rectangles but positioned on the breaks/the lines. It seems using theme(axis.text=element_text(hjust=0.5) etc helps a bit but doesn't resolve the problem entirely. – zoowalk Jan 31 '20 at 15:43
  • From the links you posted, I assumed you wanted the labels to be aligned with the grid lines of each tile. Unfortunately there isnt easy ways to make grid lines on discrete scales, you will need to manually add them with continuous scale – Justin Landis Feb 03 '20 at 16:03