R ggplot facet label position between y axis title and y axis tick mark labels

Viewed 495

I would like to put the facet labels on the left side all the way to the left so that the y-axis title is to the right of it. I can already create a suitable spacing, but I can't swap the order.

library(ggplot2)
library(tibble)
tg <- ToothGrowth %>%
  as_tibble()

tg %>%
  ggplot(aes(supp, len)) +
  geom_boxplot(aes(fill = supp)) +
  theme(strip.placement = "outside",
        strip.switch.pad.grid = unit(1, "cm")) +
  facet_grid(dose ~ ., switch = "y")

enter image description here

This order is important because I am putting this figure together with two others to have a more consistent layout. Thanks!!

EDIT: The best solution for me was the second link in aosmith's comment.

Here is the code:

tg %>%
  ggplot(aes(supp, len)) +
  geom_boxplot(aes(fill = supp)) +
  facet_grid(dose ~ ., switch = "y") +
  theme(strip.placement = "outside",
        strip.switch.pad.grid = unit(1, "cm"),
        axis.title.y = element_text(vjust = -15))

enter image description here

The solution with the grid package also looks good, but it is complicated to continue working with it. The solution with the fake axis changes the spacing of the x-axis tick marks and "label = " does not accept expressions. Thanks to all for the great help!

1 Answers

I don't think this is possible natively in ggplot because of the way the finished gtable is laid out. The y axis label always sits to the left of the facet strips. Of course, you can render the ggplot and swap the gtable around as per the link shared by aosmith. This is probably a bit too complicated for what you want to do.

I think the simplest way to achieve the result you want is to simply draw the y axis label on to the plot once it has drawn using grid.draw.

tg %>%
  ggplot(aes(supp, len)) +
  geom_boxplot(aes(fill = supp)) +
  theme(strip.placement = "outside",
        strip.switch.pad.grid = unit(1, "cm"),) +
  labs(y = "") +
  facet_grid(dose ~ ., switch = "y") +
  theme(strip.placement = "outside") 

library(grid)

grid.draw(textGrob("len", x = unit(0.1, "npc"), y = unit(0.53, "npc"), rot = 90))

enter image description here

An alternative if you want a single ggplot object without having to draw over it is to make a fake axis title using geom_text. This will require a bit more work, but the end result is more self-contained, in that it can be passed around as an object and it can have various modifications made to it without having to always draw the label on afterwards:

tg %>%
  ggplot(aes(supp, len)) +
  geom_boxplot(aes(fill = supp)) +
  scale_y_continuous(labels = function(x) formatC(x, width = 10)) +
  theme(strip.placement = "outside",
        strip.switch.pad.grid = unit(1, "cm"),) +
  labs(y = "") +
  scale_color_manual(values = c("white", "black", "white"),
                     guide = guide_none()) +
  geom_text(aes(x = -0.5, y = 20, color = factor(dose), label = "len"),
            check_overlap = TRUE, angle = 90) +
  facet_grid(dose ~ ., switch = "y") +
  coord_cartesian(clip = "off", xlim = c(0.5, 2.5))

enter image description here

Related