条形图的误差线只在一个方向上显示

12

是否可以在ggplot2中调整误差线,使其仅朝一个方向绘制(例如仅向上而不是向下)?

df <- data.frame(trt = factor(c(1, 1, 2, 2)), resp = c(1, 5, 3, 4),
                 group = factor(c(1, 2, 1, 2)), se = c(0.1, 0.3, 0.3, 0.2))
df2 <- df[c(1,3), ]

limits <- aes(ymax = resp + se, ymin = resp - se)
dodge <- position_dodge(width = 0.9)

p <- ggplot(df, aes(fill = group, y = resp, x = trt))
p + geom_bar(position = dodge, stat = "identity") +
    geom_errorbar(limits, position = dodge, width = 0.25)

Rplot

5个回答

22

一个简单的解决方法是先绘制误差线:

p +
  geom_errorbar(limits, position = dodge, width=0.25) +
  geom_bar(position = dodge, stat = "identity")

enter image description here


这对我很有效,也是我在解决这个问题时找到的最简单的解决方案。谢谢! - Kalif Vaughn

8

现在使用一般情况下实现这个功能相当容易(其中不能将较低的误差棒隐藏在其他绘图元素下),因为他们使得使用自定义geom扩展ggplot2非常容易。

ggplot2的github仓库中复制geom_errorbar的代码到新的.R文件中,然后进行以下几个修改:

geom_uperrorbar <- function(mapping = NULL, data = NULL,
   stat = "identity", position = "identity",
   ...,
   na.rm = FALSE,
   show.legend = NA,
   inherit.aes = TRUE) {
   layer(
      data = data,
      mapping = mapping,
      stat = stat,
      geom = GeomUperrorbar,
      position = position,
      show.legend = show.legend,
      inherit.aes = inherit.aes,
      params = list(
         na.rm = na.rm,
         ...
      )
   )
}

上述唯一需要更改的两个地方是将geom_errorbar更改为geom_uperrorbar,并将geom = GeomErrorbar更改为geom = GeomUperrorbar

GeomUperrorbar <- ggproto("GeomUperrorbar", Geom,
   default_aes = aes(colour = "black", size = 0.5, linetype = 1, width = 0.5,
      alpha = NA),

   draw_key = draw_key_path,

请注意,此注释中断了部分代码块,下面的代码块将继续执行函数。在上面,我们只是将 GeomErrorbar 两次更改为 GeomUperrorbar
   required_aes = c("x", "y", "ymax"),

   setup_data = function(data, params) {
      data$width <- data$width %||%
         params$width %||% (resolution(data$x, FALSE) * 0.9)

      transform(data,
         xmin = x - width / 2, xmax = x + width / 2, width = NULL
      )
   },

再次中断函数。以上我们将所需的美学要求更改为xyymax,即用y替换ymin。我们需要y从那里开始竖线(而不是在ymin处),因此我们不再需要ymin,因为那里不会有水平线。

   draw_panel = function(data, panel_scales, coord, width = NULL) {
      GeomPath$draw_panel(data.frame(
         x = as.vector(rbind(data$xmin, data$xmax, NA, data$x,   data$x)),
         y = as.vector(rbind(data$ymax, data$ymax, NA, data$ymax, data$y)),
         colour = rep(data$colour, each = 5),
         alpha = rep(data$alpha, each = 5),
         size = rep(data$size, each = 5),
         linetype = rep(data$linetype, each = 5),
         group = rep(1:(nrow(data)), each = 5),
         stringsAsFactors = FALSE,
         row.names = 1:(nrow(data) * 5)
      ), panel_scales, coord)
   }
)

我们在传递给 xy 的向量中删除了最后三个元素,这些元素是用于下限误差线的。此外,我们将最后一个元素从 ymin 更改为 y,因为我们希望该线从 y 开始,而不是从 ymin 开始。

"%||%" <- function(a, b) {
   if (!is.null(a)) a else b
}

这最后一部分只是在代码中需要定义的一个方便函数。
如果您包含所有这些代码源文件,那么您可以像使用geom_errorbar一样使用geom_uperrorbar,甚至可以将geom = "uperrorbar"传递给stat_summary, 使用y而不是ymin

1
顺便提一下,最后那部分(%||%)现在在 purrr 中很容易获得。 - Axeman
这是最佳解决方案! - Ven Yao

7

在这种情况下,Henrik的建议非常好,但我建议您查看上限和下限设置的位置。

 limits <- aes(ymax = resp + se, ymin = resp - se)

在这行代码中,你通过将ymin设置为resp - se来明确告诉ggplot把下方的误差线也画出来;如果只设置为resp,则只会有上方的误差线。

 limits <- aes(ymax = resp + se, ymin = resp)

虽然你也会在条形图的顶部看到一条黑线,但是为了让它看起来更干净,你可以给整个条形图添加黑色轮廓。

p <- ggplot(df, aes(fill = group, y = resp, x = trt))+
  geom_bar(position = dodge, stat = "identity") +
  geom_bar(position = dodge, stat = "identity", 
           color="black", show_guide=FALSE)+
  geom_errorbar(limits, position = dodge, width = 0.25)
p

请注意,我复制了条形图层,但使用了“黑色”颜色,这会添加轮廓线。在彩色图层中关闭了图例,因为我个人喜欢避免图例中的对角线。

“bar


3
Henrik的答案适用于所有条形图的高度都大于误差线的情况。然而,如果您的误差线比数据条形图还要高,那么“底部”尾部(正数据条形图的负误差线或反之亦然)的尾巴将会被看到,因为它将穿过0 y轴。如果您所有的数据方向相同,您可以将ymin限制设置为0。
这种方法的问题在于,如果您有混合数据条形图(有些是正数,有些是负数),则无法将限制设置为0。例如,如果原始数据如下:
df <- data.frame(trt = factor(c(1, 1, 2, 2)), resp = c(1, 5, -3, 4),
             group = factor(c(1, 2, 1, 2)), se = c(2, 0.3, 4, 0.2))
df2 <- df[c(1,3), ]

limits <- aes(ymax = resp + se, ymin = resp - se)
dodge <- position_dodge(width = 0.9)

p <- ggplot(df, aes(fill = group, y = resp, x = trt))
p + geom_errorbar(limits, position = dodge, width = 0.25) +
    geom_bar(position = dodge, stat = "identity") 

生成的图表将有误差棒,延伸到trt 1、group 1下方和trt 2、group1上方。

可以通过在limit语句中使用ifelse()子句来解决此问题:

limits <- aes(ymax = ifelse(resp>0,resp + se,resp/2),
              ymin = ifelse(resp<0,resp - se,resp/2))

p + geom_errorbar(limits, position = dodge, width = 0.25) +
    geom_bar(position = dodge, stat = "identity") 

在这种情况下,如果数据是正数,则误差线最大值保持不变,但误差线的最小值会调整为数据条高度的一半,因此它仍然隐藏在数据条后面。

解决方案很简洁,但我们看到误差线与柱子(如果使用geom_point)相接处有一条细黑线。@Robert Wagner提到的解决方案适用于其他几何对象。 - Denis Cousineau

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接