'Facet title alignment using facet_wrap() in ggplot2?

I'm making a plot involving facets, and I am trying to fix the alignment of the facet/strip title. Right now it seems to left align to the panel, which places it over the gap between the base of the column and the axis tick. I'd ideally have it align it with the base of the graph, or completely left align and move the base of the column closer to the y-axis label. Reprex below.

library(tidyverse)

tibble(ToothGrowth) %>% 
  mutate(dose = as_factor(dose),
         supp = as_factor(supp)) %>% 
  group_by(supp, dose) %>% 
  summarise(x = median(len)) %>% 
  ggplot(aes(y = supp, x = x)) +
  geom_col(fill = "grey55") +
  facet_wrap(~dose, ncol = 1) +
  labs(title = "Growing Teeth are less interesting than Irises") +
  theme_minimal() +
  theme(strip.placement = "inside",
        strip.text = element_text(hjust = 0),
        strip.background = element_blank(),
        panel.background = element_rect(fill = "grey95",
                                        color = NA))

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



Solution 1:[1]

Here's an alternative to @teunbrand using expand = c(0,0) and a bit of nudging with hjust = -0.01:

plot.data <- tibble(ToothGrowth) %>% 
  mutate(dose = as_factor(dose),
         supp = as_factor(supp)) %>% 
  group_by(supp, dose) %>% 
  summarise(x = median(len)) %>%
ggplot(aes(y = supp, x = x)) +
  geom_col(fill = "grey55") +
  scale_x_continuous(expand = c(0, 0)) +
  facet_wrap(~dose, ncol = 1) +
  labs(title = "Growing Teeth are less interesting than Irises") +
  theme_minimal() +
  theme(strip.text.x = element_text(hjust = -0.01),
        panel.background = element_rect(fill = "grey95",
                                        color = NA))

enter image description here

Solution 2:[2]

Is this what you are looking for?

Essentially we put the facet strips on the left of the panels, and setup the (undocumented) theme element strip.text.y.left.

I could image you'd also want to have the strip text beyond the y-axis title even, but I'm afraid that is not possible without delving into the grid/gtables of the graph.

library(tidyverse)

tibble(ToothGrowth) %>% 
  mutate(dose = as_factor(dose),
         supp = as_factor(supp)) %>% 
  group_by(supp, dose) %>% 
  summarise(x = median(len)) %>% 
  ggplot(aes(y = supp, x = x)) +
  geom_col(fill = "grey55") +
  facet_wrap(~dose, ncol = 1, strip.position = "left") +
  labs(title = "Growing Teeth are less interesting than Irises") +
  theme_minimal() +
  theme(strip.placement = "outside",
        strip.text.y.left = element_text(angle = 0, vjust = 1),
        strip.background = element_blank(),
        panel.background = element_rect(fill = "grey95",
                                        color = NA))

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

Solution 3:[3]

A better option for this is to set hjust=0, margin=margin(l=0):

plot.data <- tibble(ToothGrowth) %>% 
    mutate(dose = forcats::as_factor(dose),
           supp = forcats::as_factor(supp)) %>% 
    group_by(supp, dose) %>% 
    summarise(x = median(len)) %>%
    ggplot(aes(y = supp, x = x)) +
    geom_col(fill = "grey55") +
    scale_x_continuous(expand = c(0, 0)) +
    facet_wrap(~dose, ncol = 1) +
    labs(title = "Growing Teeth are less interesting than Irises") +
    theme_minimal() +
    theme(strip.text.x = element_text(hjust = 0, margin=margin(l=0)),
          panel.background = element_rect(fill = "grey95",
                                          color = NA))

enter image description here

The reason is that hjust is a percentage of the plot area while the offset you are compensating for is the margin which is in absolute units (pts I think). Because of this, the hjust offset needed is specific to the plot width. If you drag the figure wider or narrower, the location of the strip text will 'move' with relation to the bars when using hjust while it will be consistent when using 'margin'.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ian Campbell
Solution 2 teunbrand
Solution 3 Gabe