Home > Software design >  Multiple Legends in ggplot2/ggh4x do interfere with each other
Multiple Legends in ggplot2/ggh4x do interfere with each other

Time:10-07

I have a rather complex plot that requires multiple legends that I create with ggh4x::scale_listed. Everything works fine but the second overlay barchart creates an additional legend for the fill variable.

target: IN OUT

Is there an other way to solve this than my very hacky solution to basically "hide" the unneeded legend?

Note that my actual plot is much more complex and I would like to keep the general structure, including the custom legends.

library(ggplot2)
library(ggh4x)
my_data1 <- data.frame(case = "UK",
                       target = rep(c("IN", "OUT"), 5),
                       values = 1:10,
                       step = as.character(rep(1:2, 5)),
                       label = rep(c("A", "B"), 5))

p <- ggplot()  
  geom_bar(data = my_data1,
           position = position_stack(reverse = TRUE),
           mapping = aes(x = step, 
                         y = values, 
                         fill = target,
                         my_target_scale = target),
           stat = "identity",
           na.rm = TRUE)  
  
  # overwite prior data
  geom_bar(data = data.frame(step = 1:2,
                             purpose = "TOTAL",
                             values = c(20, 40)),
           
           # do not inherit easthetics
           inherit.aes = FALSE,
           mapping = aes(x = step,
                         y = values, 
                         # doesnt work
                         # color = purpose,
                         my_total_scale = purpose),
           show.legend = TRUE,
           position = "stack", 
           stat = "identity",
           # doesnt work
           # color = "black", 
           fill = NA,
           na.rm = TRUE)  
  ggh4x::scale_listed(scalelist = list(
    scale_fill_manual(aesthetics = "my_target_scale",
                      name = "GROUP:",
                      values = c("IN" = "red",
                                 "OUT" = "green"),
                      breaks = c("IN", "OUT"),
                      labels = c("Incoming", "Outgoing")
    ),
    scale_color_manual(aesthetics = "my_total_scale",
                       name = "Label:",
                       values = c("TOTAL" = "black"), 
                       breaks = c("TOTAL"),
                       labels = c("EVErYTHING")
    )
    # very hacky "solution"
    # ,scale_color_manual(aesthetics = "fill",
    #                    name = "",
    #                    values = c("IN", "OUT"), 
    #                    breaks = c("IN"),
    #                    labels = c(""))
  ),
  replaces = c("fill", 
               "color"
               # part of the hacky solution
               # ,"fill"
  ))  
  theme_bw()  
  theme(panel.spacing = unit(.01, "lines"),
        legend.position = "bottom",
        legend.box = "horizontal")
#> Warning: Ignoring unknown aesthetics: my_target_scale
#> Warning: Ignoring unknown aesthetics: my_total_scale

Created on 2021-10-06 by the reprex package (v2.0.0)

CodePudding user response:

If I understand the question correctly, you don't want the legend that has the 'target: -in -out' bit? What about if you just omit the fill = target line in the first layer?

library(ggplot2)
library(ggh4x)
my_data1 <- data.frame(case = "UK",
                       target = rep(c("IN", "OUT"), 5),
                       values = 1:10,
                       step = as.character(rep(1:2, 5)),
                       label = rep(c("A", "B"), 5))

ggplot()  
  geom_bar(data = my_data1,
           position = position_stack(reverse = TRUE),
           mapping = aes(x = step, 
                         y = values, 
                         my_target_scale = target),
           stat = "identity",
           na.rm = TRUE)  
  
  # overwite prior data
  geom_bar(data = data.frame(step = 1:2,
                             purpose = "TOTAL",
                             values = c(20, 40)),
           
           # do not inherit easthetics
           inherit.aes = FALSE,
           mapping = aes(x = step,
                         y = values, 
                         my_total_scale = purpose),
           show.legend = TRUE,
           position = "stack", 
           stat = "identity",
           fill = NA,
           na.rm = TRUE)  
  ggh4x::scale_listed(scalelist = list(
    scale_fill_manual(aesthetics = "my_target_scale",
                      name = "GROUP:",
                      values = c("IN" = "red",
                                 "OUT" = "green"),
                      breaks = c("IN", "OUT"),
                      labels = c("Incoming", "Outgoing")
    ),
    scale_color_manual(aesthetics = "my_total_scale",
                       name = "Label:",
                       values = c("TOTAL" = "black"), 
                       breaks = c("TOTAL"),
                       labels = c("EVErYTHING")
    )
  ),
  replaces = c("fill", 
               "color"
  ))  
  theme_bw()  
  theme(panel.spacing = unit(.01, "lines"),
        legend.position = "bottom",
        legend.box = "horizontal")
#> Warning: Ignoring unknown aesthetics: my_target_scale
#> Warning: Ignoring unknown aesthetics: my_total_scale

Created on 2021-10-07 by the reprex package (v2.0.0)

  • Related