R語(yǔ)言學(xué)習(xí)筆記 -- ggplot2 繪制單側(cè)誤差線

采用ggplot2繪制誤差線默認(rèn)是上下兩個(gè)方向均繪出谴垫,但有時(shí)對(duì)于柱狀圖只顯示一個(gè)方向的誤差線效果更好。想要實(shí)現(xiàn)這一目的胳施,可以修改geom_errorbarymax/ymin的參數(shù)(但會(huì)多顯示一條直線)或者geom_errorbargeom_bar之前(前提要求誤差線比柱子要短)舞肆。下面提供一個(gè)徹底解決該問題的方法---新增geom_uperrorbar函數(shù)。
library(ggplot2)
#' @export
#' @rdname geom_linerange
geom_uperrorbar <- function(mapping = NULL, data = NULL,
                          stat = "identity", position = "identity",
                          ...,
                          na.rm = FALSE,
                          orientation = NA,
                          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,
      orientation = orientation,
      ...
    )
  )
}

#' @rdname ggplot2-ggproto
#' @format NULL
#' @usage NULL
#' @export
GeomUperrorbar <- ggproto("GeomUperrorbar", Geom,
  default_aes = aes(colour = "black", size = 0.5, linetype = 1, width = 0.5,
    alpha = NA),

  draw_key = draw_key_path,

  required_aes = c("x|y", "ymin|xmin", "ymax|xmax"),

  setup_params = function(data, params) {
    GeomLinerange$setup_params(data, params)
  },

  extra_params = c("na.rm", "orientation"),

  setup_data = function(data, params) {
    data$flipped_aes <- params$flipped_aes
    data <- flip_data(data, params$flipped_aes)
    data$width <- data$width %||%
      params$width %||% (resolution(data$x, FALSE) * 0.9)
    data <- transform(data,
      xmin = x - width / 2, xmax = x + width / 2, width = NULL
    )
    flip_data(data, params$flipped_aes)
  },

  draw_panel = function(data, panel_params, coord, width = NULL, flipped_aes = FALSE) {
    data <- flip_data(data, flipped_aes)
    #x <- as.vector(rbind(data$xmin, data$xmax, NA, data$x,    data$x,    NA, data$xmin, data$xmax))
    #y <- as.vector(rbind(data$ymax, data$ymax, NA, data$ymax, data$ymin, NA, data$ymin, data$ymin))
    sel <- data$y < 0 
    data$ymax[sel] <- data$ymin[sel]
    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))
    data <- new_data_frame(list(
      x = x,
      y = 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),
      row.names = 1:(nrow(data) * 5)
    ))
    data <- flip_data(data, flipped_aes)
    GeomPath$draw_panel(data, panel_params, coord)
  }
)

new_data_frame <- function(x = list(), n = NULL) {
  if (length(x) != 0 && is.null(names(x))) {
    abort("Elements must be named")
  }
  lengths <- vapply(x, length, integer(1))
  if (is.null(n)) {
    n <- if (length(x) == 0 || min(lengths) == 0) 0 else max(lengths)
  }
  for (i in seq_along(x)) {
    if (lengths[i] == n) next
    if (lengths[i] != 1) {
      abort("Elements must equal the number of rows or 1")
    }
    x[[i]] <- rep(x[[i]], n)
  }
  
  class(x) <- "data.frame"
  
  attr(x, "row.names") <- .set_row_names(n)
  x
}
以上代碼參考ggplot2::geom_error源代碼修改而得廉油,參考stackoverflow帖子抒线。
  library(tidyverse); library(ggpubr)
  df <- iris %>% 
    gather(Id, Value, Sepal.Length:Petal.Width)
  
  ggplot(df, aes(Species, Value, fill = Id)) + 
    geom_hline(aes(yintercept = 0), color = "grey") +
    geom_bar(aes(col = Id), stat = "summary", fun = mean, width = 0.6, fill = "transparent",
             position = position_dodge( .7)) +
    stat_summary(aes(col = Id), fun.data = 'mean_sd', geom = "uperrorbar", colour = "black", width = .4,
                 position = position_dodge( .7)) +
    theme_bw(base_size = 16) +
    theme(panel.grid   = element_blank())
如若柱狀圖中有小于0的情況嘶炭,亦可實(shí)現(xiàn)眨猎。
  df2 <- iris %>% 
    mutate(Petal.Width = Petal.Width -2) %>% 
    gather(Id, Value, Sepal.Length:Petal.Width) 
  
  ggplot(df2, aes(Species, Value, fill = Id)) + 
    geom_hline(aes(yintercept = 0), color = "grey") +
    geom_bar(aes(col = Id), stat = "summary", fun = mean, width = 0.6, fill = "transparent",
             position = position_dodge( .7)) +
    stat_summary(aes(col = Id), fun.data = 'mean_sd', geom = "uperrorbar", colour = "black", width = .4,
                 position = position_dodge( .7)) +
    theme_bw(base_size = 16) +
    theme(panel.grid   = element_blank())
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末匿情,一起剝皮案震驚了整個(gè)濱河市码秉,隨后出現(xiàn)的幾起案子鸡号,更是在濱河造成了極大的恐慌,老刑警劉巖晋控,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姓赤,死亡現(xiàn)場(chǎng)離奇詭異赡译,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)不铆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門蝌焚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人誓斥,你說(shuō)我怎么就攤上這事只洒。” “怎么了劳坑?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵毕谴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我距芬,道長(zhǎng)涝开,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任存和,我火速辦了婚禮纵朋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己藏澳,他們只是感情好业崖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著站超,像睡著了一般剑刑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上素挽,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天撰糠,我揣著相機(jī)與錄音,去河邊找鬼术辐。 笑死猾骡,一個(gè)胖子當(dāng)著我的面吹牛隘蝎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼木羹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼脐瑰!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起续誉,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后例嘱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡即寡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年钢拧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卿嘲。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖俊啼,靈堂內(nèi)的尸體忽然破棺而出同木,到底是詐尸還是另有隱情通殃,我是刑警寧澤报慕,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站霎苗,受9級(jí)特大地震影響检眯,放射性物質(zhì)發(fā)生泄漏刽严。R本人自食惡果不足惜崎弃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一缀踪、第九天 我趴在偏房一處隱蔽的房頂上張望居砖。 院中可真熱鬧,春花似錦驴娃、人聲如沸奏候。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蔗草。三九已至,卻和暖如春疆柔,著一層夾襖步出監(jiān)牢的瞬間咒精,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工旷档, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留模叙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓鞋屈,卻偏偏與公主長(zhǎng)得像范咨,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子厂庇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容