Search code examples
rggplot2legendheatmap

Customize legend with discrete labels for heatmap with continuous but binned data


I have created a heatmap in ggplot with continuous temperature data and scale_fill_viridis_c:

heatmap continuous

To make it easier to read I am testing a binned version with scale_fill_viridis_b and n.breaks:

enter image description here

My problem is that the binned heatmap legend shows ALL level labels, in this case every degree. I prefer to show only 5 or 6 labels in the legend. What I want is to keep the resolution in the plot an legend colours, but only label some of them (eg 0, 3, 6, 9, 12).

I have tried setting the labels manually with labels=c(0, 3, 6, 9, 12), but R complains that breaks and labels are different lengths. I want that but can't have it... I have also considered to mutate the whole data set, but would rather not since it is quite large, and also contains other data than temperature.

I know I should include a working sample of code and data, but I hope my question is straightforward enough to answer anyways. I would appreciate any help on how to format the legend of a binned heatmap, to show a smaller number of labels than the number of breaks.


Solution

  • You could label only some of the breaks by assigning an empty string aka "" as the label for breaks you don't want to label. To this end I use an ifelse wrapped in an anonymous function which can be passed to the labels= argument of scale_fill_viridis_b.

    Using some fake example data:

    library(ggplot2)
    
    dat <- expand.grid(
      x = seq(10),
      y = seq(10)
    )
    dat$temp <- seq(0, 14, length.out = 100)
    
    ggplot(dat) +
      geom_tile(aes(x, y, fill = temp)) +
      scale_fill_viridis_b(
        option = "turbo",
        n.breaks = 14,
        labels = \(x) ifelse(
          x %% 3 == 0, x, ""
        ),
        guide = guide_colorsteps(show.limits = TRUE)
      )