'Divide Legend by multiple groups

In am looking a solution to a different representation of the legend to the example given here: https://rpubs.com/ageek/ggplot-adv-part2

The code below gives the following graph:

ggplot(mpg, aes(manufacturer))+
    geom_bar(aes(fill=class), width = 0.5)+
    theme(axis.text.x = element_text(angle=65, vjust=0.6))

Image_Example

Is there a way to represent the legend in groups for each different value of the variable x (discrete) given in x axis? For example, in the above example the legend for the first two entries in the x axis (Audi and Chevrolet) would look as following:

Image_DesiredOutcome

In the desired outcome, all entries in x axis should be included in the legend, and dynamically change in case the legend is adjusted (e.g. Audi removed or a new brand is added)



Solution 1:[1]

This is not too difficult with a mix of patchwork and cowplot. My answer is just to show the technical feasibility - I do not endorse this type of visualisation and I totally agree with Allan. To consider: You present the manufacturer/class relation already in the main plot - Your legend design would duplicate this!

library(dplyr)
library(ggplot2)
library(cowplot)
library(patchwork)

## named vector so you get the correct color mapping
class_colors <- setNames(scales::hue_pal()(length(unique(mpg$class))), sort(unique(mpg$class)))

p <-
  ggplot(mpg, aes(manufacturer)) +
  geom_bar(aes(fill = class), width = 0.5) +
  theme(
    axis.text.x = element_text(angle = 65, vjust = 0.6),
    ## remove legend
    legend.position = "none"
  ) +
  ## for better control use the same colors in the main plot
  scale_fill_manual(values = class_colors)

## split by your categorising variable and loop a plot over it
ls_man <- mpg %>%
  split(.$manufacturer)

## I'm looping over an index so I can dynamically change legend title and breaks
ls_plots <- lapply(1:length(ls_man), function(i) {
  ggplot(ls_man[[i]], aes(manufacturer)) +
    geom_bar(aes(fill = class), width = 0.5) +
    theme(axis.text.x = element_text(angle = 65, vjust = 0.6)) +
    labs(fill = names(ls_man)[i]) +
    scale_fill_manual(values = class_colors, breaks = unique(ls_man[[i]]$class))
})
## create the legends with patchwork and cowplot
p_mess <- wrap_plots(ls_plots) + plot_layout(guides = "collect")
p_leg <- get_legend(p_mess)

## draw the final plot with cowplot
ggdraw(plot_grid(p, p_leg))

The legends are all there, but it's just so messy you cannot see them because of the small size of this device.

Created on 2022-05-06 by the reprex package (v2.0.1)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1