rggplot2grob

R ggplot2: change colour of font and background in facet strip?


I am trying to customize a ggplot2 plot containing facets, and would like to change both the colour of the facet strip, as well as the colour of the font. I found some code to change the strip.background colour, but was not able to modify it to change also the font color... any idea?

What I got so far:

library(ggplot2)
library(grid)

p <- ggplot(mpg, aes(displ, cty)) + geom_point() + facet_grid(drv ~ cyl) +
  ggtitle("How to change coloour of font in facet strip?")

g <- ggplot_gtable(ggplot_build(p))
strip_both <- which(grepl('strip-', g$layout$name))
fills <- c("red","green","blue","yellow","red","green","blue","yellow")
k <- 1

for (i in strip_both) {
  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.draw(g)

Created on 2018-11-23 by the reprex package (v0.2.1)


Solution

  • Another option is using grid's editing functions, provided that we build the gPath of each grob that we want to edit.

    Prepare the gPaths:

    library(ggplot2)
    library(grid)
    
    p <- ggplot(mpg, aes(displ, cty)) + geom_point() + facet_grid(drv ~ cyl)
    
    # Generate the ggplot2 plot grob
    g <- grid.force(ggplotGrob(p))
    # Get the names of grobs and their gPaths into a data.frame structure
    grobs_df <- do.call(cbind.data.frame, grid.ls(g, print = FALSE))
    # Build optimal gPaths that will be later used to identify grobs and edit them
    grobs_df$gPath_full <- paste(grobs_df$gPath, grobs_df$name, sep = "::")
    grobs_df$gPath_full <- gsub(pattern = "layout::", 
                                replacement = "", 
                                x = grobs_df$gPath_full, 
                                fixed = TRUE)
    

    Check out the table grobs_df and get familiar with the naming and paths. For example all strips contain the key word "strip". Their background is identified by the key word "background" and their title text by "titleGrob" & "text". We can then use regular expression to catch them:

    # Get the gPaths of the strip background grobs
    strip_bg_gpath <- grobs_df$gPath_full[grepl(pattern = ".*strip\\.background.*", 
                                                x = grobs_df$gPath_full)]
    strip_bg_gpath[1] # example of a gPath for strip background 
    ## [1] "strip-t-1.7-5-7-5::strip.1-1-1-1::strip.background.x..rect.5374"
    
    # Get the gPaths of the strip titles
    strip_txt_gpath <- grobs_df$gPath_full[grepl(pattern = "strip.*titleGrob.*text.*", 
                                                 x = grobs_df$gPath_full)]
    strip_txt_gpath[1] # example of a gPath for strip title
    ## [1] "strip-t-1.7-5-7-5::strip.1-1-1-1::GRID.titleGrob.5368::GRID.text.5364"
    

    Now we can edit the grobs:

    # Generate some color
    n_cols <- length(strip_bg_gpath)
    fills <- rainbow(n_cols)
    txt_colors <- gray(0:n_cols/n_cols)
    
    # Edit the grobs
    for (i in 1:length(strip_bg_gpath)){
      g <- editGrob(grob = g, gPath = strip_bg_gpath[i], gp = gpar(fill = fills[i]))
      g <- editGrob(grob = g, gPath = strip_txt_gpath[i], gp = gpar(col = txt_colors[i]))
    }
    
    # Draw the edited plot
    grid.newpage(); grid.draw(g)
    # Save the edited plot
    ggsave("edit_strips_bg_txt.png", g)
    

    enter image description here