Claus Wilke Claus Wilke - 3 months ago 19
R Question

Setting width in gtable object collapses plot; this used to work but it doesn't anymore.

The following code used to work but doesn't anymore. Does anybody have an idea what's going on? It must be some change in the underlying gtable code.

require(cowplot) # for plot_grid()
require(grid) # for unit_max()

# make two plots
plot.iris <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point() + facet_grid(. ~ Species) + stat_smooth(method = "lm") +
background_grid(major = 'y', minor = "none") +
panel_border()
plot.mpg <- ggplot(mpg, aes(x = cty, y = hwy, colour = factor(cyl))) +
geom_point(size=2.5)

g.iris <- ggplotGrob(plot.iris) # convert to gtable
g.mpg <- ggplotGrob(plot.mpg) # convert to gtable

iris.widths <- g.iris$widths[1:3] # extract the first three widths,
# corresponding to left margin, y lab, and y axis
mpg.widths <- g.mpg$widths[1:3] # same for mpg plot
max.widths <- unit.pmax(iris.widths, mpg.widths) # calculate maximum widths
g.iris$widths[1:3] <- max.widths # assign max. widths to iris gtable
g.mpg$widths[1:3] <- max.widths # assign max widths to mpg gtable

plot_grid(g.iris, g.mpg, labels = "AUTO", ncol = 1)


The resulting plot is the following:
enter image description here

What it should look like is this (with the y axis lines perfectly aligned vertically):
enter image description here

The error seems to happen in this line:

g.iris$widths[1:3] <- max.widths


Any insight would be appreciated.

Note that similar solutions have been used for a long time, see e.g. here. And the
plot_grid()
function in cowplot uses code like this also to align plots, and it still works. So this has me completely mystified.

Answer

Edit
With grid version 3.3.0, this is no longer an issue. That is, the lines of code containing grid:::unit.list() below can be deleted.

The issue is to do with the way units are set. Look at g.iris$widths. You'll notice that the numerals are there but the units have been dropped. See this question and answer, and this one. After converting the plots to gtables, you need: g.iris$widths = grid:::unit.list(g.iris$widths)

require(grid) # for unit_max()
require(cowplot)

# make two plots
plot.iris <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) + 
  geom_point() + facet_grid(. ~ Species) + stat_smooth(method = "lm") + 
  background_grid(major = 'y', minor = "none") + 
  panel_border()
plot.mpg <- ggplot(mpg, aes(x = cty, y = hwy, colour = factor(cyl))) + 
  geom_point(size=2.5) 

g.iris <- ggplotGrob(plot.iris) # convert to gtable   
g.mpg <- ggplotGrob(plot.mpg) # convert to gtable

g.iris$widths = grid:::unit.list(g.iris$widths)   
g.mpg$widths =  grid:::unit.list(g.mpg$widths)

iris.widths <- g.iris$widths[1:3] # extract the first three widths, 
                                  # corresponding to left margin, y lab, and y axis
mpg.widths <- g.mpg$widths[1:3] # same for mpg plot

max.widths <- unit.pmax(iris.widths, mpg.widths) # calculate maximum widths

g.iris$widths[1:3] <- max.widths # assign max. widths to iris gtable
g.mpg$widths[1:3] <- max.widths # assign max widths to mpg gtable

plot_grid(g.iris, g.mpg, labels = "AUTO", ncol = 1)
Comments