19

I have this data

library(ggplot2)

dat = data.frame(x = c(1,2,1,2), 
                 group = c("a","a","b","b"), 
                 y = c(10,20,1000,2000))

ggplot(dat, aes(x = x, y = y)) + 
    geom_point() + 
    geom_line() + 
    facet_wrap(~group, ncol = 1) +
    coord_cartesian(ylim = c(0, 30))

You can see the B group does not show up because I set the y limit to 0,30. I want to manually set the individual y limits for each chart. I do NOT want to use scales = "free_y" because I need control over the limits in each chart.

Is there a way this can be done? Can you somehow supply y limits for each chart in a facet wrap?

alistaire
  • 42,459
  • 4
  • 77
  • 117
user3022875
  • 8,598
  • 26
  • 103
  • 167
  • you can with `gridExtra` package and individual plots. – mtoto Mar 03 '17 at 21:06
  • 2
    Thats not what I'm looking for – user3022875 Mar 03 '17 at 21:08
  • what's the difference if you want to set the individual y limits for each chart anyway. – mtoto Mar 03 '17 at 21:10
  • Seems like it's not supported officially: https://github.com/tidyverse/ggplot2/issues/187 – MrFlick Mar 03 '17 at 21:13
  • It's a lot more work. What if you have 50,100 plots.... – user3022875 Mar 03 '17 at 21:17
  • create a loop that generates your plots and save them as a list. – mtoto Mar 03 '17 at 21:25
  • that is a last resort. facet should have this feature – user3022875 Mar 03 '17 at 21:30
  • 2
    Feel free to make implement it and send a pull request. – Roman Luštrik Mar 03 '17 at 21:57
  • I had a similar question [How to apply separate coord_cartesian() to “zoom in” into individual panels of a facet_grid()?](http://stackoverflow.com/q/41536406/3817004). A lot of discussion in comments and chat but unanswered so far. – Uwe Mar 03 '17 at 22:33
  • I did something [similar](https://github.com/raredd/plotr/blob/master/R/ggplots.R#L1304) but for the x-axis (continuous or categorical), so I'm sure you could the the same for y.. basically add a geom_blank like the answer below. It can be finicky, so it would be nice if this was built in. I avoid ggplot so I haven't revisited this in a while – rawr Mar 04 '17 at 00:17

1 Answers1

39

Unless you want to decrease your plotting area (i.e. not plot some points), you can still have "full" control over your y limits while using scales = "free_y".

You can use the same trick I have given to answer your other question: how to set limits on rounded facet wrap y axis?

dat <- data.table(dat)

dat[,y_min := y*0.5, by = group]
dat[,y_max:= y*1.5, by = group]

ggplot(dat, aes(x = x, y = y)) + 
  geom_point() + 
  geom_line() + 
  facet_wrap(~group, ncol = 1, scales = "free_y") +
  geom_blank(aes(y = y_min)) +
  geom_blank(aes(y = y_max))

For others reading this question, trick is to explicitly create y_min and y_max variables for each group. And "plot" them via geom_blank(). (Nothing is actually plotted, but each facet's plotting area is adjusted based on y_min and y_max values for that group).

If for some reasons, you want to manually give min and max (instead of a rule), none is stopping you. But it is tedious:

dat[group == "a",y_min := 0]
dat[group == "a",y_max := 30]
dat[group == "b",y_min := 0]
dat[group == "b",y_max := 3000]

ggplot(dat, aes(x = x, y = y)) + 
  geom_point() + 
  geom_line() + 
  facet_wrap(~group, ncol = 1, scales = "free_y") +
  geom_blank(aes(y = y_min)) +
  geom_blank(aes(y = y_max))

But, as I have mentioned this works if you want to extend your limits, not decrease them. enter image description here

Community
  • 1
  • 1
Jav
  • 2,203
  • 13
  • 22
  • 1
    Very clever solution, well explained. But does this also work to "zoom in"? – Uwe Mar 04 '17 at 01:04
  • 2
    Unfortunately no. `geom_blank()` can be used to increase the limits but not to decrease. Can't think of a similar solution for decreasing ("zoom in") right now. Maybe put a condition to remove those 'outliers' for plotting. Thus, if you want to plot y between 2 and 4 only. But your data goes from 1 to 10. Put a condition before plot to remove anything below 2 or above 4. – Jav Mar 05 '17 at 16:51