thomasp85 / patchwork

The Composer of ggplots
https://patchwork.data-imaginist.com
Other
2.48k stars 163 forks source link

Collecting guides from list of plots with partially matching legends #410

Open almita opened 3 days ago

almita commented 3 days ago

Here's an example:

set.seed(10)
library(dplyr)
library(purrr)
library(ggplot2)
library(patchwork)
data <- list()
for(i in 1:4){
    x <- rnorm(4)
    y <- rnorm(4)
    z <- sample(x = c("B1", "B2", "B3", "B4"), replace = TRUE)
    data[[i]] <- data.frame(x,y,z)
}

pal <- c("B1"="red", "B2"="blue", "B3"="green", "B4"="black")

names(data) <- c("A1", "A2", "A3", "A4")

plots <- map(data, ~ .x %>% ggplot(aes(x, y, colour = z))+
    geom_point() +
        scale_color_manual(values = pal)) 

wrap_plots(plots, guides = "collect")

image

So what I'd like is to be able to have just one legend with B1, B2, B3, and B4. Is that possible?

trekonom commented 2 days ago

guides="collect" will only collect legends when they are identical, which for your case can be achieved by setting the limits= to include all categories. Additionally in ggplot2 >= 3.5.0 one also has to add show.legend=TRUE to the geom display a legend key for unused levels:

set.seed(10)
library(dplyr, warn = FALSE)
library(purrr)
library(ggplot2)
library(patchwork)

data <- list()
for (i in 1:4) {
  x <- rnorm(4)
  y <- rnorm(4)
  z <- sample(x = c("B1", "B2", "B3", "B4"), replace = TRUE)
  data[[i]] <- data.frame(x, y, z)
}

pal <- c("B1" = "red", "B2" = "blue", "B3" = "green", "B4" = "black")

names(data) <- c("A1", "A2", "A3", "A4")

plots <- map(data, ~ .x %>% ggplot(aes(x, y, colour = z)) +
  geom_point(show.legend = TRUE) +
  scale_color_manual(values = pal, limits = names(pal)))

wrap_plots(plots, guides = "collect")

almita commented 2 days ago

Yeah I figured they had to be identical, thanks for your solution!! This is very helpful