rggplot2heatmap

Warning message: Removed 2 rows containing missing values (`geom_tile()`)


I want to produce a heatmap of values by days (0 to 41 = 6 weeks) by hours in the day (0 to 23).

The first example below works fine, but the second produces an error

Warning message: Removed 2 rows containing missing values (`geom_tile()`).

The error message is strange because there are no explicit missing values in my data. Also the plot shows a merger of consecutive days!

I need to set the breaks so that the axis ticks align with seven days and 3 hours on the day. I set the limits so that I always have a full 6 weeks and 24 hours. I had this same error before and thought I'd solved it by expanding the limits from 0:23 and 0:41 to -1:24 and -1:42, which helped in some cases (I don't understand why I had to do that). Thanks.

library(ggplot2)

hours<-c(8,9,1,12,8,9,8,9,8)
days<-c(0,0,1,1,14,14,40,40,41)
value<-c(47,11,46,11,48,12,57,3,47)
df<-data.frame(cbind(hours,days,value))

ggplot(df,aes(days,hours))+
  geom_tile(fill=value)+
  geom_text(aes(label=value),size=3)+
  scale_fill_gradient(low="white",high="red")+
  xlab("Day")+
  ylab("Hour")+
  scale_x_continuous(breaks=seq(0,41,by=7),limits=c(-1,42))+
  scale_y_continuous(breaks=seq(0,23,by=3),limits=c(-1,24))

hours<-c(16,17,0,1,2,21,22,9,19,20)
days<-c(0,0,3,3,3,6,6,11,21,21)
value<-c(3,60,18,60,23,51,48,49,47,40)
df<-data.frame(cbind(hours,days,value))

ggplot(df,aes(days,hours))+
  geom_tile(fill=value)+
  geom_text(aes(label=value),size=3)+
  scale_fill_gradient(low="white",high="red")+
  xlab("Day")+
  ylab("Hour")+
  scale_x_continuous(breaks=seq(0,41,by=7),limits=c(-1,42))+
  scale_y_continuous(breaks=seq(0,23,by=3),limits=c(-1,24))

EDIT

Thanks to PBulls with the suggestion to further widen the limits. However I still see a wider heatbox than I am expecting: enter image description here My output is different to theirs.


Solution

  • The issue is that the tiles have a width and height and you have to account for that when setting the limits (And what you already tried when you have set the limits). However, whereas in case of a discrete scale the width and height of the tiles are set to 1 by default (and it is sufficient to add -/+ .5), this is not the case for a continuous scale. I haven't had a look at the source but my guess is that the width and height are set according to the minimum of the (positive) distances between the data points. Hence, depending on your data you end up with different values for the tile width and height and accordingly have to expand the limits by a different amount.

    Instead I would suggest to explicitly set the width and height to 1. Doing so it is sufficient to expand the limits by -/+ .5 and it should also fix the issue with the "merged" or overlapping tiles for consecutive days/hours.

    library(ggplot2)
    
    # Set width and height to 1
    w <- 1
    h <- 1
    
    hours <- c(8, 9, 1, 12, 8, 9, 8, 9, 8)
    days <- c(0, 0, 1, 1, 14, 14, 40, 40, 41)
    value <- c(47, 11, 46, 11, 48, 12, 57, 3, 47)
    
    df <- data.frame(hours, days, value)
    
    ggplot(df, aes(days, hours)) +
      geom_tile(fill = value, width = w, height = h) +
      geom_text(aes(label = value), size = 3) +
      scale_fill_gradient(low = "white", high = "red") +
      xlab("Day") +
      ylab("Hour") +
      scale_x_continuous(
        breaks = seq(0, 41, by = 7),
        limits = c(0, 41) + w / 2 * c(-1, 1),
        expand = c(0, 0)
      ) +
      scale_y_continuous(
        breaks = seq(0, 23, by = 3),
        limits = c(0, 23) + h / 2 * c(-1, 1),
        expand = c(0, 0)
      )
    

    
    hours <- c(16, 17, 0, 1, 2, 21, 22, 9, 19, 20)
    days <- c(0, 0, 3, 3, 3, 6, 6, 11, 21, 21)
    value <- c(3, 60, 18, 60, 23, 51, 48, 49, 47, 40)
    df <- data.frame(hours, days, value)
    
    ggplot(df, aes(days, hours)) +
      geom_tile(fill = value, width = w, height = h) +
      geom_text(aes(label = value), size = 3) +
      scale_fill_gradient(low = "white", high = "red") +
      xlab("Day") +
      ylab("Hour") +
      scale_x_continuous(
        breaks = seq(0, 41, by = 7),
        limits = c(0, 41) + w / 2 * c(-1, 1),
        expand = c(0, 0)
      ) +
      scale_y_continuous(
        breaks = seq(0, 23, by = 3),
        limits = c(0, 23) + h / 2 * c(-1, 1),
        expand = c(0, 0)
      )