75

How can I change the grey facet labels (A and B) into say red background with white text?

library(data.table)
A = data.table(x = 1:4, y = 1:4, z = c('A','A','B','B'))
ggplot(A) + geom_point(aes(x = x, y = y)) + facet_wrap(~z) + theme_bw()

enter image description here

AnilGoyal
  • 25,297
  • 4
  • 27
  • 45
jf328
  • 6,841
  • 10
  • 58
  • 82

2 Answers2

116

You can do:

ggplot(A) +
  geom_point(aes(x = x, y = y)) +
  facet_wrap(~z) +
  theme_bw()+
  theme(strip.background =element_rect(fill="red"))+
  theme(strip.text = element_text(colour = 'white'))

enter image description here

Haboryme
  • 4,611
  • 2
  • 18
  • 21
  • 7
    Is it possible to change the color of only one label? Lets say I have 5 columns and I want to highlight the center one. – Sergio Feb 08 '18 at 17:13
  • 1
    @Sergio; I haven't played with ggplot for quite a while now, as such I can't give a proper answer, sorry. I could suggest you to look into grob editing (warning : tedious), this [answer](https://stackoverflow.com/questions/6750664/how-to-change-the-format-of-an-individual-facet-wrap-panel) might give you some inspiration. There might be some easier solution. – Haboryme Feb 09 '18 at 08:59
25

For anyone else looking to change individual facet labels, there's a solution here:

g <- ggplot_gtable(ggplot_build(p))
stripr <- which(grepl('strip-r', g$layout$name))
fills <- c("red","green","blue","yellow")
k <- 1
for (i in stripr) {
  j <- which(grepl('rect', g$grobs[[i]]$grobs[[1]]$childrenOrder))
  g$grobs[[i]]$grobs[[1]]$children[[j]]$gp$fill <- fills[k]
  k <- k+1
}
grid::grid.draw(g)

enter image description here

filups21
  • 1,611
  • 1
  • 19
  • 22
  • I'm using the latest version of R and this doesn't work. I get the error `Error in `*tmp*`[[j]] : attempt to select less than one element in get1index`. Any ideas? – vashts85 Apr 25 '20 at 00:23
  • 1. I'm using R v. 3.6.1, and it looks like some of the plot components' names have changed. To recreate the same plot I changed lines 2 and 3 above to: `striprt <- which( grepl('strip-r', g$layout$name) | grepl('strip-t', g$layout$name) )` and `fills <- c("red","green","blue","yellow", "red","green","blue")` (and also changed `stripr` in line 5 to `striprt`. 2. with the recent major update to R, there may be upcoming changes to the ggplot & grid packages that will also alter things. ¯\_(ツ )_/¯ – filups21 Apr 27 '20 at 15:29
  • 2
    Is there no way to do this natively in ggplot? – Herman Toothrot Mar 30 '21 at 18:37
  • @vashts85 I get the same. It is because there is nothing in `g$grobs[[i]]$grobs[[1]]$childrenOrder)` that contains `'rect'` for `grepl` to find. – Matt Jun 16 '21 at 15:49
  • 1
    Just in case someone else needs this, for my newer version I had to change strip-r to strip-1, you might need to look at your particular plot first by first typing g$layout$name this is how I realized that my plot is with -1 – Ahdee Jul 16 '21 at 00:18
  • For those experiencing the same problem as @vashts85 and @Matt with updated packages, it seems to stem from `striprt` matching to more than the number of panels. You can simply add a line in the for loop to skip cases that aren't panels: `if(length(j) == 0) next` – TKraft Sep 08 '21 at 18:23
  • @HermanToothrot - no, it's not possible to do this natively in ggplot. In the link in my answer, Hadley Wickham says "This would require fundamental changes to ggplot2, so is unfortunately not possible." For now you're stuck with ugly work-arounds like this one. – filups21 Sep 08 '21 at 20:10
  • Anyone have an idea on how to add a legend for the strip colour? – Max J. Feb 07 '23 at 14:34