r - 在 tidybayes 中自定义半眼图的透明度
问题描述
我正在使用 tidybayes 生成半眼图来说明后验图的分布,遵循此处的示例。
使用以下代码:
library(magrittr)
library(dplyr)
library(purrr)
library(forcats)
library(tidyr)
library(modelr)
library(tidybayes)
library(ggplot2)
library(ggstance)
library(ggridges)
library(cowplot)
library(rstan)
library(brms)
library(ggrepel)
library(RColorBrewer)
library(gganimate)
theme_set(theme_tidybayes() + panel_border())
rstan_options(auto_write = TRUE)
options(mc.cores = parallel::detectCores())
set.seed(5)
n = 10
n_condition = 5
ABC =
tibble(
condition = rep(c("A","B","C","D","E"), n),
response = rnorm(n * 5, c(0,1,2,1,-1), 0.5)
)
m = brm(response ~ (1|condition), data = ABC, control = list(adapt_delta = .99),
prior = c(
prior(normal(0, 1), class = Intercept),
prior(student_t(3, 0, 1), class = sd),
prior(student_t(3, 0, 1), class = sigma)
))
m %>%
spread_draws(b_Intercept, r_condition[condition,]) %>%
mutate(condition_mean = b_Intercept + r_condition) %>%
ggplot(aes(y = condition, x = condition_mean, fill = stat(x < 0))) +
stat_halfeyeh() +
geom_vline(xintercept = 0, linetype = "dashed") +
scale_fill_manual(values = c("gray80", "skyblue"))
我能够生成下图,其中每个分布的负区域为蓝色,而正区域为灰色:
我想要的最终数字应满足以下标准:
(1) 条件 A 到 E 的分布曲线下区域依次用“#009B9F”、“#5EBCBF”、“#C6DFE0”、“#E9D4E2”、“#D99BC5”着色;
(2)对于后验均值为正的分布(即条件A到D),将较大的alpha值分配给曲线下位于0线右侧的区域,并分配较低的alpha值(更透明)到曲线下位于 0 线左侧的区域;
(3) 对于后均值为负的分布(即条件 E),将较低的 alpha 值(更透明)分配给曲线下位于 0 线右侧的区域,并将较高的 alpha 值(更不透明)分配给曲线下位于 0 线左侧的区域。
我用 ggplot 函数中的 alpha 参数进行了调整,但总是失败。欢迎任何建议。
解决方案
让我们一一解决:
(1) 条件 A 到 E 的分布曲线下区域依次用“#009B9F”、“#5EBCBF”、“#C6DFE0”、“#E9D4E2”、“#D99BC5”着色;
将其转换为 ggplot-speak,您想要condition
映射到fill
美学上,然后您想要一个自定义的填充色标与 values c("#009B9F", "#5EBCBF", "#C6DFE0", "#E9D4E2", "#D99BC5")
。
(我会在每个发生变化的块中添加评论)
m %>%
spread_draws(b_Intercept, r_condition[condition,]) %>%
mutate(condition_mean = b_Intercept + r_condition) %>%
# map condition onto fill here ------------------------\/
ggplot(aes(y = condition, x = condition_mean, fill = condition)) +
stat_halfeyeh() +
geom_vline(xintercept = 0, linetype = "dashed") +
# change the fill scale to use your values ------------\/
scale_fill_manual(values = c("#009B9F", "#5EBCBF", "#C6DFE0", "#E9D4E2", "#D99BC5"))
侧边栏:我不确定我是否会为此使用手动色标:使用Viridis、ColorBrewer或HCL Wizard等地方的预制色标通常更容易、更好——这些色标是为诸如此类的事情而设计的色盲安全、感知均匀性、良好的去饱和度等。此外,此示例使用分类数据,并且您提供的色标具有自然顺序;我希望你的真实数据是有序的而不是分类的,否则色阶意味着数据中不存在的排序。
无论如何,下一个问题:
(2)对于后验均值为正的分布(即条件A到D),将较大的alpha值分配给曲线下位于0线右侧的区域,并分配较低的alpha值(更透明)到曲线下位于 0 线左侧的区域;
(3) 对于后均值为负的分布(即条件 E),将较低的 alpha 值(更透明)分配给曲线下位于 0 线右侧的区域,并将较高的 alpha 值(更不透明)分配给曲线下位于 0 线左侧的区域。
我不确定你在这里的意思,所以我将尝试两种不同的东西。
一种可能性是:您想将x
值映射到美学上,但如果平均值小于 0 alpha
,您想反转这种关系(我实际上将使用美学,它专门针对此几何的平板部分并离开仅间隔)。我将从做简单的映射开始:condition_mean
slab_alpha
slab_alpha
m %>%
spread_draws(b_Intercept, r_condition[condition,]) %>%
mutate(condition_mean = b_Intercept + r_condition) %>%
# map x value onto alpha -------------------------------------------\/
ggplot(aes(y = condition, x = condition_mean, fill = condition, slab_alpha = stat(x))) +
stat_halfeyeh() +
geom_vline(xintercept = 0, linetype = "dashed") +
scale_fill_manual(values = c("#009B9F", "#5EBCBF", "#C6DFE0", "#E9D4E2", "#D99BC5"))
马上您应该会看到一个问题:您的手动色标也使用了 alpha 通道,而这两个映射以一种令人困惑的方式组合在一起。所以我要从不使用 alpha 通道的 ColorBrewer 切换到调色板:
m %>%
spread_draws(b_Intercept, r_condition[condition,]) %>%
mutate(condition_mean = b_Intercept + r_condition) %>%
ggplot(aes(y = condition, x = condition_mean, fill = condition, slab_alpha = stat(x))) +
stat_halfeyeh() +
geom_vline(xintercept = 0, linetype = "dashed") +
# categorical palette that doesn't vary alpha much:
scale_color_brewer(palette = "Set1")
对于下一部分,您必须将 alpha 映射一分为二(我认为不拆分数据就不可能做到这一点,因为 ggplot 目前不支持将原始数据中的列与统计数据计算的列混合) . 您可以将函数(包括 purrr 样式的~
函数)传递给data
stats 和 geoms 的参数,这些函数将应用于数据,这使您可以轻松地在 ggplot 中拆分数据。此外,由于spread_draws
按您传递的表达式中的所有索引(在本例中为conditions
)分组,数据已经按 分组condition
,因此类似表达式mean(condition_mean)
将计算 的condition_mean
每个级别内的平均值condition
。这使您可以执行以下操作:
m %>%
spread_draws(b_Intercept, r_condition[condition,]) %>%
mutate(condition_mean = b_Intercept + r_condition) %>%
ggplot(aes(y = condition, x = condition_mean, fill = condition)) +
# move alpha mapping here and split halfeye spec in two
stat_halfeyeh(aes(slab_alpha = stat(x)), data = ~ filter(., mean(condition_mean) > 0)) +
stat_halfeyeh(aes(slab_alpha = -stat(x)), data = ~ filter(., mean(condition_mean) < 0)) +
geom_vline(xintercept = 0, linetype = "dashed") +
scale_color_brewer(palette = "Set1")
或者,您可能一直要求对 alpha 值进行硬性更改。为此,您只需要类似stat(x < 0)
orstat(x > 0)
而不是stat(x)
or
-stat(x)
:
m %>%
spread_draws(b_Intercept, r_condition[condition,]) %>%
mutate(condition_mean = b_Intercept + r_condition) %>%
ggplot(aes(y = condition, x = condition_mean, fill = condition)) +
# use binary alpha mapping
stat_halfeyeh(aes(slab_alpha = stat(x > 0)), data = ~ filter(., mean(condition_mean) > 0)) +
stat_halfeyeh(aes(slab_alpha = stat(x < 0)), data = ~ filter(., mean(condition_mean) < 0)) +
geom_vline(xintercept = 0, linetype = "dashed") +
scale_color_brewer(palette = "Set1")
最后,一般而言,如果您尝试使用 alpha 来强调任何一方更可能远离 0 的事物,我倾向于不根据均值在哪一侧来定义该映射——这似乎是一点点倒退,以忽略仅根据均值决定它在哪一边的不确定性。
abs(x)
这是一个更简单的替代方案,它仅在 alpha 美学上编码距 0 (即)的距离:
m %>%
spread_draws(b_Intercept, r_condition[condition,]) %>%
mutate(condition_mean = b_Intercept + r_condition) %>%
ggplot(aes(y = condition, x = condition_mean, fill = condition)) +
# use alpha mapping with abs(x)
stat_halfeyeh(aes(slab_alpha = stat(abs(x)))) +
geom_vline(xintercept = 0, linetype = "dashed") +
scale_color_brewer(palette = "Set1")
推荐阅读
- node.js - 如何保护 nodejs 中的套接字连接?
- javascript - 如何向动态目标、远程未启用 cors 的 url 发出 fetch 请求?在 http-proxy-middleware 中,可以在目标中使用变量吗?
- logging - 有没有办法从 DAW 中的白菜插件中记录 printk 的某处?
- scala - twitter4s:如何在播放框架中从 Action.async 返回未来
- multithreading - 将 Monix `Task` 转换为 Cats `IO` 后丢失了什么?
- java - Java中的时区问题
- java - 查找数组中频率最高的数字
- java - Eclipse、jvm 和虚拟内存过度使用
- javascript - 使用上一个 HTML 页面中的文本框值填充表格
- python - 如何使用 Big-M 在线性规划中编写此 IF 语句