最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

r - make ggplot legend correspond to geom type - Stack Overflow

programmeradmin2浏览0评论

Let's say I need to plot two sets ("types") of data with the same units, where each type has a group a and group b. I want group (a,b) to correspond to color, but I want the type (A, B) to correspond to the geom (say, path for A and point for B). How can I build a plot like this?

library(ggplot2)
library(dplyr)

set.seed(22)

# Example data
df <- data.frame(
  x = rep(1:10, 2),
  y = c(runif(10, 1, 3), runif(10, 3, 5)),
  pVar = rep(c("A", "B"), each = 10),
  cVar = rep(c("a", "b"), 10)
) %>%
  mutate(grp = paste(pVar, cVar, sep = "_"))

Let's say I need to plot two sets ("types") of data with the same units, where each type has a group a and group b. I want group (a,b) to correspond to color, but I want the type (A, B) to correspond to the geom (say, path for A and point for B). How can I build a plot like this?

library(ggplot2)
library(dplyr)

set.seed(22)

# Example data
df <- data.frame(
  x = rep(1:10, 2),
  y = c(runif(10, 1, 3), runif(10, 3, 5)),
  pVar = rep(c("A", "B"), each = 10),
  cVar = rep(c("a", "b"), 10)
) %>%
  mutate(grp = paste(pVar, cVar, sep = "_"))
Share Improve this question asked Jan 29 at 20:19 Michael RoswellMichael Roswell 1,48215 silver badges38 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 4

I struggled with this for quite a while, and stumbled on a solution that feels pretty good. Rather than subsetting the data argument for each geom, I use the alpha aesthetic to render the off-type invisible, and then construct the appropriate legend inside scale_alpha_identity().

library(ggplot2)
library(dplyr)

set.seed(22)

# Example data
df <- data.frame(
  x = rep(1:10, 2),
  y = c(runif(10, 1, 3), runif(10, 3, 5)),
  pVar = rep(c("A", "B"), each = 10),
  cVar = rep(c("a", "b"), 10)
) %>%
  mutate(grp = paste(pVar, cVar, sep = "_"))

# set point size 
sz <- 4

# Base plot
ggplot(df, aes(x, y, group = grp)) +
  # Path for group A (cVar) with color mapping for group (cVar)
  geom_path(aes(color = cVar
                , alpha = as.numeric(pVar == "A")
                , group = grp)
            , linewidth = 1) +
  # Points for group B (pVar) with fill based on cVar
  geom_point(aes(fill = cVar
                 , alpha = as.numeric(pVar == "B")
                 , group = grp
                 )
             , shape = 21
             , size = sz
             , color = scales::alpha("white", alpha = 0)
             ) +
  
  # set up a guide for the plotting type, using the alpha scale that renders
  # outside type invisible
  scale_alpha_identity(breaks = c(0,1)
                       , labels = c("A", "B")
                       , guide = guide_legend(title = "type"
                                              
                                              , override.aes = list(
                                                linewidth = c(0.8, 0)
                                                , shape = c(15, 21)
                                                , linetype = c("solid", "blank")
                                                , fill = c(NA, "grey")
                                                , size = c(0, sz)
                                                , alpha = c(1)
                                              )
                       )
  ) +


  theme_classic()


I would also use a fake alpha scale to get the nice legend, but I would first try pivoting to make two y-variables:

library(ggplot2); library(tidyr)

df |> 
  pivot_wider(id_cols = c(x, cVar), names_from = pVar, values_from = y) |> 
  ggplot(aes(x, color = cVar)) +
  geom_path(aes(y = A, alpha = 'A')) +
  geom_point(aes(y = B, alpha = 'B')) +
  scale_alpha_discrete(range = c(1, 1))

Otherwise I still find the data subsetting easier in general:

ggplot(df, aes(x, y, color = cVar, alpha = pVar)) +
  geom_path(data = \(d) filter(d, pVar == 'A')) +
  geom_point(data = \(d) filter(d, pVar == 'B')) +
  scale_alpha_discrete(range = c(1, 1))

发布评论

评论列表(0)

  1. 暂无评论