Home > Back-end >  Neatly place 2 legends together in ggplot2
Neatly place 2 legends together in ggplot2

Time:11-11

I am trying to get my ggplot2 legends to sit together well.

I have a fill legend and a colour legend and I want them to be over multiple rows at the base of the plot but with the colour legend continuing directly after the fill legend, rather than starting a new column.

I've made a quick example and desired output (just made in paint) below to illustrate

  library(ggplot2)
set.seed(1)
testdf <- data.frame(mon = factor(month.abb, levels = month.abb), y = rnorm(84,mean = 20, sd = 10), cat = rep(paste0("class ",letters[1:7]), each =  12))

thresholds <- data.frame(ThresholdNm = c("low","high"), ThresholdVal = c(110,150))

ggplot(testdf, aes(x = mon, y = y, fill = cat)) 
  geom_bar(stat = "identity") 
  geom_hline(data = thresholds, aes(yintercept = ThresholdVal, colour = ThresholdNm)) 
  scale_colour_manual(values = c("red","black")) 
  theme(legend.position = "bottom", legend.title = element_blank()) 
  guides(fill = guide_legend(nrow=3,byrow=FALSE,order = 1),colour = guide_legend(nrow=2,byrow=FALSE,order = 2))

This is what I get:

But what I am hoping for is this:

enter image description here

Created on 2022-11-10 by the reprex package (v0.3.0)

CodePudding user response:

Adapting my answer on this post to your case you could achieve your desired result using a custom key glyph like so:

  1. Basically this involves mapping ThresholdVal on the fill aes in geom_hline. Doing so will add the items to the fill legend too.
  2. Create a color palette which could be used for both the fill and the color scale and which takes care of the right order of the items.
  3. Write custom key glyph function which conditional on the color value switches between the key glyph used for bars and the one used for geom_hline
  4. Remove the color legend.
  5. Use theme options to get a border around all legend keys including the ones for the hlines.
library(ggplot2)

nclass <- nlevels(factor(testdf$cat))
pal <- c(scales::hue_pal()(nclass), "red", "black")
names(pal) <- c(levels(factor(testdf$cat)), "high", "low")

draw_key_cust <- function(data, params, size) {
  if (data$fill %in% c("red", "black")) {
    data$colour <- data$fill
    data$fill <- NA
    draw_key_path(data, params, size)
  } else {
    GeomCol$draw_key(data, params, size)
  }
}

ggplot(testdf, aes(x = mon, y = y, fill = cat))  
  geom_bar(stat = "identity", key_glyph = "cust")  
  geom_hline(data = thresholds, aes(yintercept = ThresholdVal, colour = ThresholdNm, fill = ThresholdNm))  
  scale_fill_manual(values = pal, aesthetics = c("fill", "color"))  
  theme(legend.position = "bottom", legend.title = element_blank(), 
        legend.key = element_rect(linewidth = .25 * .pt, color = "white"))  
  guides(fill = guide_legend(nrow = 3, byrow = FALSE, order = 1), colour = "none")
#> Warning in geom_hline(data = thresholds, aes(yintercept = ThresholdVal, :
#> Ignoring unknown aesthetics: fill

  • Related