在ggplot中混合颜色和填充美学

4

我想知道是否有可能根据分类变量更改填充主颜色。

这里是一个可复制的示例:

df = data.frame(x = c(rnorm(10, mean = 0),
                  rnorm(10, mean = 3)),
            y = c(rnorm(10, mean = 0),
                  rnorm(10, mean = 3)),
            grp = c(rep('a', times = 10),
                    rep('b', times = 10)),
            val = rep(1:10, times = 2))

ggplot(data = df,
       aes(x = x,
           y = y)) +
  geom_point(pch = 21,
             aes(color = grp,
                 fill = val,
                 size = val))

这是输出结果

当然,根据变量grp,更改圆形的颜色/形状很容易,但我想让a组呈现红色渐变,b组呈现蓝色渐变。 我也考虑过使用facets,但不知道是否可以为两个面板更改填充渐变。

有人知道是否可以在不使用gridExtra的情况下完成这项工作吗?

谢谢!


你可以先尝试将第一组数据以蓝色绘制出来,然后添加一个全新的图层,例如:+geom_point(data=df[group==b],aes(...),fill=val, col="red")。大致思路是(可能不是最优解)从新数据中绘制新图形,然后将颜色设置为红色。 - Jan Sila
无法工作:col参数定义了形状的颜色,而不是主要填充主题。 - Emiliano
2个回答

3

我认为有两种方法可以做到这一点。第一种是使用alpha美学来设置你的val列。这是一种快速简便的实现目标的方法,但可能并不完全符合你的要求:

ggplot(data = df,
       aes(x = x,
           y = y)) +
  geom_point(pch = 21,
             aes(alpha=val,
                 fill = grp,
                 size = val)) + theme_minimal()

enter image description here

第二种方法是类似于这篇文章所述:如何在使用ggplot2创建的散点图中改变颜色渐变。我稍微编辑了一下代码,使其不是从白色到您感兴趣的颜色范围,而是从浅色到深色。这需要一些工作,并使用scale_fill_identity函数,该函数基本上接受一个具有所需颜色的变量,并将它们直接映射到每个点(因此不进行任何缩放)。
这段代码是:
#Rescale val to [0,1]
df$scaled_val <- rescale(df$val)
low_cols <- c("firebrick1","deepskyblue")
high_cols <- c("darkred","deepskyblue4")

df$col <- ddply(df, .(grp), function(x)
  data.frame(col=apply(colorRamp(c(low_cols[as.numeric(x$grp)[1]], high_cols[as.numeric(x$grp)[1]]))(x$scaled_val),
                       1,function(x)rgb(x[1],x[2],x[3], max=255)))
)$col
df

ggplot(data = df,
       aes(x = x,
           y = y)) +
  geom_point(pch = 21,
             aes(
                 fill = col,
                 size = val)) + theme_minimal() +scale_fill_identity()

enter image description here


前面的解决方案非常巧妙,完全符合ggplot2的风格。然而,它让我想知道如果val的范围不同会发生什么,比如当grp = a时为1-10,当grp = 50时为20-50。 当然,如果比较类似的对象,这种情况不应该发生,如果确实发生了,那么这将是正确的可视化。另一个“问题”可能是缺少图例:在这里,您使用大小作为填充(alpha)值的代理。 第二个选项中也存在同样的问题,因为使用guide ='legend'会返回列df $ col中的整个十六进制值列表。 - Emiliano
我使用 size,因为您在原始代码中使用了它。它可以很容易地被删除。关于图例,您尝试做的事情并不被 ggplot 鼓励(这就是为什么它很难做)所以如果您想要做后者,您可能需要覆盖图例美学或自己创建一个 - 无论哪种方式都非常手动化。 - Mike H.

1
感谢这篇文章,我找到了一种方法来可视化图例中的填充条,尽管那不是我本意想做的。
以下是输出结果。

enter image description here

和代码

df = data.frame(x = c(rnorm(10, mean = 0),
                      rnorm(10, mean = 3)),
                y = c(rnorm(10, mean = 0),
                      rnorm(10, mean = 3)),
                grp = factor(c(rep('a', times = 10),
                               rep('b', times = 10)),
                             levels = c('a', 'b')),
                val = rep(1:10, times = 2)) %>%
  group_by(grp) %>%
  mutate(scaledVal = rescale(val)) %>%
  ungroup %>%
  mutate(scaledValOffSet = scaledVal + 100*(as.integer(grp) - 1))

scalerange <- range(df$scaledVal)
gradientends <- scalerange + rep(c(0,100,200), each=2)

ggplot(data = df,
       aes(x = x,
           y = y)) +
  geom_point(pch = 21,
             aes(fill = scaledValOffSet,
                 size = val)) + 
  scale_fill_gradientn(colours = c('white',
                                   'darkred',
                                   'white',
                                   'deepskyblue4'),
                       values = rescale(gradientends))

基本上,应该重新缩放填充值(例如在0和1之间),并使用由分类变量grp提供的另一个数量级进行分离。但这并不是我想要的:当然,可以改进代码片段,使整个过程更少手动操作,但仍然缺乏简单常见的离散填充图例。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接