使用ggplot2绘制渐变填充小提琴图

4
我希望能够根据箱体中数据点的密度渐变填充小提琴图(蓝色代表最高密度,红色代表最低),同时保留以下命令生成的绘图。但是我尝试了一些方法未能根据密度进行着色(在本例中是小提琴的宽度)。我也希望生成类似着色的箱线图。
library("ggplot2")
data(diamonds)

ggplot(diamonds, aes(x=cut,y=carat)) + geom_violin() 

你能展示一张期望输出的图片(绘图)吗?为什么需要颜色;难道小提琴的宽度不已经暗示了密度吗? - Heroka
嗨Heroka,我的最终目标实际上是根据另一个参数上色小提琴图(或箱形图,在我的情况下由于空间限制我更喜欢箱形图)。因此,我想展示让我们说克拉数的分布如何影响另一个变量;让我们说是丰度。例如,如果高克拉钻石很少见(只是一个假设),那么宽度较大的小提琴图区域应该更蓝色,而窄区域则应更红色。 - user2438149
对于钻石数据集,是否可以使用价格变量填充切割与克拉小提琴图以展示克拉和价格之间的关系。谢谢! - user2438149
ggplot不支持使用渐变填充单个图形对象。虽然可以将每个箱线图的实心颜色与某些变量相关联,但无法在单个箱线图内创建渐变。可能有一些“绕过”限制并绘制类似于具有渐变填充的箱线图的方法,但这将非常复杂,并且违背了使用ggplot简化操作的初衷。 - jdobres
这个回答解决了你的问题吗?如何在ggplot中基于Y轴分配颜色比例尺 - tjebo
2个回答

2
要改变小提琴图的颜色,您可以使用 fill = variable,如下所示:

要更改小提琴图的颜色,使用 fill = 变量,像这样:

ggplot(diamonds, aes(x=cut,y=carat)) + geom_violin(aes(fill=cut)) 

同样适用于箱线图。
ggplot(diamonds, aes(x=cut,y=carat)) + geom_boxplot(aes(fill=cut)) 

enter image description here

但是,无论您选择什么值作为颜色变量,每个切割的值都必须相同。也就是说,如果您想使用平均深度/切割作为颜色变量,您需要对其进行编码。

使用dplyr将钻石按切割分组,并使用summarize获得平均深度(或任何其他变量)。

library(dplyr)
diamonds_group <- group_by(diamonds, cut)
diamonds_group <- summarize(diamonds_group, Mean_Price = mean(price))

然后我使用diamonds2作为diamonds的副本来操纵数据集。
diamonds2 <- diamonds

我将合并两个数据框以获取Mean_Depth变量,并将其应用于diamonds2。
diamonds2 <- merge(diamonds2, diamonds_group)

现在我可以使用平均深度作为颜色变量来绘制它。

ggplot(diamonds2, aes(x=cut,y=carat)) + geom_boxplot(aes(fill=Mean_Price)) + scale_fill_gradient2(midpoint = mean(diamonds2$price))

enter image description here


嗨 Derek,非常感谢!我在想是否可以根据价格分别对每个框进行渐变填充(高价为蓝色;低价为红色,均价为白色)。 - user2438149
@user2438149 我编辑了答案,希望这就是你要找的。 - Derek Corcoran
我的意思是根据每个方框的价格值分别进行渐变填充;因此,5个方框中的每一个都会使用渐变(每个方框都将使用蓝色和红色)。谢谢! - user2438149
五个方框应该更像是图例。因此,每个方框都必须计算平均价格五次,然后单独对每个方框进行渐变填充。这样分析将不涉及显示不同切割之间的关系,只需要单独考虑每个切割,并展示克拉和价格之间的关系。鉴于高克拉钻石通常更昂贵,所以每个方框的上端将会更加蓝色,下部则为红色。很抱歉没有让它更清晰明了。非常感谢! - user2438149
1
@user2438149,我认为你不能这样做。不过,我有一个替代方案,请尝试一下,看看你是否喜欢它:ggplot(diamonds2, aes(x=cut,y=carat)) + geom_jitter(aes(color = price)) + scale_colour_gradient2(midpoint = mean(diamonds2$price)) - Derek Corcoran
很高兴知道这个。非常感谢! - user2438149

1

刚刚回答了另一个帖子,但认为这可能更适合这个帖子。您可以通过绘制许多线段来创建伪填充。您可以直接从ggplot_built对象的底层数据中获取这些数据。

如果您想要额外的多边形轮廓(“边框”),则需要从x / y坐标创建此轮廓。以下是一种选项。

library(tidyverse)

p <- ggplot(diamonds, aes(x=cut,y=carat)) + geom_violin() 

mywidth <- .35 # bit of trial and error

# all you need for the gradient fill 
vl_fill <- data.frame(ggplot_build(p)$data) %>%
  mutate(xnew = x- mywidth*violinwidth, xend = x+ mywidth*violinwidth) 

# the outline is a bit more convoluted, as the order matters
vl_poly <- vl_fill %>%
  select(xnew, xend, y, group) %>%
  pivot_longer(-c(y, group), names_to = "oldx", values_to = "x") %>% 
  arrange(y) %>%
  split(., .$oldx) %>%
  map(., function(x) {
    if(all(x$oldx == "xnew")) x <- arrange(x, desc(y))
    x
    }) %>%
  bind_rows()

ggplot() +
  geom_polygon(data = vl_poly, aes(x, y, group = group), 
               color= "black", size = 1, fill = NA) +  
  geom_segment(data = vl_fill, aes(x = xnew, xend = xend, y = y, yend = y,
                                   color = violinwidth))  

2021-04-14由reprex package (v1.0.0)创建


这个有没有更新?不知道有没有更简单的方法来用渐变填充小提琴,以实现更容易或更集成的密度效果。 - undefined
@CyG 据我所知,没有。如果你找到了更简单的解决方案,请随意添加答案! - undefined

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