5

I'm looking to assign a custom width to each row of a one column, facet-wrapped plot in R. (I know this is entirely non-standard.)

With grid.arrange I can assign a unique height to each row of a facet-wrapped like plot with the following snippet:

group1 <- seq(1, 10, 2)
group2 <-  seq(1, 20, 3)
x = c(group1, group2)
mydf <- data.frame (X =x , Y = rnorm (length (x),5,1), 
                    groups = c(rep(1, length (group1)), rep(2, length(group2))))

plot1 <- ggplot(mydf, aes(X, Y)) + geom_point()
plot2 <- ggplot(mydf, aes(X, Y)) + geom_point()

grid.arrange(plot1, plot2, heights=c(1,2))

The code above gives each row of the plot a unique height:

enter image description here

I'm wondering if it's possible to assign a unique width to each row of the plot, rather than assign a unique height to each row. Is that even possible with any ggplot2 extension?

Community
  • 1
  • 1
duhaime
  • 25,611
  • 17
  • 169
  • 224
  • 1
    What are you planning to do with the widths? Do you want to add more plots on each row or is it for visual purposes? One idea might be to add margins to each plot. Something like: `plot1 <- ggplot(mydf, aes(X, Y)) + geom_point() +theme( plot.margin = unit(c(1,10,1,1), "lines"))` where the `10` in the `plot.margin` would be your right margin and could be thought of as your width. – Mike H. Jun 15 '16 at 14:32
  • Thanks @MikeyMike essentially the goal is to have the x-axes of each facet have n units, where n is the number of observations for that facet. Each unit should be represented by a consistent amount of space, so facets that visualize more observations should have physically longer x-axes. The margin trick may work if I set each facet's width as a function of its length relative to the max length! I'm going to try this... – duhaime Jun 15 '16 at 14:41
  • @MikeyMike Do you know where one can find documentation on the available units for `plot.margin`? I'm praying there's something along the lines of percent, but fear there won't be. – duhaime Jun 15 '16 at 14:49
  • In terms of documentation on `plot.margin` unfortunately I don't know off the top of my head. But, if you check out `?grid::unit` you can see the unit documentation. This shows you that you can use the `npc` unit to set the width as a function of the page width. So `npc = 0.5` means that the width will be `0.5` the page width. Is this what you're looking for? – Mike H. Jun 15 '16 at 14:55
  • 1
    I believe something like this would work: `plot1 <- ggplot(mydf, aes(X, Y)) + geom_point() +theme( plot.margin = unit(c(0.01,0.5,0.01,0.01), "npc"))` where the `0.5` roughly equates to your percent. – Mike H. Jun 15 '16 at 14:55
  • YES! `npc` is exactly what I was searching for (I should have grepped with ?). If you mark your last comment as an answer I'll enthusiastically accept! – duhaime Jun 15 '16 at 15:01
  • Glad to help out! I've uploaded a slightly more detailed discussion as my answer. – Mike H. Jun 15 '16 at 15:09
  • maybe relevant http://stackoverflow.com/a/32583612/471093 – baptiste Jun 15 '16 at 21:52

2 Answers2

2

Yes this is possible if you use the plot.margin functionality in the ggplot theme(). You can set each plot width as a percent of the total length of the page by doing:

plot1 <- ggplot(mydf, aes(X, Y)) + geom_point()+theme( plot.margin = unit(c(0.01,0.5,0.01,0.01), "npc"))
plot2 <- ggplot(mydf, aes(X, Y)) + geom_point()+theme( plot.margin = unit(c(0.01,0.2,0.01,0.01), "npc"))

When we use npcs as our unit of interest in the plot.margin call, we are setting relative to the page width. The 0.5 and 0.2 correspond to the right margin. As npc increases, the smaller your plot will get.

grid.arrange(plot1, plot2, heights=c(1,2))

enter image description here

Mike H.
  • 13,960
  • 2
  • 29
  • 39
2

As another option, you can use nullGrob (a blank grob that just takes up space) to allocate horizontal space in a given row. For example:

library(gridExtra)
library(grid)

plot1 <- ggplot(mydf, aes(X, Y)) + geom_point()
plot2 <- ggplot(mydf, aes(X, Y)) + geom_point()

grid.arrange(arrangeGrob(plot1, nullGrob(), widths=c(1,1)), 
             plot2, heights=c(1,2))

enter image description here

eipi10
  • 91,525
  • 24
  • 209
  • 285