首页 > 解决方案 > 如何将 geom_point、geom_bar 和 geom_errobar 与 position_dodge 对齐

问题描述

我正在尝试在 ggplot 中为多项逻辑回归生成一个图。并非在每个因子水平上都观察到我的名义因变量的所有水平。我想要一个具有均匀宽度的图。使用代码后,我可以使用带有均匀宽度条的 geom_bar 来显示每个因子的平均值position_dodge(preserve='single'),但我无法使geom_point它们对齐。

这是我的数据,决定是名义因变量:

decide=c("h", "g", "h", "g", "h", "g", "g", "h", "g", "h", "g", "h", "h", "h", "h", "h", "g", "h", "h", "r", "g", "h", "h", "h", "g", "g", "g", "h", "h", "h","h", "h", "h", "r", "h", "g", "g", "h", "g", "h", "g", "h", "g", "h", "d", "h", "h", "r", "h", "h", "g", "g", "g", "h", "g", "g", "g", "g", "h", "h")
dcsz=c("small",  "medium", "small",  "small",  "medium", "small",  "small",  "medium", "medium", "small",  "small",  "medium", "small",  "medium", "small",  "medium", "small", "medium", "small",  "small",  "medium", "small",  "medium", "medium", "medium", "small",  "small",  "medium", "small",  "medium", "small",  "medium", "small",  "medium", "medium", "medium", "small",  "medium", "medium", "small",  "medium", "small",  "medium", "medium", "small",  "small",  "medium", "small",  "medium", "medium", "medium", "small",  "small",  "small",  "small",  "medium", "medium", "small",  "small",  "medium")
disthome=c(9.2,10.0,5.0,0.8,6.5,2.0,6.8,1.6,6.9,4.4,5.8,6.2,4.7,0.6,3.0,4.7,5.8,1.5,5.8,4.5,3.2,4.6,2.9,4.1,6.5,4.8,9.1,4.7,4.3,4.2,4.8,3.5,5.4,7.1,3.0,5.3,1.0,5.2,2.2,1.7,6.0,6.1,3.1,2.4,4.3,5.1,7.2,9.8,6.9,3.1,8.8,0.9,9.7,2.2,5.4,4.4,6.8,8.3,5.4,2.2)

gohome=data.frame(decide, dcsz, disthome)

这是我得到平均误差和标准误差的方法:

gohome.disthome <- gohome %>% 
  group_by(dcsz,decide) %>%
  summarise(meandisthome = mean(na.omit(disthome)), 
            sedisthome=sd(na.omit(disthome))/sqrt(n()))

现在进入细节:这是我在设法将误差线与均值条对齐并将点分成名义变量之前的原始代码:

ggplot(gohome,aes(y=disthome, x=dcsz, fill = decide)) +
  #add bars and the preserve part keeps all bars same width
  geom_bar(stat="identity", position=position_dodge(),
           data=gohome.disthome,aes(x=dcsz,y=meandisthome))
  #overlay data points
  geom_point(position=position_dodge()) +
  #add error bars of means
  geom_errorbar(data=gohome.disthome,stat="Identity",
                position=position_dodge(),
                aes(x=dcsz, fill = decide,y=meandisthome,
                    ymin=meandisthome-sedisthome,ymax=meandisthome+sedisthome),
                    width=0.3)+
  #flip axis
  coord_flip()

在此处输入图像描述

这是我让误差线与平均线对齐的代码(使用 0.9 in position_dodge),将点分成名义变量(0.9),并且即使误差线和平均线都具有相同的宽度因变量的水平并未在每个因子水平中都观察到(我preserve="single"在 中添加position_dodge)。我不能添加preserve='single'到,geom_point否则它不会通过名义变量分隔点,并且 usingpreserve='total'也不会做任何事情:

ggplot(gohome,aes(y=disthome, x=dcsz, fill = decide)) +
  #add bars and the preserve part keeps all bars same width
  geom_bar(stat="identity",position=position_dodge(preserve='single'),
           data=gohome.disthome,aes(x=dcsz,y=meandisthome))+
  #overlay data points
  geom_point(position=position_dodge(0.9)) +
  #add error bars of means
  geom_errorbar(data=gohome.disthome,stat="Identity",
                position=position_dodge(0.9,preserve = "single"),
                aes(x=dcsz, fill = decide,y=meandisthome,
                    ymin=meandisthome-sedisthome,ymax=meandisthome+sedisthome),
                width=0.3)+
  #flip axis
  coord_flip()

在此处输入图像描述

我也尝试过使用position_dodge2而不是position_dodge不同的组合和preserve='total',但这也不能解决它。这些点要么保持发言权,要么完全分散,没有分离。我有使用的想法,position_dodge2并且preserve='total'来自以下链接,因为我的问题非常相似(不知道为什么我的不工作):https ://github.com/tidyverse/ggplot2/issues/2712

有人可以帮我修复我的代码吗?我需要指出所有错误栏的完美对齐。

标签: rggplot2

解决方案


躲避可能是一种痛苦。鉴于您的用例,并假设您没有将构面用于其他任何事情,使用它们可能会更简单:

ggplot(gohome, 
       aes(x = decide, y = disthome)) +
  stat_summary(geom = "bar", fun = "mean",
               aes(fill = decide),
               width = 1) +
  geom_point() +
  stat_summary(geom = "errorbar") + # default summary function is mean_se()
  facet_grid(forcats::fct_rev(dcsz) ~ ., switch = "y") +
  coord_flip() +
  
  # optional: aesthetic changes to imitate the original look
  theme(axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        axis.title.y = element_blank(),
        panel.spacing = unit(0, "pt"), 
        strip.background = element_blank(),
        strip.text.y.left = element_text(angle = 0))

(请注意,我也没有使用摘要数据框,因为 ggplot2 中的摘要统计信息就足够了。)

阴谋


推荐阅读