用ggplot添加误差线时的位置问题

时间:2019-03-25 12:12:35

标签: r ggplot2

我有以下数据框

group1 = c('a', 'b')
group2 = c('1', '1', '2', '2')
mean = 1:4
sd = c(0.2, 0.3, 0.5, 0.8)
df = data.frame(group1, group2, mean, sd)

我想用geom_errorbar()在图表上绘制sd。效果很好:

ggplot(data = df, aes(x=group1, y = mean))+
  geom_col(position = 'dodge') + 
  geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd),
                position = 'dodge')

我想减小误差线的宽度,所以我运行:

ggplot(data = df, aes(x=group1, y = mean))+
  geom_col(position = 'dodge') + 
  geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd), width = 0.2,
                position = 'dodge')

到目前为止,一切都很好。但是后来我想按组2填充。

ggplot(data = df, aes(x=group1, y = mean, fill = group2))+
  geom_col(position = 'dodge') + 
  geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd), width = 0.2,
                position = 'dodge')

问题在于错误栏不再位于中间。我不知道为什么。我查看了文档,但没有找到关于此问题的任何信息。我看着这个问题Force error bars to be in the middle of bar 而这个Aesthetics issue using position dodge in ggplots with geom_errorbar却没有人解释为什么会这样。一种建议的解决方案是添加position_dodge(0.9)。

ggplot(data = df, aes(x=group1, y = mean, fill = group2))+
  geom_col(position = 'dodge') + 
  geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd), width = 0.2,
                position = position_dodge(0.9))

它起作用了,但是我不知道为什么以及它做了什么。有人可以解释发生了什么吗?为什么我不能仅添加width = 0.2来减小误差线的宽度?而position_dodge(0.9)的作用是什么?我为什么需要它?为什么仅当我添加fill = group2时才会出现问题?

1 个答案:

答案 0 :(得分:1)

TL; DR :从一开始,position = "dodge"(或position = position_dodge(<some width value>))并没有按照您的预期做。

基本直觉

position_dodge是ggplot2软件包中可用的位置调整功能之一。如果有多个 属于不同组的元素 占据相同的位置,则position_identity完全不执行任何操作,position_dodge会将元素并排放置position_stack将它们垂直放置,position_fill将它们垂直放置并按比例拉伸以适合整个绘图区域,等等。

以下是RStudio's ggplot2 cheat sheet中不同位置调整功能的行为摘要:

cheatsheet

请注意,要闪避的元素等必须属于不同的组。如果在图解中明确指定了group = <some variable>,它将用作分组变量,以确定应该躲避的元素等。如果aes()中没有显式的组映射,但是存在color = <some variable> / fill = <some variable> / linetype = <some variable>等中的一个或多个,依此类推,则将使用所有离散变量的交互作用。来自?aes_group_order

  

默认情况下,该组设置为所有离散的交互   图中的变量。这通常可以正确划分数据,但是   当它没有,或者在图中没有使用离散变量时,   您将需要通过映射来明确定义分组结构   组为每个组具有不同值的变量。

按图细分

让我们从原始情节开始。由于情节的美学映射中没有任何类型的分组变量,因此position = "dodge" 完全没有

对于两个几何层,我们都可以用position = "identity"替换它(实际上position = "identity"geom_errorbar的默认位置,因此无需将其拼写出来),然后将结果情节是一样的。

增加透明度可以很明显地看出,两个条形图占据了相同的位置,一个位于另一个位置之后。

我猜这原始情节不是您的实际意图?确实很少有这样的场景,一个酒吧像这样在另一个酒吧之后...

ggplot(data = df, aes(x=group1, y = mean))+
  geom_col(position = 'dodge') + 
  geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd),
                position = 'dodge') +
  ggtitle("original plot")

ggplot(data = df, aes(x=group1, y = mean))+
  geom_col(position = "identity") + 
  geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd)) +
  ggtitle("remove position dodge")

ggplot(data = df, aes(x=group1, y = mean))+
  geom_col(position = "identity", alpha = 0.5) + 
  geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd)) +
  ggtitle("increase transparency")

illustration 1

由于添加width = 0.2并没有改变任何基本内容,因此我将跳过第二个情节。

在第三幅图中,我们终于使用position = "dodge"了,因为现在有一个组变量。条和误差条根据其各自的宽度相应地移动。如果使用position = "dodge"而不是position = position_dodge(width = <some value>, ...),这是预期的行为,默认情况下,躲避的距离遵循geom层的宽度,除非{{{ 1}}。

如果position_dodge(width = ...)层保持其默认宽度(与geom_errorbar的默认宽度相同),则两个层的元素都将闪避相同的量。

geom_col

illustration 2

旁注:我们知道ggplot(data = df, aes(x=group1, y = mean, fill = group2))+ geom_col(position = 'dodge') + geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd), width = 0.2, position = 'dodge') + ggtitle("third plot") ggplot(data = df, aes(x=group1, y = mean, fill = group2))+ geom_col(position = 'dodge') + geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd), position = 'dodge') + ggtitle("with default width") geom_errorbar都具有相同的默认宽度,因为它们以相同的方式设置数据。在geom_col / GeomErrorbar$setup_data中都可以找到以下代码行:

GeomCol$setup_data

总而言之,当您有不同的审美组时,在data$width <- data$width %||% params$width %||% (resolution(data$x, FALSE) * 0.9) # i.e. if width is specified as one of the aesthetic mappings, use that; # else if width is specified in the geom layer's parameters, use that; # else, use 90% of the dataset's x-axis variable's resolution. <- default value of 0.9 中指定宽度确定每个元素移动的距离,而在每个geom图层中指定宽度则确定每个元素的...宽度。只要不同的geom层闪避相同的数量,它们就会彼此对齐。

下面是一个随机示例,每个图层使用不同的宽度值(position_dodge使用0.5,geom_col使用0.9),但闪避宽度相同(0.6):

geom_errorbar

example