Home > front end >  ggplot add horizontal line to grouped categorical data and share legend
ggplot add horizontal line to grouped categorical data and share legend

Time:01-18

Here is some code that makes a categorical bar chart and places a mean line on the chart. The problem is that the legends are separate and I can't figure out how to stick them together. I think I have made a dummy variable in the past and included it in the scale_manual arguments but geom_vline doesn't handle the "fill" mappings. Any ideas?

library(tidyverse)
data(mtcars)

y = mean(mtcars$mpg)
x = unique(mtcars$cyl)
meanDf <- 
  data.frame(x, y )


mtcars$mean = y
mtcars$group = "mean"

mtcars %>%


ggplot(aes(x = factor(cyl), y = mpg, fill = factor(carb)))  
  geom_col(position = "dodge")  
  geom_hline(data = meanDf, aes(yintercept = y, color = ""))  
  scale_fill_manual(name = "", values = c("blue", "red", "green", "white", "black", "yellow"), labels = paste("myLabel", 1:6))  
  scale_color_manual(name = "", values = "red", label = "myLabel")  
  theme(panel.background = element_rect(fill = "white"))  
  theme(legend.background = element_rect(color = "black", fill = "white")) 
  
  

CodePudding user response:

I think for readability, it's better to separate them out. However, for formatting purpose, you sure can bring them as close as you want by dropping the legend.title (not just assigning it an empty string) and adjusting the legend.margin and legned.spacing. For instance,

library(tidyverse)
data(mtcars)

y = mean(mtcars$mpg)
x = unique(mtcars$cyl)
meanDf <- 
  data.frame(x, y )


mtcars$mean = y
mtcars$group = "mean"

mtcars %>%
  ggplot(aes(x = factor(cyl), y = mpg, fill = factor(carb)))  
  geom_col(position = "dodge")  
  geom_hline(data = meanDf, aes(yintercept = y, color = ""))  
  scale_fill_manual(name = "", values = c("blue", "red", "green", "white", "black", "yellow"), labels = paste("myLabel", 1:6))  
  scale_color_manual(name = "", values = "red", label = "myLabel")   
  theme(
    legend.title = element_blank(), 
    legend.margin = margin(t = 0, b = 0, r = 2, l = 2),
    legend.spacing.y = unit(.5, "pt")
  )

Output res

CodePudding user response:

One option would be to use only the fill scale and make use of custom key glyph.

  1. Set the color for the geom_hline as an argument instead of mapping on the color aes. Instead map a constant e.g. "" on the fill aes. A Drawback is that we get a warning.
  2. Add an additional color and label to scale_fill_manual.
  3. To get a line as the key glyph for the geom_hline I make use of a custom key glyph which conditionally on the fill color switches between draw_key_path and the default key glyph for geom_col. To make this work I use a "red2" as the additional fill color for the hline which I switch to "red" inside the custom key glyph function.
library(tidyverse)
data(mtcars)

y = mean(mtcars$mpg)
x = unique(mtcars$cyl)
meanDf <- data.frame(x, y )

mtcars$mean = y
mtcars$group = "mean"

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

mtcars %>%
  ggplot(aes(x = factor(cyl), y = mpg, fill = factor(carb)))  
  geom_hline(data = meanDf, aes(yintercept = y, fill = ""), color = "red")  
  geom_col(key_glyph = "cust")  
  scale_fill_manual(name = NULL, values = c("red2", "blue", "red", "green", "white", "black", "yellow"), labels = c("label", paste("myLabel", 1:6)))  
  theme(panel.background = element_rect(fill = "white"))  
  theme(legend.background = element_rect(color = "black", fill = "white"))
#> Warning: Ignoring unknown aesthetics: fill

  •  Tags:  
  • Related