How to harmonize axes within facet_wrap and scale="free_y"?

Viewed 1229

I would like to draw boxplots of relationship between a continuous and a categorical variables (geom_boxplot with ggplot2), this for several situations (facet_wrap). Quite easy:

data("CO2")
ggplot(CO2, aes(Treatment, uptake) ) + 
  geom_boxplot(aes(Treatment, uptake), 
               col="black", fill="white", alpha=0, width=.5) + 
  geom_point(col="black", size=1.2) + 
  facet_wrap(~Type, ncol=3, nrow=6, scales= "free_y") + 
  theme_bw() + 
  ylab("Uptake")

The result: enter image description here

This is quite nice with this toy dataset, but applied to my own data (where facet_wrap enables me to plot 18 different graphs) the y-axes are hardly readable, with varying number of y-ticks and varying spacing between them:

enter image description here

What could be a nice way to harmonize the y-axes? (i.e., getting equal spacing between y-axes ticks, no matter what breaks are -these will necessarily change from a graph to another because the variation range of my continuous variable changes a lot)

Thank you very much for any help :)

2 Answers

You can turn force each facet's limits to something relatively nice looking, by manually expanding each facet's values through the application of pretty() on the y-axis values & taking the first / last values.

The following is an example using the diamonds dataset:

# normal facet_wrap plot with many different y-axis scales across facets
p <- ggplot(diamonds %>% filter(cut %in% c("Fair", "Ideal")), 
       aes(x = cut, y = carat) ) + 
  geom_boxplot(col="black", fill="white", alpha=0, width=.5) + 
  geom_point(col="black", size=1.2) + 
  facet_wrap(~clarity, scales= "free_y", nrow = 2) + 
  theme_bw() + 
  ylab("Uptake")

p

plot

# modified plot with consistent label placements
p + 
  # Manually create values to expand the scale, by finding "pretty" 
  # values that are slightly larger than the range of y-axis values 
  # within each facet; set alpha = 0 since they aren't meant to be seen
  geom_point(data = . %>% 
               group_by(clarity) %>% #group by facet variable
               summarise(y.min = pretty(carat)[1],
                         y.max = pretty(carat)[length(pretty(carat))]) %>%
               tidyr::gather(key, value, -clarity), 
             aes(x = 1, y = value),
             inherit.aes = FALSE, alpha = 0) +

  # Turn off automatical scale expansion, & manually set scale breaks
  # as an evenly spaced sequence (with the "pretty" values created above
  # providing the limits for each facet). If there are many facets to
  # show, I recommend no more than 3 labels in each facet, to keep things
  # simple.
  scale_y_continuous(breaks = function(x) seq(from = x[1], 
                                              to = x[2], 
                                              length.out = 3), 
                     expand = c(0, 0))

plot2

Just remove scales= "free_y" inside geom_point, you should get what you want.

However, it has been rightly pointed out by MrFlick in comments, even spacing will most definitely result in crazy weird numbers on the axes

Related