Search code examples
rggplot2axisaxis-labels

How to programmatically label the minimum and maximum values on a `ggplot` axis?


I want to have axis ticks (breaks) for the minimum value and maximum value observed in the data. But I do not want to do this manually because the code should scale to different datasets.

I have tried adapting https://stackoverflow.com/a/22819926/17724015, https://stackoverflow.com/a/5380817/17724015, and https://stackoverflow.com/a/52337662/17724015. What ggplot options am I missing?

# situation
library(ggplot2)
dat <- data.frame(x = sample(letters), y = 1:26)
ggplot(dat, aes(x, y)) + 
  geom_tile() + 
  scale_y_reverse()


# required output
ggplot(dat, aes(x, y)) + 
  geom_tile() + 
  scale_y_reverse(breaks = c(1, 10, 20, 26))


# attempted solution (not suitable, not enough breaks)
ggplot(dat, aes(x, y)) + 
  geom_tile() + 
  scale_y_reverse(breaks = seq(min(dat$y), max(dat$y), by = mean(range(dat$y)) - 1))


# attempted solution (not scalable, too many breaks)
ggplot(dat, aes(x, y)) + 
  geom_tile() + 
  scale_y_reverse(n.breaks = nrow(dat) - 1)


# attempted solution (not working)
ggplot(dat, aes(x, y)) + 
  geom_tile() + 
  scale_y_reverse(expand = expansion(add = 1))

Created on 2023-11-16 with reprex v2.0.2


Solution

  • The default function for calculating breaks is scales::extended_breaks(). You can run that function and modify the results as you see fit. (And the breaks argument accepts a function.) Maybe something like this:

    ggplot(dat, aes(x, y)) + 
      geom_tile() + 
      scale_y_reverse(breaks = \(y) {
        eb = scales::extended_breaks()(y)
        eb[1] = min(dat$y)
        eb[length(eb)] = max(dat$y)
        eb
      })
    

    enter image description here

    I'm not sure of a good way to avoid hardcoding the data frame and y column here, but at least it's better than hardcoding the actual values. Perhaps someone else will know how to do that.