ggplot2 Полосы ошибок только в 1 направлении (в зависимости от группы)

#r #ggplot2

#r #ggplot2

Вопрос:

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

У меня есть следующий составленный пример набора данных:

   Subject lt;- c(1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3)  Condition lt;- c("A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B", "C", "C", "C", "C", "C", "C")  Time lt;- c(1,1,1,2,2,2,1,1,1,2,2,2,1,1,1,2,2,2)  Value1 lt;- c(600,550,450,300,325,250,610,545,453,323,299,280,575,560,475,100,140,85)   DF1 lt;- data.frame (Subject, Condition, Time, Value1)   

Я использую ggplot для отображения этих данных в виде линейного графика с полосами ошибок. Цель этого графика-создать фигуру, готовую к академической публикации. Поэтому, в связи с тем, что у меня большие стандартные отклонения (в реальных данных они еще больше), я хотел бы показать только верхнюю полосу ошибок для условия с самой высокой строкой и нижнюю полосу ошибок для условий с более низкими строками, чтобы попытаться визуально очистить это.

В моем примере фрейма данных есть только одна Value , однако на самом деле у меня есть 9 переменных значений для каждого Субъекта, в каждом условии, для каждого времени. В результате я хотел бы избежать (если возможно) ручного вычисления среднего и SD для каждой из этих комбинаций.

В настоящее время я использую следующий код ggplot:

 PublicationPlot lt;-ggplot(DF1, aes(Time, Value1, shape = Condition))  PublicationPlot   stat_summary(fun = mean,  geom = "point",  size= 2,  aes(group = Condition))   stat_summary(fun= mean,   geom = "line",  aes(group = Condition,  linetype = Condition))    stat_summary(fun.data = mean_cl_normal,  geom = "errorbar",  width = 0.075,  aes(group = Condition))   xlab("Measurement Times")   ylab("Value 1 (Units)")   theme(panel.grid.major = element_blank(),  panel.grid.minor = element_blank(),  panel.background = element_blank(),  axis.line=element_line(color = "black"),  legend.key = element_rect(fill= "white"),  axis.title.x = element_text(size = 15),  axis.text.x = element_text(size = 13),  axis.title.y = element_text(size = 15),  axis.text.y = element_text(size = 13),  legend.title = element_text( size=12),   legend.text=element_text(size=12))    

Любая помощь в решении этой проблемы была бы невероятной. Спасибо вам за ваше время и опыт. Я с нетерпением жду возможности поучиться у вас.

Комментарии:

1. если ваша цель состоит в том, чтобы визуально уменьшить беспорядок на графике, возможно, подумайте о другой визуализации-парные измерения гораздо лучше отображаются диаграммами рассеяния — измерение 1 по оси x, измерение 2 по оси y. Затем вы можете огранить или раскрасить по идентификатору. Показывая каждое значение, вы можете лучше идентифицировать выбросы, а ваши данные также лучше и правдивее представлены. Кроме того, вам больше не нужно будет визуализировать неопределенность. (ваши ошибки)

Ответ №1:

Хотя функции сводки в ggplot отлично подходят для быстрого создания часто используемых манипуляций с данными, я часто нахожу, что люди завязывают себя в узлы, пытаясь заставить встроенные функции ggplot делать то, для чего они не были предназначены. Как я часто говорю, вы должны решить, что вы хотите построить, а затем построить это.

В вашем случае это звучит так, как будто вы хотите иметь отдельный фрейм данных с сгруппированными минимумами и максимумами в момент времени 1 и 2. Поэтому вы могли бы сделать что-то вроде этого:

 times lt;- lapply(split(DF1, DF1$Time),   function(x) do.call(rbind,  lapply(split(x$Value1, x$Condition), mean_cl_normal)))  DF2 lt;- do.call(rbind,   lapply(times,   function(x) data.frame(ymin = min(x$ymin), ymax = max(x$ymax))))  DF2$Time lt;- 1:2   

Что затем позволяет вам рисовать полосы ошибок напрямую, а не полагаться на stat_summary :

 PublicationPlot lt;-ggplot(DF1, aes(Time, Value1, shape = Condition))  PublicationPlot   stat_summary(fun = mean,  geom = "point",  size= 2,  aes(group = Condition))   stat_summary(fun= mean,   geom = "line",  aes(group = Condition,  linetype = Condition))    geom_errorbar(data = DF2,  aes(x = Time, ymin = ymin, ymax = ymax),  inherit.aes = FALSE,  width = 0.075)    xlab("Measurement Times")   ylab("Value 1 (Units)")   theme(panel.grid.major = element_blank(),  panel.grid.minor = element_blank(),  panel.background = element_blank(),  axis.line=element_line(color = "black"),  legend.key = element_rect(fill= "white"),  axis.title.x = element_text(size = 15),  axis.text.x = element_text(size = 13),  axis.title.y = element_text(size = 15),  axis.text.y = element_text(size = 13),  legend.title = element_text( size=12),   legend.text=element_text(size=12))  

введите описание изображения здесь

Комментарии:

1. Я полностью согласен. Я чувствую, что часто люди странно боятся выполнять некоторые преобразования данных:)

Ответ №2:

