ggplot2facet-wrapggforce

Add space argument to facet_wrap


facet_wrap() has been recognized for not having a space = "free" argument (https://github.com/tidyverse/ggplot2/issues/2933). This can causes spacing issues on the y-axis of plots.

enter image description here

Create the above figure using the following code:

library(tidyverse)

p <-
  mtcars %>%
  rownames_to_column() %>%
  ggplot(aes(x = disp, y = rowname)) + geom_point() +
  facet_wrap(~ carb, ncol = 1, scales = "free_y")

facet_grid on the other hand has a space = "free" argument. Allowing for nice y-axis spacing.

enter image description here

Create the above figure using the following code:

p <-
  mtcars %>%
  rownames_to_column() %>%
  ggplot(aes(x = disp, y = rowname)) + geom_point() + 
  facet_grid(carb ~ ., scales = "free_y", space = "free_y")

The issue with this is that the label is on the side, not the top. I sometimes have longer facet labels and few rows in the facet. This means the facet label gets cut off.

There is a solution from the package (comment by ilarischeinin on https://github.com/tidyverse/ggplot2/issues/2933).

p <-
  mtcars %>%
  rownames_to_column() %>%
  ggplot(aes(x = disp, y = rowname)) + geom_point()

p + ggforce::facet_col(vars(carb), scales = "free_y", space = "free")

But, there are limitations leaving . For example, I ultimately want a two column figure, and this functionality does not seem possible with . Is there any way to produce the same result using facet_wrap() so that I can utilize the ncol() argument?


Solution

  • Here is a potential workaround based on https://stackoverflow.com/a/29022188/12957340 :

    library(tidyverse)
    library(gtable)
    library(grid)
    
    p1 <- mtcars %>%
      rownames_to_column() %>%
      ggplot(aes(x = disp, y = rowname)) + geom_point() +
      facet_grid(carb ~ ., scales = "free_y", space = "free_y") +
      theme(panel.spacing = unit(1, 'lines'),
            strip.text.y = element_text(angle = 0))
    
    gt <- ggplotGrob(p1)
    panels <-c(subset(gt$layout, grepl("panel", gt$layout$name), se=t:r))
    for(i in rev(panels$t-1)) {
      gt = gtable_add_rows(gt, unit(0.5, "lines"), i)
    }
    panels <-c(subset(gt$layout, grepl("panel", gt$layout$name), se=t:r))
    strips <- c(subset(gt$layout, grepl("strip-r", gt$layout$name), se=t:r))
    stripText = gtable_filter(gt, "strip-r")
    for(i in 1:length(strips$t)) {
      gt = gtable_add_grob(gt, stripText$grobs[[i]]$grobs[[1]], t=panels$t[i]-1, l=5)
    }
    gt = gt[,-6]
    for(i in panels$t) {
      gt$heights[i-1] = unit(0.8, "lines")
      gt$heights[i-2] = unit(0.2, "lines")
    }
    grid.newpage()
    grid.draw(gt)
    

    Created on 2021-12-15 by the reprex package (v2.0.1)

    It's not clear to me what you mean by "I ultimately want a two column figure", but if you can come up with an example to illustrate your 'ultimate' expected outcome I can try to adapt this approach and see if it will work or not.