我有以下数据框
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时才会出现问题?
答案 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中不同位置调整功能的行为摘要:
请注意,要闪避的元素等必须属于不同的组。如果在图解中明确指定了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")
由于添加width = 0.2
并没有改变任何基本内容,因此我将跳过第二个情节。
在第三幅图中,我们终于使用position = "dodge"
了,因为现在有一个组变量。条和误差条根据其各自的宽度相应地移动。如果使用position = "dodge"
而不是position = position_dodge(width = <some value>, ...)
,这是预期的行为,默认情况下,躲避的距离遵循geom层的宽度,除非{{{ 1}}。
如果position_dodge(width = ...)
层保持其默认宽度(与geom_errorbar
的默认宽度相同),则两个层的元素都将闪避相同的量。
geom_col
旁注:我们知道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