7
votes

Is there a way to change the heights/lengths of the y-axis for individual facets in a facet_grid or facet_wrap?

For example,

library(ggplot2)
ggplot(economics_long[economics_long$variable %in% c("pop", "uempmed"),], aes(date, value)) +
    geom_line() +
    facet_grid(variable~., scales = "free_y") +
    theme(strip.background = element_blank())

enter image description here

In the above plot, I would like the pop time series y-axis height/length to be, say, twice as large as the uempmed y-axis length (2:1), regardless of the fact the two time series have different y-axis scales.

Like what Kohske does here, in a much older version of ggplot2, which doesn't work in ggplot >=2.0.0:

https://kohske.wordpress.com/2010/12/25/adjusting-the-relative-space-of-a-facet-grid/

I know I can specify the argument space = "free" in facet_grid, but I don't think that argument can be used to set a 2:1 y-axis ratio?

I also don't want to use a "grid.arrange type" solution for lining up separately created ggplots (where I can make the 2 separate plots with different y-axis lengths), because I would ideally like to make use of Shiny's interactive ggplot2 features in this one single facet_wrap plot (e.g. an interactive shiny facet example with a brush is half way down the page here: http://shiny.rstudio.com/articles/selecting-rows-of-data.html).

1
Did you ever found a solution for your problem? I am asking as I have the exact same question. And what to do when you have 3 grids and you want them in a ratio (2, 1, 1). It is quite easy to do with grid_extra and the heights parameter, but they don't align well verticallyFranky
Unfortunately not yet. Maybe there is a way to it, particularly with the updates to ggplot2 over the past year or so but I'm not aware of it. My guess is it probably still needs implementing in the ggplot2 source, which I'm not at all familiar with.FXQuantTrader

1 Answers

4
votes

There are multiple options.

With facets, you can use facet_grid(..., space='free_y') to have the height of each row adjusted to the length of the y-scale. In your data set, however, the bottom row is minimised to a single line (0-25 vs. 200,000 - 320,000).

When ggplot2 objects are plotted/printed, they are first converted to gtable objects. Saving your plot as p, we can call ggplotGrob to get the gtable object. This is a one-way procedure; once converted, you cannot convert the gtable back to a ggplot2 object!

(g <- ggplotGrob(p))
TableGrob (12 x 8) "layout": 18 grobs
    z         cells       name                                    grob
1   0 ( 1-12, 1- 8) background        rect[plot.background..rect.3766]
2   1 ( 6- 6, 4- 4)  panel-1-1               gTree[panel-1.gTree.3696]
3   1 ( 8- 8, 4- 4)  panel-1-2               gTree[panel-2.gTree.3711]
4   3 ( 5- 5, 4- 4)   axis-t-1                          zeroGrob[NULL]
5   3 ( 9- 9, 4- 4)   axis-b-1    absoluteGrob[GRID.absoluteGrob.3725]
6   3 ( 6- 6, 3- 3)   axis-l-1    absoluteGrob[GRID.absoluteGrob.3733]
7   3 ( 8- 8, 3- 3)   axis-l-2    absoluteGrob[GRID.absoluteGrob.3741]
8   3 ( 6- 6, 6- 6)   axis-r-1                          zeroGrob[NULL]
9   3 ( 8- 8, 6- 6)   axis-r-2                          zeroGrob[NULL]
10  2 ( 6- 6, 5- 5)  strip-r-1                           gtable[strip]
11  2 ( 8- 8, 5- 5)  strip-r-2                           gtable[strip]
12  4 ( 4- 4, 4- 4)     xlab-t                          zeroGrob[NULL]
13  5 (10-10, 4- 4)     xlab-b titleGrob[axis.title.x..titleGrob.3714]
14  6 ( 6- 8, 2- 2)     ylab-l titleGrob[axis.title.y..titleGrob.3717]
15  7 ( 6- 8, 7- 7)     ylab-r                          zeroGrob[NULL]
16  8 ( 3- 3, 4- 4)   subtitle  zeroGrob[plot.subtitle..zeroGrob.3763]
17  9 ( 2- 2, 4- 4)      title     zeroGrob[plot.title..zeroGrob.3762]
18 10 (11-11, 4- 4)    caption   zeroGrob[plot.caption..zeroGrob.3764]

All the elements are set up in a grid-like layout. The height of each row in the layout is given by g$heights:

> g$heights
 [1] 5pt                 0cm                 0cm                 0cm                 0cm                 1null               5pt                 1null               0.396281911581569cm 1grobheight        
[11] 0cm                 5pt    

Match the coordinate of 'panel-1-1' and 'panel-1-2' to these heights, and you'll find the 6th and 8th element are both 1null. You can change them to any unit, cm, in, pt, ... The 1null is simply what is left after the other elements, and divided among them. So we can change the 6th heigth to 2null (note the use of double brackets):

> g$heights[[6]] <- unit(2, 'null')
> grid.draw(g)

enter image description here