ggplot:如何为一个因素分配颜色和形状,以及为另一个因素分配形状?

ggplot: how to assign both color and shape for one factor, and also shape for another factor?

我必须用 colorshape 编码因子 age。我知道该怎么做(请参阅下面的情节和 data/code)。

此外,我还必须用 shape 编码因子 day

是否有可能将指定的不同形状分配给两个不同的因素?

下面是我想要实现的传说(我在 power point 中做了一个例子)。 情节不太正确,因为只有年龄因素用颜色和形状编码。

df = data.frame(test = c(1,2,3, 1,2,3, 1,2,3,  1,2,3, 1,2,3, 1,2,3),
                age = c(1,1,1, 2,2,2, 3,3,3,   1,1,1, 2,2,2, 3,3,3),
                day = c(1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2),
                result = c(1,2,2,1,1,2,2,1,0, 2,2,0,1,2,1,2,1,0))

df$test <- factor((df$test))
df$age <- factor((df$age))
df$day <- factor((df$day))

windows(width=4, height=3 )

df %>%
  ggplot( aes(x=test, y=result)) +
  geom_point(aes(color=age, shape=age, group=age), 
             position=position_jitterdodge(dodge.width=0.8,jitter.height=0.2, jitter.width=0), 
             size=2, stroke=0.8)  +
  scale_shape_manual(values=c(16, 15, 17), name="", labels=c("young","older","the oldest")) +
  scale_color_manual(name="", labels=c("young","older","the oldest"), values=c('#009E73','#56B4E9','#D55E00')) +
  
  theme_bw()+
  theme(panel.border = element_blank(), axis.ticks = element_blank(),
        legend.position=c(), legend.text=element_text(size=10, face="bold"), legend.title=element_text(size=10),
        panel.grid.major.x = element_blank() ,
        panel.grid.major.y = element_blank() ,
        plot.title = element_text(size=10, face = "bold"), axis.title=element_text(size=11),
        axis.text.y = element_text(size=9, angle = 45), 
        axis.text.x = element_text(size=9, angle = 90),
        plot.margin = unit(c(0.5,0.2,0,0), "cm")) +
  
  labs(title= "", x = "",y = "Test result") +
  scale_y_continuous(breaks=c(0,1,2), labels=c('good','better','the best')) +
  geom_vline(xintercept=c(0.5,1.5,2.5),color="grey90")+
  geom_hline(yintercept=-0.5, color="grey90")+
  expand_limits(x=3.9, y=c(0,2.35)) +
  scale_x_discrete(limits = c("1", "2", "3"),labels = c("test a", "test b", "test c")) + 
  coord_cartesian(clip = "off") 

所以再次如下:Filled and hollow shapes where the fill color = the line color下面的代码提供了商品,但没有给你图例。

df %>%
  ggplot( aes(x=test, y=result)) +
  geom_point(aes(color=age, 
                 shape=age, 
                 group=age,
                 fill=factor(ifelse(day==1, NA, age))), # STEP 1
             position=position_jitterdodge(dodge.width=0.8,jitter.height=0.2, jitter.width=0), 
             size=2, stroke=0.8)  +
  scale_shape_manual(values=c(22,21,24), name="", labels=c("young","older","the oldest")) +
  scale_color_manual(name="", labels=c("young","older","the oldest"), values=c('#009E73','#56B4E9','#D55E00')) +
  scale_fill_manual(name="",
                      labels=c("young","older","the oldest"), 
                      values=c('#009E73','#56B4E9','#D55E00'), 
                      na.value=NA, guide="none") # STEP 2

我的评论误导了我,我们想要形状 21 到 26,而不是“空心”形状。这些显然接受不同的 fillcolor

您可以在年龄和日期之间的交互中使用形状,并且只在一个年龄使用颜色。然后删除颜色图例并使用 override.aes.

手动为形状图例着色

这接近您想要的 - 标签可以更改,我在创建因子时定义了它们。

如何制作精美的图例

但是,您想要一个非常奇特的图例,所以最简单的方法是自己将图例构建为一个单独的图例,然后合并到主面板中。 (《假传说》)。这需要一些 semi-hardcoding,但考虑到形状的手动定义,您并不羞于这样做。请参阅第二部分如何执行此操作。

第一部分

library(ggplot2)
df = data.frame(test = c(1,2,3, 1,2,3, 1,2,3,  1,2,3, 1,2,3, 1,2,3),
                age = c(1,1,1, 2,2,2, 3,3,3,   1,1,1, 2,2,2, 3,3,3),
                day = c(1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2),
                result = c(1,2,2,1,1,2,2,1,0, 2,2,0,1,2,1,2,1,0))

df$test <- factor(df$test)
## note I'm changing this here already!! If you udnergo the effor tof changing to
## factor, define levels and labels here
df$age <- factor(df$age, labels = c("young", "older", "the oldest"))
df$day <- factor(df$day, labels = paste("Day", 1:2))

ggplot(df, aes(x=test, y=result)) +
  geom_jitter(aes(color=age, shape=interaction(day, age)),
              width = .1, height = .1) +
  ## you won't get around manually defining the shapes
  scale_shape_manual(values = c(0, 15, 1, 16, 2, 17)) +
  scale_color_manual(values = c('#009E73','#56B4E9','#D55E00')) +
  guides(color = "none", 
         shape = guide_legend(
          override.aes = list(color = rep(c('#009E73','#56B4E9','#D55E00'), each = 2)),
          ncol = 3))

第二部分 - 假传说

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

## df and factor creation as above !!!

p_panel <- 
ggplot(df, aes(x=test, y=result)) +
  geom_jitter(aes(color=age, shape=interaction(day, age)),
              width = .1, height = .1) +
  ## you won't get around manually defining the shapes
  scale_shape_manual(values = c(0, 15, 1, 16, 2, 17)) +
  scale_color_manual(values = c('#009E73','#56B4E9','#D55E00')) +
  ## for this solution, I'm removing the legend entirely
  theme(legend.position = "none") 

## make the data frame for the fake legend
## the y coordinates should be defined relative to the y values in your panel
y_coord <- c(.9, 1.1)
df_legend <- df %>% distinct(day, age) %>% 
  mutate(x = rep(1:3,2), y = rep(y_coord,each = 3))

## The legend plot is basically the same as the main plot, but without legend -
## because it IS the legend ... ;)
lab_size = 10*5/14
p_leg <- 
  ggplot(df_legend, aes(x=x, y=y)) +
  geom_point(aes(color=age, shape=interaction(day, age))) +
  ## I'm annotating in separate layers because it keeps it clearer (for me)
  annotate(geom = "text", x = unique(df_legend$x), y = max(y_coord)+.1, 
           size = lab_size, angle = 45, hjust = 0,
           label = c("young", "older", "the oldest")) +
  annotate(geom = "text", x = max(df_legend$x)+.2, y = y_coord, 
           label = paste("Day", 1:2), size = lab_size, hjust = 0) +
  scale_shape_manual(values = c(0, 15, 1, 16, 2, 17)) +
  scale_color_manual(values = c('#009E73','#56B4E9','#D55E00')) +
  theme_void() +
  theme(legend.position = "none",
        plot.margin = margin(r = .3,unit = "in")) +
  ## you need to turn clipping off and define the same y limits as your panel
  coord_cartesian(clip = "off", ylim = range(df$result))

## now combine them
p_panel + p_leg +
  plot_layout(widths = c(1,.2))