如何在ggplot2的geom_density中按关键值设置不同填充颜色
如何在ggplot2的geom_density中按关键值设置不同填充颜色
嗨,我完全懂你遇到的困扰——用geom_histogram能轻松按临界值给不同区间上色,但换成geom_density要么变成两条分开的曲线,要么加了group=1后填充直接失效,对吧?咱们来一步步解决这个问题!
首先得搞清楚问题出在哪:当你把fill映射到treat_b > CRIT[[2]] | treat_b < CRIT[[1]]这个逻辑变量时,ggplot默认会把这个变量当成分组依据,所以直接生成了两条独立的密度曲线(一条对应“显著”的数值,一条对应“不显著”的),这可不是你想要的单条曲线分区填充效果。而加group=1虽然能强制把所有数据归为一组,但又会让填充的逻辑映射彻底失效,自然看不到分区上色了。
下面给你两种可行的解决方案:
方法一:用stat_density结合after_stat()直接在ggplot中处理
这种方法不用额外预处理数据,直接在图层里用after_stat()访问密度计算后的x值,判断是否在临界区间外,然后实现分区填充:
library(tidyverse) set.seed(42) P <- .65 K <- 1e3 SIMS <- 4e3 df <- tibble( recipe_a = rbinom(SIMS, K, P) / K, recipe_b = rbinom(SIMS, K, P) / K, treat_a = recipe_a-recipe_b, treat_b = recipe_b-recipe_a ) CRIT <- quantile(df$treat_b, c(.025, .975)) # 核心代码 df |> ggplot(aes(x = treat_b)) + stat_density( aes(fill = after_stat(x < CRIT[[1]] | x > CRIT[[2]])), geom = "area", # 用area geom来生成填充区域 alpha = 0.7, # 调整透明度让颜色更柔和 bins = 50 ) + labs(fill = "Stat Sig")
这里的关键是after_stat(x)——它能让我们访问到stat_density计算出来的密度曲线的x坐标值,这样就能针对每个x点判断是否落在临界区间外,进而给对应区域填充不同颜色,同时保证是单条密度曲线的分区效果。
方法二:先手动计算密度数据,再用geom_area填充
如果你想更灵活地控制密度数据(比如查看中间计算结果),可以先手动算出密度数据,再用geom_area实现分区填充:
# 第一步:计算treat_b的密度数据并整理成数据框 density_data <- df |> pull(treat_b) |> density(n = 512) |> # n控制密度曲线的平滑度,数值越高越平滑 as_tibble() |> mutate( stat_sig = x < CRIT[[1]] | x > CRIT[[2]] # 添加判断是否显著的列 ) # 第二步:用geom_area画图 density_data |> ggplot(aes(x = x, y = density, fill = stat_sig)) + geom_area(alpha = 0.7) + labs(x = "treat_b", fill = "Stat Sig")
这种方法的好处是你可以清晰看到密度计算的中间数据,方便后续调整或添加其他自定义逻辑。
两种方法都能实现你想要的“单条密度曲线按临界值分区填充”的效果,选哪种看你的需求就好~
备注:内容来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

