15

I'm creating several facetted plots for a report. The number of facets varies between 2 and 8. Ideally, I'd like the absolute size of each facet (across plots) to be the same (e.g. 4x4 cm) so that it is easier to compare them (and it looks nicer, too).

Is that possible?

df1 <- structure(list(group1 = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L,1L, 1L, 1L, 1L, 1L), .Label = c("S1", "S2"), class = "factor"), group = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L), .Label = c("A", "B", "C", "D", "E"), class = "factor"), value = 1:12), class = "data.frame", row.names = c(NA, -12L), .Names = c("group1", "group", "value"))

df2 <- structure(list(group1 = structure(c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("S1", "S2"), class = "factor"), group = structure(c(4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L), .Label = c("A", "B", "C", "D", "E"), class = "factor"), value = 13:20), class = "data.frame", row.names = c(NA, -8L), .Names = c("group1", "group", "value"))

library(ggplot2)

plot1 <- ggplot(df1) + geom_histogram(aes(x=value)) + facet_wrap(~group)
plot2 <- ggplot(df2) + geom_histogram(aes(x=value)) + facet_wrap(~group)

enter image description here enter image description here

erc
  • 10,113
  • 11
  • 57
  • 88

1 Answers1

14

I've used the following function for this purpose,

set_panel_size <- function(p=NULL, g=ggplotGrob(p), file=NULL, 
                           margin = unit(1,"mm"),
                           width=unit(4, "cm"), 
                           height=unit(4, "cm")){

  panels <- grep("panel", g$layout$name)
  panel_index_w<- unique(g$layout$l[panels])
  panel_index_h<- unique(g$layout$t[panels])
  nw <- length(panel_index_w)
  nh <- length(panel_index_h)

if(getRversion() < "3.3.0"){

   # the following conversion is necessary
   # because there is no `[<-`.unit method
   # so promoting to unit.list allows standard list indexing
   g$widths <- grid:::unit.list(g$widths)
   g$heights <- grid:::unit.list(g$heights)

   g$widths[panel_index_w] <-  rep(list(width),  nw)
   g$heights[panel_index_h] <- rep(list(height), nh)

} else {

   g$widths[panel_index_w] <-  rep(width,  nw)
   g$heights[panel_index_h] <- rep(height, nh)

}

  if(!is.null(file))
    ggsave(file, g, 
           width = grid::convertWidth(sum(g$widths) + margin, 
                                unitTo = "in", valueOnly = TRUE),
           height = grid::convertHeight(sum(g$heights) + margin,  
                                  unitTo = "in", valueOnly = TRUE))

  g
}

g1 <- set_panel_size(plot1)
g2 <- set_panel_size(plot2)
gridExtra::grid.arrange(g1,g2)

enter image description here

jan-glx
  • 7,611
  • 2
  • 43
  • 63
baptiste
  • 75,767
  • 19
  • 198
  • 294
  • 1
    Thanks, though I still do not get how to use this function without receiving an error message. Can you expand your answer by showing how to get the desired result with my example data? – erc Sep 15 '15 at 11:43
  • I just tried this with R Devel, and this line doesn't work for me: `g$widths[panel_index_w] <- rep(list(width), nw)`. I need to use this one: `g$widths[panel_index_w] <- rep(grid:::unit.list(width), nw)`. – Claus Wilke Mar 08 '16 at 20:47
  • 1
    To reply to my earlier comment: the line `g$widths[panel_index_w] <- rep(list(width), nw)` should be replaced by `g$widths[panel_index_w] <- rep(width, nw)`. Then things work. – Claus Wilke Mar 08 '16 at 21:50
  • 1
    `set_panel_size` is also available in @baptiste 's package [egg](https://github.com/baptiste/egg). – jan-glx Nov 13 '18 at 22:09