В дополнение к решению @allan-cameron, вы также можете просто оставить всю сводку-шабанг вне вызова ggplot и просто объединить свои данные в более ранней части конвейера:

 library(tidyverse)  Subject lt;- c(1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3) Condition lt;- c("A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B", "C", "C", "C", "C", "C", "C") Time lt;- c(1,1,1,2,2,2,1,1,1,2,2,2,1,1,1,2,2,2) Value1 lt;- c(600,550,450,300,325,250,610,545,453,323,299,280,575,560,475,100,140,85)  DF1 lt;- data.frame (Subject, Condition, Time, Value1)  DF1 %gt;%  group_by(Condition,  Time) %gt;%  summarise(  m = mean(Value1),  SD = sd(Value1),  upper = m   SD,  lower = m - SD  ) %gt;%  ungroup() %gt;%   group_by(Time) %gt;%   mutate(upper = max(upper),  lower = min(lower)) %gt;%   ggplot(aes(x = Time, y = m))    geom_point(aes(shape = Condition))    geom_line(aes(lty = Condition))    geom_errorbar(aes(ymin = lower,  ymax = upper),  width = .075)    xlab("Measurement Times")   ylab("Value 1 (Units)")   theme(panel.grid.major = element_blank(),  panel.grid.minor = element_blank(),  panel.background = element_blank(),  axis.line=element_line(color = "black"),  legend.key = element_rect(fill= "white"),  axis.title.x = element_text(size = 15),  axis.text.x = element_text(size = 13),  axis.title.y = element_text(size = 15),  axis.text.y = element_text(size = 13),  legend.title = element_text( size=12),   legend.text=element_text(size=12)) #gt; `summarise()` has grouped output by 'Condition'. You can override using the `.groups` argument.  

Это решение основано на других пакетах tidyverse, которые заменяют пределы ваших ошибок на относительный максимум. С академической точки зрения, SD условия C во второй раз теряется таким образом, поэтому вам может потребоваться немного другое решение для этого, которое сохраняет ошибки, которые не перекрываются.

Вот решение, которое делает именно это:

 DF1 lt;- data.frame (Subject, Condition, Time, Value1)  DF1 %gt;%  group_by(Condition,  Time) %gt;%  summarise(  m = mean(Value1),  SD = sd(Value1),  upper = m   SD,  lower = m - SD  ) %gt;%  ungroup() %gt;%   group_by(Time) %gt;%   mutate(upper = map_dbl(upper, ~ if (any(upper gt; .) amp;  !any(. gt; m amp; . lt; upper)) {  .  } else{  max(upper[mlt;= .])  }),  lower = map_dbl(lower, ~ if (any(lower lt; .) amp;  !any(. lt; m amp; . gt; lower)) {  .  } else{  min(lower[mgt;= .])  })) %gt;%  ggplot(aes(x = Time, y = m))    geom_point(aes(shape = Condition))    geom_line(aes(lty = Condition))    geom_errorbar(aes(ymin = lower,  ymax = upper),  width = .075)    xlab("Measurement Times")   ylab("Value 1 (Units)")   theme(panel.grid.major = element_blank(),  panel.grid.minor = element_blank(),  panel.background = element_blank(),  axis.line=element_line(color = "black"),  legend.key = element_rect(fill= "white"),  axis.title.x = element_text(size = 15),  axis.text.x = element_text(size = 13),  axis.title.y = element_text(size = 15),  axis.text.y = element_text(size = 13),  legend.title = element_text( size=12),   legend.text=element_text(size=12)) #gt; `summarise()` has grouped output by 'Condition'. You can override using the `.groups` argument.  

По сути, вы используете верхний или нижний предел max/min, который не относится к среднему значению, которое выше/ниже предела, на который вы проводите тестирование.


Редактировать: Я только что увидел, что ваша функция сводки использует t-CI, сгенерированный функцией mean_cl_normal, вот решение, которое тоже это делает.

 library(tidyverse)  Subject lt;- c(1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3) Condition lt;- c("A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B", "C", "C", "C", "C", "C", "C") Time lt;- c(1,1,1,2,2,2,1,1,1,2,2,2,1,1,1,2,2,2) Value1 lt;- c(600,550,450,300,325,250,610,545,453,323,299,280,575,560,475,100,140,85)  DF1 lt;- data.frame (Subject, Condition, Time, Value1)  DF1 %gt;%   group_by(Condition,  Time) %gt;%  summarise(  m = mean(Value1),  SD = sd(Value1),  upper = m   qt((1   .95)/2, n()-1) * SD/sqrt(n()),  lower = m - qt((1   .95)/2, n()-1) * SD/sqrt(n())  ) %gt;%  ungroup() %gt;%   group_by(Time) %gt;%   mutate(upper = map_dbl(upper, ~ if (any(upper gt; .) amp;  !any(. gt; m amp; . lt; upper)) {  .  } else{  max(upper[mlt;= .])  }),  lower = map_dbl(lower, ~ if (any(lower lt; .) amp;  !any(. lt; m amp; . gt; lower)) {  .  } else{  min(lower[mgt;= .])  })) %gt;%  ggplot(aes(x = Time, y = m))    geom_point(aes(shape = Condition))    geom_line(aes(lty = Condition))    geom_errorbar(aes(ymin = lower,  ymax = upper),  width = .075)    xlab("Measurement Times")   ylab("Value 1 (Units)")   theme(panel.grid.major = element_blank(),  panel.grid.minor = element_blank(),  panel.background = element_blank(),  axis.line=element_line(color = "black"),  legend.key = element_rect(fill= "white"),  axis.title.x = element_text(size = 15),  axis.text.x = element_text(size = 13),  axis.title.y = element_text(size = 15),  axis.text.y = element_text(size = 13),  legend.title = element_text( size=12),   legend.text=element_text(size=12)) #gt; `summarise()` has grouped output by 'Condition'. You can override using the `.groups` argument.