Modifying panel spacing between two facets using ggh4x::facet_nested()

68 Views Asked by At

I would like to only increase the panel spacing only between two specific facets (and not other nested facets in the plot). Is there a way to do this with ggh4x or what other approach can be used?

For the example below, the goal would be to add spacing between the "group" facets (Maternal vs Paternal) but no extra spacing between the nested facets ("clusters").

library(ggh4x)
library(ggplot2)
library(viridis)

# Create dummy dataset 
Cluster <- rep(paste("Cluster", 1:6), each = 15)
group <- ifelse(Cluster == "Cluster 1", "Paternal", "Maternal")
Cytokine <- rep(c("gmcsf_a_YN", "il2_a_YN", "il5_a_YN", "il12_p70_a_YN"), times = c(3, 3, 4, 3), length.out = 90)
Analyte <- rep(c("GM-CSF", "IL-2", "IL-5", "IL-12(p70)"), times = c(3, 3, 4, 3), length.out = 90)
component <- factor(rep(c("V1", "V2", "V3", "V7"), times = 90)[1:90])
weight <- runif(90, 0, 0.5)
combined_data <- data.frame(Cluster, Cytokine, Analyte, component, weight, group)


# Custom strip with ggh4x
custom_strips <- strip_nested(
  bleed = FALSE,
  background_x = elem_list_rect(colour =  c("white","white","white","darkgrey","darkgrey","darkgrey","darkgrey","darkgrey"),
                                fill = c("white","white", "white","#440154FF","#3B528BFF","#21908CFF","#5DC863FF","#FDE725FF")),
  text_x = elem_list_text(colour = c("black", "black","white","white","white","white","white","black"),
                          face = c("bold", "bold")))

# Plot
 g <- ggplot(combined_data, aes(x = Analyte, y = component)) +
  geom_point(aes(size = abs(weight), color = weight), stroke = 0.5, color = "grey30") + 
  geom_point(aes(size = abs(weight), color = weight)) +  
  scale_color_gradient2(low = "blue", high = "red", mid = "white", midpoint = 0, limit = c(-1, 1)) +
  scale_size_continuous(range = c(0, 10)) +
  ggh4x::facet_nested(~group + Cluster, scales = "free_x", space = "free_x", nest_line = element_line(linetype = 1, size = 0.5 ,colour = "darkgrey"), strip = custom_strips) +  
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1), 
        panel.spacing.x = unit(0, "lines"), 
        panel.border = element_rect(colour = "darkgrey", fill = NA, size = 0.5)) +
  labs(color = "Weight", size = "Magnitude of Weight")
 
 g 
 

1

There are 1 best solutions below

0
stefan On

One option would be to use patchwork, i.e. create two separate plots and glue them together, which allows to add some spacing using the plot.margin:

Note: As I use the new axes="collect" the code below requires patchwork >= 1.2.0. Still, it fails to collect the x axis title.

library(ggh4x)
library(ggplot2)
library(patchwork)

custom_strips <- list(
  Maternal = strip_nested(
    bleed = FALSE,
    background_x = elem_list_rect(
      colour = c("white", "white", "darkgrey", "darkgrey", "darkgrey", "darkgrey"),
      fill = c("white", "white", "#440154FF", "#3B528BFF", "#21908CFF", "#5DC863FF")
    ),
    text_x = elem_list_text(
      colour = c("black", "white", "white", "white", "white", "white"),
      face = "bold"
    )
  ),
  Paternal = strip_nested(
    bleed = FALSE,
    background_x = elem_list_rect(
      colour = c("white", "darkgrey"),
      fill = c("white", "#FDE725FF")
    ),
    text_x = elem_list_text(
      colour = "black",
      face = "bold"
    )
  )
)

plot_fun <- function(.data, .group) {
  plot_margin <- if (.group == "Maternal") {
    theme(
      plot.margin = margin()
    )
  } else {
    theme(
      plot.margin = margin(l = 20)
    )
  }

  ggplot(.data, aes(x = Analyte, y = component)) +
    geom_point(
      aes(size = abs(weight), color = weight),
      stroke = 0.5, color = "grey30"
    ) +
    geom_point(aes(size = abs(weight), color = weight)) +
    scale_color_gradient2(
      low = "blue", high = "red", mid = "white",
      midpoint = 0, limit = c(-1, 1)
    ) +
    scale_size_continuous(range = c(0, 10), limits = limits_size) +
    ggh4x::facet_nested(~ group + Cluster,
      scales = "free_x", space = "free_x",
      nest_line = element_line(linetype = 1, size = 0.5, colour = "darkgrey"),
      strip = custom_strips[[.group]]
    ) +
    theme_minimal() +
    theme(
      axis.text.x = element_text(angle = 45, hjust = 1),
      panel.spacing.x = unit(0, "lines"),
      panel.border = element_rect(colour = "darkgrey", fill = NA, size = 0.5)
    ) +
    plot_margin +
    labs(color = "Weight", size = "Magnitude of Weight")
}

limits_size <- abs(range(combined_data$weight))

combined_data |>
  split(~group) |>
  purrr::imap(plot_fun) |>
  wrap_plots() +
  plot_layout(
    guides = "collect",
    axes = "collect",
    widths = c(5, 1)
  )

enter image description here