Search code examples
rggplot2facetr-grid

How to increase space among different boxes created for the facet labels using `facet_nested`?


I have a plot like this below:

library(ggplot2)
library(ggh4x) # remotes::install_github("teunbrand/ggh4x")

df1 <- data.frame(x = rep(1:12, times=4, each=1), 
                  y = rep((1:12)^2, times=4, each=1),
                  Variable1 = rep(c("A","B"), times=1, each=24),
                  Variable2 = rep(c("C","D"), times=4, each=12))


g<-ggplot(df1, aes(x=x, y=y)) + 
  geom_point(size=1.5) + 
  theme(strip.background = element_rect(colour = "black", fill = "white", 
                                        size = 1.5, linetype = "solid"),
        axis.title.x =element_text(margin = margin(t = 2, r = 20, b = 0, l = 0),size = 16),
        axis.title.y =element_text(margin = margin(t = 2, r = 20, b = 0, l = 0),size = 16),
        axis.text.x = element_text(angle = 0, hjust = 0.5,size = 14),
        axis.text.y = element_text(angle = 0, hjust = 0.5,size = 14),
        strip.text.x = element_text(size = 14),
        strip.text.y = element_text(size = 13),
        axis.line = element_line(),
        panel.grid.major= element_blank(),
        panel.grid.minor = element_blank(),
        legend.text=element_text(size=15),
        legend.title = element_text(size=15,face="bold"),
        legend.key=element_blank(),
        legend.position = "right",
        panel.border = element_blank(),
        strip.placement = "outside",
        strip.switch.pad.grid = unit('0.25', "cm")) + 
  facet_nested( .~Variable1 + Variable2)

g

enter image description here

How could I increase the space among different boxes for the different facet labels? So for example, I want to increase the space between A and C/D. In this post is explained how to change the distance between the plot edge and the facet labels (using strip.switch.pad.grid in theme), but it doesn't work for separating facet boxes among them.

Does anyone know how to do it?


Solution

  • ggplot2 and ggh4x don't have options to place the facet strips apart. However, that doesn't mean it can't be done: it just means that the solution is a bit uglier than you'd like. Because you'd have to dive into the gtable/grid structures underneath ggplot.

    For completeness; this gives identical output to your code.

    library(ggplot2)
    library(ggh4x)
    library(grid)
    
    df1 <- data.frame(x = rep(1:12, times=4, each=1), 
                      y = rep((1:12)^2, times=4, each=1),
                      Variable1 = rep(c("A","B"), times=1, each=24),
                      Variable2 = rep(c("C","D"), times=4, each=12))
    
    
    
    g<-ggplot(df1, aes(x=x, y=y)) + 
      geom_point(size=1.5) + 
      theme(strip.background = element_rect(colour = "black", fill = "white", 
                                            size = 1.5, linetype = "solid"),
            axis.title.x =element_text(margin = margin(t = 2, r = 20, b = 0, l = 0),size = 16),
            axis.title.y =element_text(margin = margin(t = 2, r = 20, b = 0, l = 0),size = 16),
            axis.text.x = element_text(angle = 0, hjust = 0.5,size = 14),
            axis.text.y = element_text(angle = 0, hjust = 0.5,size = 14),
            strip.text.x = element_text(size = 14),
            strip.text.y = element_text(size = 13),
            axis.line = element_line(),
            panel.grid.major= element_blank(),
            panel.grid.minor = element_blank(),
            legend.text=element_text(size=15),
            legend.title = element_text(size=15,face="bold"),
            legend.key=element_blank(),
            legend.position = "right",
            panel.border = element_blank(),
            strip.placement = "outside",
            strip.switch.pad.grid = unit('0.25', "cm")) + 
      facet_nested( .~Variable1 + Variable2)
    

    Then here is the extra steps that you'd have to take for your plot, or any plot where the strip layout is horizontal without vertical strips. This should work for regular facet_grid() too.

    # How much to push the boxes apart
    space <- unit(0.5, "cm")
    
    # Convert to gtable
    gt <- ggplotGrob(g)
    
    # Find strip in gtable
    is_strip <- which(grepl("strip", gt$layout$name))
    strip_row <- unique(gt$layout$t[is_strip])
    
    # Change cell height
    gt$heights[strip_row] <- gt$heights[strip_row] + space
    
    # Add space to strips themselves
    gt$grobs[is_strip] <- lapply(gt$grobs[is_strip], function(strip) {
      gtable::gtable_add_row_space(strip, space)
    })
    
    # Render
    grid.newpage(); grid.draw(gt)
    

    Created on 2020-05-26 by the reprex package (v0.3.0)

    Note that this example is on R4.0.0. The grid::unit() arithmetic behaviour might be slightly different in previous R versions.

    As an aside, if you just want to add padding to the text, it is easier to just wrap newlines around the text:

    df1$Variable1 <- factor(df1$Variable1)
    levels(df1$Variable1) <- paste0("\n", levels(df1$Variable1), "\n")
    

    EDIT: It might just be easiest to use ggtext textbox elements:

    library(ggtext) # remotes::install_github("wilkelab/ggtext")
    g + theme(
      strip.background = element_blank(),
        strip.text = element_textbox_simple(
          padding = margin(5, 0, 5, 0),
          margin = margin(5, 0, 5, 0),
          size = 13,
          halign = 0.5,
          fill = "white",
          box.color = "black",
          linewidth = 1.5,
          linetype = "solid",
        )
    )
    g