4

I'd like to add a shaded region, using ggplot2, connecting the category for each bar as shown in this graph enter image description here

Data

library(ggplot2)
  
specie <- c(rep("sorgho" , 3) , rep("poacee" , 3) , rep("banana" , 3) , rep("triticum" , 3) )
condition <- rep(c("normal" , "stress" , "Nitrogen") , 4)
value <- abs(rnorm(12 , 0 , 15))
data <- data.frame(specie,condition,value)
  
ggplot(data, aes(fill=condition, y=value, x=specie)) + 
  geom_bar(position="fill", stat="identity", width = .5)

enter image description here

user438383
  • 5,716
  • 8
  • 28
  • 43
PabloAB
  • 233
  • 1
  • 6
  • 1
    very related https://stackoverflow.com/questions/70837348/connect-stack-bar-charts-with-multiple-groups-with-lines-or-segments-using-ggplo and https://stackoverflow.com/questions/66229164/r-connect-bar-graphs-with-lines-filled-in-with-matching-bar-color?noredirect=1&lq=1 – tjebo Aug 16 '22 at 20:50

1 Answers1

7

What you are describing is more like an alluvial plot, and you should check out ggalluvial.

However, it is possible in vanilla ggplot using a lot of data manipulation and geom_area

library(tidyverse)

alluvia <- data %>%
  mutate(condition = factor(condition, c('Nitrogen', 'normal', 'stress'))) %>%
  group_by(specie) %>%
  arrange(specie, condition, by_group = TRUE) %>%
  mutate(y = value) %>%
  ungroup() %>%
  mutate(x = as.numeric(as.factor(specie))) %>%
  group_by(specie, condition) %>%
  summarise(x = c(x - 0.25, x, x + 0.25), y = y)

ggplot(alluvia %>% filter(x %% 1 == 0), aes(x, y, fill = condition)) +
  geom_area(data = alluvia, alpha = 0.4, position = 'fill') +
  geom_col(width = 0.5, color = 'gray50', position = 'fill') +
  scale_x_continuous(breaks = 1:4, labels = unique(alluvia$specie),
                     name = 'specie') +
  theme_minimal(base_size = 16) +
  scale_fill_brewer(palette = 'Set2') +
  theme(panel.grid.major.x = element_blank(),
        panel.grid.minor.x = element_blank())

enter image description here

For a quick and easy (but not as pretty) equivalent in vanilla ggplot you can use a geom_area with thinner bars:

ggplot(data, aes(fill=condition, y=value, x=specie)) + 
  geom_area(aes(group = condition), position = 'fill', alpha = 0.5) +
  geom_bar(position="fill", stat="identity", width = .25)

enter image description here

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87