Ggplot dynamic shading/pattern overlay on geom_bar

ggplot2
geom_bar

#1

Is there a way to dynamically shade a region of the geom_bar based on a secondary value?

In the simple example below, I have a limit which is used to create the line on the chart. I would want any portion of the bars above the line to be either lighter/darker than below the line or have a pattern overlay but remain the same colors. However, the number of groups and size of groups making up the bars are dynamic and will change from bar to bar and plot to plot so I was hoping there was a way to do it without calculating on each bar where the line intersects. Thank you!

x <- tribble(
  ~n, ~a, ~b, ~c, ~d, ~cut,
   1,  5,  5,  5,  5,   12,
   2, 10,  4,  1,  2,   12,
   3, 11,  0,  0, 14,   12,
   4,  5,  7,  5,  0,   12
)
x <- x %>% gather(a:d, key = label, value = val)
ggplot(a) + 
  geom_col(aes(n, val, fill=label)) +
  geom_line(aes(n, cut)) +
  theme_bw()


#2

I created a summary data frame with just a single row for each n. Without knowing how your actual data is structured, it’s hard to say if this is the most straightforward way.

Once that was done, I just added a black semi-transparent geom_col.

suppressPackageStartupMessages(library(tidyverse))

x <- tribble(
  ~n, ~a, ~b, ~c, ~d, ~cut,
  1,  5,  5,  5,  5,   12,
  2, 10,  4,  1,  2,   12,
  3, 11,  0,  0, 14,   12,
  4,  5,  7,  5,  0,   12
)
x <- x %>% gather(a:d, key = label, value = val)
ggplot(x) + 
  geom_col(aes(n, val, fill=label)) +
  geom_col(
    data = . %>% group_by(n) %>% summarize(cut = mean(cut)),
    mapping = aes(x = n, y = 12),
    fill = "black",
    alpha = .5) +
  theme_bw()

image


#3

Thanks Nick, definitely set me in the right direction. Ended up using geom_segment to get the shade above the cutoff.

library(tidyverse)

x <- tribble(
  ~n, ~a, ~b, ~c, ~d, ~cut,
   1,  5,  5,  5,  5,   12,
   2, 10,  4,  1,  2,   12,
   3, 11,  0,  0, 14,   12,
   4,  5,  7,  5,  0,   12
)
x <- x %>% 
  gather(a:d, key = label, value = val) %>% 
  group_by(n) %>% 
  mutate(tot=sum(val))

ggplot(x) + 
  geom_col(aes(n, val, fill=label)) +
  geom_segment(aes(x=n, xend=n, y=cut, yend=tot), 
               size=51.5, color="black", alpha=0.1) +
  theme_bw()