简体   繁体   中英

Nested legend based on colour and shape

I want to make an xy plot of nested groups (Group and Subgroup) where points are colored by Group and have shape by Subgroup. A minimal example is below:

DATA<-data.frame(
  Group=c(rep("group1",10),rep("group2",10),rep("group3",10) ),
  Subgroup = c(rep(c("1.1","1.2"),5), rep(c("2.1","2.2"),5), rep(c("3.1","3.2"),5)),
  x=c(rnorm(10, mean=5),rnorm(10, mean=10),rnorm(10, mean=15)),
  y=c(rnorm(10, mean=3),rnorm(10, mean=4),rnorm(10, mean=5))
)
ggplot(DATA, aes(x=x, y=y,colour=Group, shape=Subgroup) ) +
  geom_point(size=3) 

One option to achieve your desired result would be via the ggnewscale package which allows for multiple scales and legends for the same aesthetic.

To this end we have to

  1. split the data by GROUP and plot each GROUP via a separate geom_point layer.
  2. Additionally each GROUP gets a separate shape scale and legend which via achieve via ggnewscale::new_scale .
  3. Instead of making use of the color aesthetic we set the color for each group as an argument for which I make use of a named vector of colors
  4. Instead of copying and pasting the code for each group I make use of purrr::imap to loop over the splitted dataset and add the layers dynamically.

One more note: In general the order of legends is by default set via a "magic algorithm". To get the groups in the right order we have to explicitly set the order via guide_legend .

library(ggplot2)
library(ggnewscale)
library(dplyr)
library(purrr)
library(tibble)

DATA_split <- split(DATA, DATA$Group)

# Vector of colors and shapes
colors <- setNames(scales::hue_pal()(length(DATA_split)), names(DATA_split))
shapes <- setNames(scales::shape_pal()(length(unique(DATA$Shape))), unique(DATA$Shape))

ggplot(mapping = aes(x = x, y = y)) +
  purrr::imap(DATA_split, function(x, y) {
    # Get Labels
    labels <- x[c("Shape", "Subgroup")] %>% 
      distinct(Shape, Subgroup) %>% 
      deframe()
    # Get order
    order <- as.numeric(gsub("^.*?(\\d+)$", "\\1", y))
    list(
      geom_point(data = x, aes(shape = Shape), color = colors[[y]], size = 3),
      scale_shape_manual(values = shapes, labels = labels, name = y, guide = guide_legend(order = order)),
      new_scale("shape")
    )
  })

DATA

set.seed(123)

DATA <- data.frame(
  Group = c(rep("group1", 10), rep("group2", 10), rep("group3", 10)),
  Subgroup = c(rep(c("1.1", "1.2"), 5), rep(c("2.1", "2.2"), 5), rep(c("3.1", "3.2"), 5)),
  Shape = as.character(c(rep(c(1, 2), 15))),
  x = c(rnorm(10, mean = 5), rnorm(10, mean = 10), rnorm(10, mean = 15)),
  y = c(rnorm(10, mean = 3), rnorm(10, mean = 4), rnorm(10, mean = 5))
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM