Nested facets in ggplot2 spanning groups

ZNK picture ZNK · Oct 29, 2016 · Viewed 9.2k times · Source

I encountered a situation in which I want to create a plot that was facetted by three grouping variables. To do so, I would simply use facet_grid(f1 ~ f2 + f3), but the issue here is that the labels for f2 would be redundant, and it would be much better to have them span the facets for f3 nested within f2.

MWE:

library('tibble')
library('ggplot2')
df <- tribble(
  ~x, ~y, ~f1, ~f2, ~f3,
  0.5, 0.5, "a", "a", "a",
  0.5, 0.5, "b", "a", "a",
  0.5, 0.5, "a", "b", "a",
  0.5, 0.5, "b", "b", "a",
  0.5, 0.5, "a", "a", "b",
  0.5, 0.5, "b", "a", "b",
  0.5, 0.5, "a", "b", "b",
  0.5, 0.5, "b", "b", "b"
)


p <- ggplot(df, aes(x = x, y = y)) +
  geom_point() +
  facet_grid(f1 ~ f2 + f3)

MWE of nested facet plot

Again, I'm looking to combine the labels for f2 so that they are not so redundant.

Edit: This is different from other questions in that it asks how to use the existing groupings to modify a facet as opposed to adding a new one.

Answer

teunbrand picture teunbrand · Apr 29, 2019

I'm sorry necroing this thread and unintended self-promotion, but I had a go at generalizing this to a facet_nested() function and it can be found in the ggh4x package.

The function isn't tested extensively but I thought it might be of some convenience to people. Maybe some good feedback will come from this.

There are two other modifications that I made in this function beyond the scope of grouping strips. One is that it doesn't automatically expand missing variables. This is because I was of the opinion that nested facets should be able to co-exist with non-nested facets without any entries to the 2nd or further arguments in vars() when plotting with two data.frames. The second is that it orders the strips from outer to inner, so that inner is nearer to the panels than outer, even when switch is set.

Reproducing the plot in this question would then be as follows, assuming df is the df in the question above:

# library(ggh4x)
p <- ggplot(df, aes(x = x, y = y)) +
  geom_point() +
  facet_nested(f1 ~ f2 + f3)

enter image description here

There was also a related question with a more real-world example plot, which would work like the following, assuming df is the df from that question:

p <- ggplot(df, aes("", density)) + 
  geom_boxplot(width=0.7, position=position_dodge(0.7)) + 
  theme_bw() +
  facet_nested(. ~ species + location +  position) +
  theme(panel.spacing=unit(0,"lines"),
        strip.background=element_rect(color="grey30", fill="grey90"),
        panel.border=element_rect(color="grey90"),
        axis.ticks.x=element_blank()) +
  labs(x="")

enter image description here