3

From this dataframe

 df <- data.frame(cat=c(rep("X", 20),rep("Y", 20), rep("Z",20)), 
                     value=c(runif(20),runif(20)*100, rep(0, 20)), 
                     var=rep(LETTERS[1:5],12))

i want to create facetted boxplots.

library(ggplot2)

p1 <- ggplot(df, aes(var,value)) + geom_boxplot() + facet_wrap(~cat, scale="free") 
p1

The results is aesthetically dissactisfactory as it centers the y-axis of the empty panel at zero. I want to start all y-scales at zero. I tried several answers from this earlier question:

p1 + scale_y_continuous(expand = c(0, 0)) # not working
p1 + expand_limits(y = 0) #not working
p1 + scale_y_continuous(limits=c(0,NA)) ## not working
p1 + scale_y_continuous(limits=c(0,100)) ## partially working, but defeats scale="free"
p1 + scale_y_continuous(limits=c(0,max(df$value))) ## partially working, see above
p1 + scale_y_continuous(limits=c(0,max(df$value))) + expand_limits(y = 0)## partially working, see above

One solution would possibly be to replace the zero's with very tiny values, but maybe you can find a more straightforward solution. Thank you.

nouse
  • 3,315
  • 2
  • 29
  • 56
  • 1
    Seems like this might be good candidate to be filed as an issue https://github.com/tidyverse/ggplot2/issues. But how would you expect the plot to choose a max y value for the Z panel? I'm not sure there's an obvious default there. – MrFlick Mar 02 '20 at 17:24
  • good point. maybe to max(df$value))? – nouse Mar 02 '20 at 17:31

2 Answers2

4

A simpler solution would be to pass a function as the limits argument:

p1 <- ggplot(df, aes(var,value)) + geom_boxplot() + facet_wrap(~cat, scale="free") +
  scale_y_continuous(limits = function(x){c(0, max(0.1, x))})

enter image description here

The function takes per facet the automatically calculated limits as x argument, where you can apply any transformation on them, such as for example choosing the maximum between 0.1 and the true maximum.

The result is still subject to scale expansion though.

teunbrand
  • 33,645
  • 4
  • 37
  • 63
1

This might be a bit of a work around, but you could use geom_blank() to help set your axis dimension. For example:

df <- data.frame(cat=c(rep("X", 20),rep("Y", 20), rep("Z",20)), 
                 value=c(runif(20),runif(20)*100, rep(0, 20)), 
                 var=rep(LETTERS[1:5],12))

# Use this data frame to set min and max for each category
# NOTE: If the value in this DF is smaller than the max in df it will be overridden
# by the max(df$value)
axisData <- data.frame(cat = c("X", "X", "Y", "Y", "Z", "Z"),
                       x = 'A', y = c(0, 1, 0, 100, 0, 1))

p1 <- ggplot(df, aes(var,value)) + 
        geom_boxplot() + 
        geom_blank(data = axisData, aes(x = x, y = y)) +
        facet_wrap(~cat, scale="free") 

p1
Amanda
  • 506
  • 2
  • 6