otteheng
otteheng

Reputation: 604

R: Connect bar graphs with lines filled in with matching bar color

I'm working on recreating the look of a plot found in a recent Economist article. There are two bar graphs connected by lines with the space in between them having the same color, albeit a little opaque.

I've seen this question asked but the examples only have lines connecting the bar graphs. Here's some fake data:

set.seed(0)
data_bar <- data.frame(
  stringsAsFactors = F,
  Sample = rep(c("A", "B"), each = 10),
  Percentage = runif(20),
  Taxon = rep(1:10, by = 2)
)

I've worked on reworking the linked example with no success. Any ideas?

Also in case you can't see the graph here's a screen shot:

enter image description here

Upvotes: 2

Views: 2598

Answers (2)

tjebo
tjebo

Reputation: 23757

This is essentially an alluvial chart, and you can use the ggalluvial package for this.

You will need to use geom_flow, as it creates the geom "in between" the bars (use geom_col for those), and you need to set curve_type = "linear".

library(ggalluvial)
#> Loading required package: ggplot2
library(tidyverse)

set.seed(0)
data_bar <- data.frame(
  stringsAsFactors = F,
  Sample = rep(c("A", "B"), each = 10),
  Percentage = runif(20),
  Taxon = rep(1:10, by = 2)
)

## first need to calcualte the actual percentage by group
data_bar %>%
  group_by(Sample) %>%
  mutate(perc = Percentage* 100/sum(Percentage)) %>%
ggplot(aes(y = perc, x = Sample, fill = as.character(Taxon))) +
  geom_flow(aes(alluvium = Taxon), alpha= .5, color = "white",
            curve_type = "linear", 
            width = .5) +
  geom_col(width = .5, color = "white") +
  scale_fill_brewer(palette = "RdBu")+
  scale_y_continuous(NULL, expand = c(0,0)) +
  cowplot::theme_minimal_hgrid() +
  theme(panel.grid.major = element_blank(), 
        axis.text.y = element_blank(), 
        axis.ticks.y = element_blank())
#> Warning: The `.dots` argument of `group_by()` is deprecated as of dplyr 1.0.0.
#> This warning is displayed once every 8 hours.
#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.

Created on 2022-01-25 by the reprex package (v2.0.1)

Upvotes: 2

teunbrand
teunbrand

Reputation: 37953

This took some fiddling adjusting the width of the bars and the x-position of the area, but essentially geom_area(..., position = "fill") could take you pretty far. Alternatively you could also use position = "stack".

library(ggplot2)

set.seed(0)
data_bar <- data.frame(
  stringsAsFactors = F,
  Sample = rep(c("A", "B"), each = 10),
  Percentage = runif(20),
  Taxon = rep(1:10, by = 2)
)


ggplot(data_bar, aes(Sample, Percentage, fill = Taxon, group = Taxon)) +
  geom_col(position = "fill", width = 0.5, colour = "black") +
  geom_area(aes(x = c("A" = 1.25, "B" = 1.75)[Sample]), 
            position = "fill", colour = "black", alpha = 0.5,
            outline.type = "both")

Created on 2021-02-16 by the reprex package (v1.0.0)

Alternative with stacking:

ggplot(data_bar, aes(Sample, Percentage, fill = Taxon, group = Taxon)) +
  geom_col(position = "stack", width = 0.5, colour = "black") +
  geom_area(aes(x = c("A" = 1.25, "B" = 1.75)[Sample]), 
            position = "stack", colour = "black", alpha = 0.5,
            outline.type = "both")

enter image description here

Upvotes: 4

Related Questions