Search code examples
rggplot2facet-grid

Calculate axis tick locations based on data in faceted plot


I have an issue where I would like to calculate locations of y-axis labels in a large plot mad with facet_grid(). Let me show you what I mean using the mpg dataset.

require(tidyverse)

ggplot(mpg, aes(x = displ)) +
  geom_point(aes(y = hwy)) +
  facet_grid(drv ~ class, scales = "free")

enter image description here

You will notice that both axes use variable numbers of labels. Ignoring problems with the x-axis, I am interested in labelling only three values on the y-axis: 0, half of max value, and max value. It makes sense in my use-case, so here is what I tried.

ggplot(mpg, aes(x = displ)) +
  geom_point(aes(y = hwy)) +
  facet_grid(drv ~ class, scales = "free") +
  geom_blank(aes(y = 0)) +                                 # extends y-axis to 0
  scale_y_continuous(expand = expansion(mult = c(0, 0.1)), # prevents ggplot2 from extending beyond y = 0
                     n.breaks = 3)                         # Three axis labels, please.

enter image description here

The plot correctly starts at y = 0 and labels it correctly. However, remaining labels are poorly assigned, and have labels n = 2 and n = 4 instead of n = 3 for some reason.

If I could only directly calculate the label positions!

ggplot(mpg, aes(x = displ)) +
  geom_point(aes(y = hwy)) +
  facet_grid(drv ~ class, scales = "free") +
  geom_blank(aes(y = 0)) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.1)),
                     n.breaks = 3,
                     breaks = c(0, 0.5*max(hwy), 1*max(hwy))) # Maybe these formulas works?
Error in check_breaks_labels(breaks, labels) : object 'hwy' not found

I believe providing break points by this way should work, but that my syntax is bad. How do I access and work with the data underlying the plot? Alternatively, if this doesn't work, can I manually specify y-axis labels for each row of panels?

I could really use some assistance here, please.


Solution

  • If you want custom rules for breaks, the easiest thing is to use a function implementing those rules given the (panel) limits.

    Below an example for labeling 0, the max and half-max.

    library(ggplot2)
    
    ggplot(mpg, aes(x = displ)) +
      geom_point(aes(y = hwy)) +
      facet_grid(drv ~ class, scales = "free") +
      scale_y_continuous(expand = expansion(mult = c(0, 0.1)),
                         limits = c(0, NA), # <- fixed min, flexible max. replaces geom_blank
                         breaks = function(x){c(x[1], mean(x), x[2])})