Настройте прозрачность сюжета Halfeye в Tidybayes - PullRequest
0 голосов
/ 21 октября 2019

Я использую 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"))

Я смог сгенерировать рисунок ниже, где отрицательная область каждого распределения была синего цвета, а положительные области были серыми: enter image description here

Моя конечная цифра должна удовлетворять следующим критериям:

(1) Области под кривой распределения для условий от A до E последовательно окрашиваются с помощью "# 009B9F", "# 5EBCBF", "# C6DFE0", "# E9D4E2", "# D99BC5";

(2) Для распределения, чье апостериорное среднее значение положительное (т. Е. Условие от A до D), назначьте большее альфа-значение (менее прозрачное) областям под кривой, которые находятся справа от линии 0, и назначьте более низкое альфа-значение (более прозрачным) для областей под кривой, которые находятся слева от линии 0;

(3) Для распределения, заднее среднее значение которого отрицательное (т. е. условие E), присвойте более низкое значение альфа (мопрозрачность) 0 для областей под кривой, которые находятся справа от линии 0, и назначьте более высокое альфа-значение (менее прозрачное) для областей под кривой, которые находятся слева от линии 0.

Я настроилс аргументом альфа в функции ggplot, но всегда терпел неудачу. Любые предложения приветствуются.

1 Ответ

2 голосов
/ 21 октября 2019

Давайте разберемся по очереди:

(1) Области под кривой распределения для условий от A до E последовательно окрашены с помощью "# 009B9F", "# 5EBCBF", "# C6DFE0"," # E9D4E2 "," # D99BC5 ";

Переводя это в ggplot-speak, вы хотите, чтобы condition отображалось на эстетику fill, а затем вам нужна пользовательская заливка цвета сзначения 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"))

plot with manual fill scale

Боковая панель: я не уверен, что использовал бы для этого ручную цветовую шкалу: обычно проще и лучше использовать готовые цветовые шкалы из таких мест, как Viridis , ColorBrewer или Мастер HCL --- эти цветовые шкалы предназначены для таких вещей, как безопасность дальтоников, однородность восприятия, хорошая десатурация и т. Д. Также в этом примере используются категориальные данные, и у предоставленной вами цветовой шкалы естественный порядок;Я надеюсь, что ваши реальные данные являются порядковыми, а не категориальными, так как в противном случае цветовая шкала подразумевает порядок, который не существует в данных.

В любом случае, следующий вопрос:

(2) Для распределения, чье апостериорное среднее значение положительное (т. Е. Условие от A до D), назначьте большее альфа-значение (менее прозрачное) для областей под кривой, которые находятся справа от линии 0, и назначьте более низкое альфа-значение (более прозрачное) для регионовпод кривой, расположенной слева от линии 0;

(3) Для распределения, среднее значение которого отрицательно (т. е. условие E), присвойте нижнему альфа-значению (более прозрачному) 0 для областей под кривойкоторые находятся справа от линии 0 и назначают более высокое альфа-значение (менее прозрачное) для областей под кривой, которые находятся слева от линии 0.

Я не совсем уверен, что выЯ имею в виду здесь, так что я собираюсь попробовать две разные вещи.

Одна из возможностей заключается в следующем: вы хотите отобразить значение x на эстетику alpha, ноВы хотите изменить это соотношение, если среднее значение condition_mean меньше 0 (на самом деле я буду использовать эстетику slab_alpha, которая специально нацелена на часть плиты этого geom и оставляет интервалы в покое). Я начну с простого 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"))

simple slab_alpha mapping

Сразу же вы должны увидеть проблему: ваша ручная цветовая шкала также используетальфа-канал, и эти два отображения объединяются в замешательстве. Поэтому я собираюсь перейти на цветовую палитру из 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 with color brewer palette

Для следующей части вынужно разделить альфа-отображение на две части (я не думаю, что это можно сделать без разделения данных, поскольку ggplot в настоящее время не поддерживает смешивание столбцов из исходных данных со столбцами, вычисленными по статистике). Вы можете передавать функции (включая функции ~ в стиле purrr) в аргумент data статистики и геометрии, и эти функции применяются к данным, что позволяет легко разделять данные внутри 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")

split alpha, continuous

В качестве альтернативы, вы могли бы попросить о резком изменении альфа-значения. Для этого вам просто нужно что-то вроде stat(x < 0) или stat(x > 0) вместо stat(x) или -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")

split alpha, binary

Наконец,в общем, если вы пытаетесь использовать альфу, чтобы подчеркнуть вещи, которые, скорее всего, далеки от 0 с обеих сторон, я был бы склонен не определять это отображение, на основе какой стороны находится среднее значение - оно кажется немного задом наперед. игнорировать неопределенность, чтобы решить, на чьей стороне он находится, исходя только из среднего.

Вот более простая альтернатива, которая просто кодирует расстояние от 0 (т.е. abs(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 alpha mapping with abs(x)
  stat_halfeyeh(aes(slab_alpha = stat(abs(x)))) +

  geom_vline(xintercept = 0, linetype = "dashed") +
  scale_color_brewer(palette = "Set1")

alpha channel on distance from 0

...