Graeme Prentice-Mott
Graeme Prentice-Mott

Reputation: 312

Indicate geom_errorbar outside log10 scale limits w/o using geom_segment

I have some data where some estimates have wide error bars. I'd like to plot on a meaningful scale by setting limits to the graph. However, I'd also like to indicate where error bars exceed the limits. Preferably with an arrow, and if possible, without using geom_segment, as it doesn't seem to play nicely with the log10 scale. Below the red arrows are drawn in afterwards. The solution would be to add arrows or other indication where geom_errorbar exceeds plot limits within ggplot.

set.seed(12345)
data <- data.frame(A = rnorm(10), 
                   group = c(rep("Dog", 5), rep("Cat", 5)),
                   Time = c(rep(1:5), rep(1:5)))
data <- data %>% mutate(
  SE = abs(rnorm(10)),
  B = A + SE,
  C = A - SE
  )

upper <- (with(data, max(B)) - 0.5) %>% exp()
lower <- (with(data, min(C)) + 0.5) %>% exp()

data <- data %>% mutate_at(vars(A, B, C), funs(exp))

library (ggplot2)
ggplot(data = data, aes(y = A, x = Time, color = group)) +
  geom_point(position = position_dodge(width = 0.2), size = 2) +
  geom_errorbar(aes(ymin = C, ymax = B), position = "dodge", width = 0.2, size = 0.8) +
  coord_cartesian(ylim = c(lower, upper)) +
  scale_y_log10()

enter image description here

Upvotes: 3

Views: 1017

Answers (1)

Graeme Prentice-Mott
Graeme Prentice-Mott

Reputation: 312

I found a not-so-precise solution. You can call geom_point once for upward directed triangles, and again for downward facing triangles. The only problem is that coord_cartesian doesn't seem to set the limits exactly at the specified values, so you have to add or subtract to each limit to get the triangle in the right position. Additionally, since position_dodge is already being used, position_nudge is unavailable. It involves guessing the the values to add or subtract to the y coordinate of the geom_point.

PLEASE comment if there's better solution.

    library(ggplot2)
    library(tidyverse)

    set.seed(12345)
    data <- data.frame(A = rnorm(10), 
                       group = c(rep("Dog", 5), rep("Cat", 5)),
                       Time = c(rep(1:5), rep(1:5)))
    data <- data %>% mutate(
      SE = abs(rnorm(10)),
      B = A + SE,
      C = A - SE
      )

    upper <- (with(data, max(B)) - 0.5) %>% exp()
    lower <- (with(data, min(C)) + 0.5) %>% exp()

    data <- data %>% mutate_at(vars(A, B, C), funs(exp))

    data <- data %>% 
      mutate(upper_out = ifelse(B > upper, upper, NA),
             lower_out = ifelse(C < lower, lower, NA))

    ggplot(data = data, aes(y = A, x = Time, color = group, fill = group)) +
      geom_point(position = position_dodge(width = 0.2), size = 2) +
      geom_errorbar(aes(ymin = C, ymax = B), position = "dodge", width = 0.2, size = 0.8) +
      geom_point(aes(y = upper_out + 1.02), shape = 24, 
          position = position_dodge(width = 0.2), size = 4, show.legend = F) +
      geom_point(aes(y = lower_out - 0.013), shape = 25, 
          position = position_dodge(width = 0.2), size = 4, show.legend = F) +
      scale_y_log10() +
      coord_cartesian(ylim = c(lower, upper))

enter image description here

Upvotes: 1

Related Questions