Serkan
Serkan

Reputation: 1945

Geom_ribbon with two groups in different locations

I have the following data,

# Generate Data


library(tidyverse)
library(ggspectra)


fake_data <- tibble(
        time = seq(1,100, length.out = 1000),
        gdp  = time+time*(1-sin(0.15*time))
) %>% mutate(
        time  = row_number(),
        growth = (gdp - lag(gdp))/lag(gdp) * 100,
        peak   = as.numeric(near(gdp, peaks(gdp), tol = 0.01)),
        valley = as.numeric(near(gdp, valleys(gdp), tol = 0.01)),
        type = as.factor(
                case_when(
                        gdp >= lag(gdp) ~ "Expansion",
                        gdp <= lag(gdp) ~ "Contraction"
                )
        )
) %>% mutate(
        cycle = as.factor(cumsum(peak + valley))
) %>%  na.omit()

And I'm using ggplot2 to produce a plot

fake_data %>% 
        ggplot(mapping = aes(x = time, y = gdp)) + 
        geom_line() + geom_point(
                fake_data %>% filter(peak == 1 | valley == 1),
                mapping = aes(x = time, y = gdp)
        ) + geom_ribbon(aes(ymax = gdp, ymin = 0,fill = type, group = type), alpha = 0.5)

Which generates the following plot,

enter image description here

Ideally, the contraction and expansion are clearly seperated for illustrative purposes. I attempted to create an additional group to seperate the connected ribbons but I got the following error Error: Aesthetics can not vary with a ribbon.

How do I generate this plot neatly?

Upvotes: 0

Views: 147

Answers (1)

teunbrand
teunbrand

Reputation: 37933

You might benefit from setting your groups from run-length based IDs. The data.table::rleid() can help with that.

library(tidyverse)
library(ggspectra)

fake_data <- tibble(
  time = seq(1,100, length.out = 1000),
  gdp  = time+time*(1-sin(0.15*time))
) %>% mutate(
  time  = row_number(),
  growth = (gdp - lag(gdp))/lag(gdp) * 100,
  peak   = as.numeric(near(gdp, peaks(gdp), tol = 0.01)),
  valley = as.numeric(near(gdp, valleys(gdp), tol = 0.01)),
  type = as.factor(
    case_when(
      gdp >= lag(gdp) ~ "Expansion",
      gdp <= lag(gdp) ~ "Contraction"
    )
  )
) %>% mutate(
  cycle = as.factor(cumsum(peak + valley))
) %>%  na.omit()

fake_data %>% 
  ggplot(mapping = aes(x = time, y = gdp)) + 
  geom_line() + 
  geom_point(
    fake_data %>% filter(peak == 1 | valley == 1),
    mapping = aes(x = time, y = gdp)
  ) + 
  geom_area(aes(fill = type, group = data.table::rleid(type)), 
              alpha = 0.5)

Created on 2021-08-27 by the reprex package (v1.0.0)

Upvotes: 1

Related Questions