Search code examples
rggplot2legendbackground-color

Assign different background color for each legend in ggplot2


This page shows how to manipulate the multiple legends of a ggplot such as order, color of title using the guide_legend function. I wonder if it is possible to modify the background color of each legend individually. Thanks!

ggplot(mpg, aes(displ, cty)) +
  # I tired to use legend.background and a list of colors in fill to individually change the color, but is it not working
  theme(legend.background=element_rect(fill=c('brown','grey','whie'))) +
  geom_point(aes(size = hwy, colour = cyl, shape = drv)) +
  guides(
    colour = guide_colourbar(order = 1),
    # title.theme allows individual adjustment of title color, I wonder if similar can be done for legend background color
    shape = guide_legend(order = 2,title.theme = element_text(color='green')),
    size = guide_legend(order = 3,label.theme=element_text(color='red'))
  )

Solution

  • I don't think there's a way to send multiple colors to legend.background. If this is really important to you, then you probably need to hack the grobs in the final plot. Here's a little function that can do it without using any external packages:

    recolor_legends <- function(gg_plot, col)
    {
      p2      <- ggplotGrob(gg_plot)
      grobs   <- p2$grobs[which(p2$layout$name == "guide-box")][[1]]$grobs
      legends <- grobs[sapply(grobs, function(x) any(grepl("grobs", names(x))))]
      bgs     <- lapply(legends, function(x) {
        x$grobs[x$layout$name == "background"][[1]]
      })
      bgs <- mapply(function(x, y) {x$gp$fill <- y; x}, bgs, col, SIMPLIFY = FALSE)
      legends <- mapply(function(x, y){
        x$grobs[x$layout$name == "background"][[1]] <- y; x
      }, legends, bgs, SIMPLIFY = FALSE)
      grobs[sapply(grobs, function(x) any(grepl("grobs", names(x))))] <- legends
      p2$grobs[which(p2$layout$name == "guide-box")][[1]]$grobs <- grobs
      plot(p2)
    }
    

    So suppose I have the following plot:

    p <- ggplot(mpg, aes(displ, cty)) +
      geom_point(aes(size = hwy, colour = cyl, shape = drv)) +
      guides(
        colour = guide_colourbar(order = 1),
        shape = guide_legend(order = 2,
        title.theme = element_text(color = 'green')),
        size = guide_legend(order = 3, label.theme = element_text(color = 'red'))
      )
    
    p
    

    enter image description here

    I can just do

    recolor_legends(p, c("red", "blue", "green"))
    

    enter image description here