4

I'm trying to understand the default behavior of ggplot2::facet_wrap(), in terms of how the panel layout is decided as the number of facets increases.

I've read the ?facet_wrap help file, and also googled this topic with limited success. In one SO post, facet_wrap() was said to "return a symmetrical matrix of plots", but I did not find anything that explained what exactly the default behavior would be.

So next I made a series of plots which had increasing numbers of facets (code shown further down).

Set of plots with increasing number of facets

The pattern in the image makes it seem like facet_wrap() tries to "make a square"...

Questions

  1. Is that correct? Does facet_wrap try to render the facet panels so in totality they are most like a square, in terms of the number of elements in the rows and columns?
  2. If not, what is it actually doing? Do graphical parameters factor in?

Code that made the plot

# load libraries
library(ggplot2)
library(ggpubr)

# plotting function
facetPlots <- function(facets, groups = 8){
   # sample data  
   df <- data.frame(Group = sample(LETTERS[1:groups], 1000, replace = T),
                    Value = sample(1:10000, 1000, replace = T),
                    Facet = factor(sample(1:facets, 1000, replace = T)))
   # get means
   df <- aggregate(list(Value = df$Value), 
                   list(Group = df$Group, Facet = df$Facet), mean)

   # plot
   p1 <- ggplot(df, aes(x= Group, y= Value, fill = Group))+
           geom_bar(stat="identity", show.legend = FALSE)+
           facet_wrap(. ~ Facet) +
           theme_bw()+
     theme(strip.text.x = element_text(size = 6, 
        margin = margin(.1, 0, .1, 0, "cm")),
       axis.text.x=element_blank(),
       axis.ticks=element_blank(),
       axis.title.x=element_blank(),
       axis.text.y=element_blank(),
       axis.title.y=element_blank(),
       plot.margin = unit(c(3,3,3,3), "pt"))
  p1

}

# apply function to list
plot_list <- lapply(c(1:25), facetPlots)
# unify into single plot
plot <- ggpubr::ggarrange(plotlist = plot_list)  
xilliam
  • 2,074
  • 2
  • 15
  • 27
  • 2
    Without looking at the ggplot code, I wouldn't be surprised if it used something like `grDevices::n2mfrow` as a default (although it seems for some plots it switches from row rather than column) – user20650 Feb 06 '20 at 23:24
  • ... perhaps https://github.com/tidyverse/ggplot2/blob/660aad2db2b3495ae0d8040915a40d247133ffc0/R/facet-wrap.r#L453 – user20650 Feb 06 '20 at 23:25

1 Answers1

3

Here is how the default number of rows and columns are calculated:

ncol <- ceiling(sqrt(n))
nrow <- ceiling(n/ncol)

Apparently, facet_wrap tends to prefer wider grids, since "most displays are roughly rectangular" (according to the documentation). Hence, the number of columns would be greater than or equal to the number of rows.

For your example:

n <- c(1:25)

ncol <- ceiling(sqrt(n))
nrow <- ceiling(n/ncol)

data.frame(n, ncol, nrow)

Here are the computed numbers of rows/cols:

#   n   ncol   nrow
#   1      1      1
#   2      2      1
#   3      2      2
#   4      2      2
#   5      3      2
#   6      3      2
#   7      3      3
#   8      3      3
#   9      3      3
#  10      4      3
#  11      4      3
#  12      4      3
#  13      4      4
#  14      4      4
#  15      4      4
#  16      4      4
#  17      5      4
#  18      5      4
#  19      5      4
#  20      5      4
#  21      5      5
#  22      5      5
#  23      5      5
#  24      5      5
#  25      5      5
Taher A. Ghaleb
  • 5,120
  • 5
  • 31
  • 44
  • As mentioned by @user20650, it could be using `grDevices::n2mfrow`. The only exception might be when n==3. It's actually 3x1 rather than 2x2 – wxxyyyzz Jul 25 '23 at 02:58