rggplot2

Adding vertically aligned text in ggplot


I have below histogram based on ggplot

library(ggplot2)
set.seed(1)

ggplot(data.frame(x = rnorm(1000)), aes(x = x)) + 
  geom_histogram(breaks  = seq(-10, 10, 0.5),
                 mapping = aes(y = after_stat(density)),
                 colour  = "black",
                 alpha   = 0.3) +
  stat_function(fun = dnorm, args = list(mean = 0, sd = 1)) +
  geom_vline(xintercept = 2, linewidth = 0.70) +
  geom_vline(xintercept = -2, linewidth = 0.70)

However I would like add to text-boxes along two vertical lines, as below. The texts should be vertically aligned and placed in the middle portion along y-axis. Additionally, I would like to have a fixed distance between the text boxes and corresponding vertical line, say 10 pixel points.

How can I achieve this?

enter image description here


Solution

  • Here's an approach using annotate calls for text, rectangle, and segments, and specifying everything in data coordinates. It may take some tweaking once you've finalized the output dimensions of your plot.

    set.seed(1)
    dd = data.frame(x = rnorm(1000))
    
    v_x = 2
    y0 = .15
    y1 = .3
    box_width = 1.5
    x_offset = .3
    line_gap = 0.3
    mult = c(-1, 1)
    ggplot(dd, aes(x = x)) + 
      geom_histogram(breaks  = seq(-10, 10, 0.5),
                     mapping = aes(y = after_stat(density)),
                     colour  = "black",
                     alpha   = 0.3) +
      stat_function(fun = dnorm, args = list(mean = 0, sd = 1)) +
      geom_vline(xintercept = v_x * mult, linewidth = 0.70) +
      annotate(
        geom = "text",
        label = c(
          "Some text Some text\nSome text", 
          "Some text Some text\nSome text"
        ),
        x = (v_x + x_offset) * mult,
        y = c(y1, y0),
        hjust = 0,
        angle = 90 * mult,
        vjust = 1,
        nudge_y = -.1
      ) +
      annotate(
        geom = "rect",
        xmin = mult * (v_x + x_offset),
        xmax = mult * (v_x + x_offset + box_width),
        ymin = y0,
        ymax = y1,
        fill = alpha("dodgerblue2", 0.2),
        color = NA
      ) +
      annotate(
        geom = "segment",
        x = mult * (v_x + x_offset + box_width + line_gap),
        y = y0,
        yend = y1,
        color = alpha("dodgerblue4", 0.8),
        linewidth = 2
      )
    

    enter image description here