geom_area with fill argument

Hi there, I would like to make a plot with geom_area with different colours to negative and positive values, but I am getting an error that I could not find out how to solve with this specific data. I mean, I have found out there other examples that work, but not able to apply the logic to this data that comes from TidyTuesday.

Here is my code and the result that I got

library(tidyverse)
library(tidytuesdayR)

tt <- tt_load("2021-03-16")

dt <- tt$games

dt.2 <- dt %>% 
  filter(year == 2020) %>% 
  mutate(month = fct_relevel(month, month.name)) %>% 
  group_by(year, month) %>% 
  summarise(diff = sum(gain, na.rm = T)) %>% 
  ungroup() %>% 
  mutate(signal = ifelse(diff >=0, "pos", "neg"))

dt.2 %>% 
  ggplot(aes(x = month, y = diff, group = 1))+
  geom_area()

With this code I got this plot image

Then, I'd like to positive and negative in different colors. I thought that creating the 'signal' variable and passing it into fill would resolve, but not.

dt.2 %>% 
  ggplot(aes(x = month, y = diff, fill = signal, group = 1))+
  geom_area()

I got an error: "Erro: Aesthetics can not vary with a ribbon"

Could some help me? Thanks in advantage.

Hi, Rony.

After some googling, I think that there is some natural limitation of the geom_ribbon() (and consequently geom_area()) that does not allow the desired behavior. This is somehow connected to the way how the actual color for each pixel is defined in ggplots. For instance, with the same data, if you try to plot a line with the same idea in mind you will get the following:

dt.2 %>% 
  ggplot(aes(x = month, y = diff, color = diff > 0, group = 1))+
  geom_line()

Rplot

As you may see, color changes, but not exactly where you want it to be.
In order to overcome this limitation, you can add extra points with y = 0 and x = 'position where the line intersects x-axis' and then break the whole plot into groups with its own color (in this specific case into 3 groups).

library(tidyverse)
library(tidytuesdayR)

tt <- tt_load("2021-03-16")

dt <- tt$games

dt.2 <- dt %>% 
  filter(year == 2020) %>% 
  mutate(month = fct_relevel(month, month.name)) %>% 
  group_by(year, month) %>% 
  summarise(diff = sum(gain, na.rm = T)) %>% 
  ungroup()

# Since months are discrete, while we need to define x coordinate 
# somewhere between months, we need to convert factor to double
dt.plot <- dt.2 %>%
  mutate(month = as.numeric(month))

# This banch of lines detects the position where diff changes sign
# and assign it to groups
dt.int1 <- dt.plot %>%
  # Define the observation between which sign is changes
  mutate(si = sign(diff),
         delta = si - lead(si),
         nex = lag(delta)) %>%
  filter(abs(delta) == 2 | abs(nex) == 2) %>%
  # Using some trigonometry calculate x-coordinate of transition
  mutate(delta2 = abs(lead(diff)) + abs(diff),
         month = month + abs(diff)/delta2) %>%
  filter(abs(delta) == 2) %>%
  add_tally() %>%
  mutate(gr = 1:median(n),
         diff = 0) %>%
  select(-si, -delta, -nex, -delta2, -n)

# We need each y = 0 points at both groups ("positive" and "negative")
dt.int2 <- dt.int1 %>%
  mutate(gr = gr+1)

# Now we adding y = 0 to original dataset
dt.plot <- bind_rows(dt.plot, dt.int1, dt.int2) %>%
  arrange(month) %>%
  # this need to assign each observation in original dataset to 
  # one of the gr's
  fill(gr, .direction = "downup")

# As we need only two colors, but we have three groups
# we need to define additional variable for fill
dt.plot <- dt.plot %>%
  group_by(gr) %>%
  summarise(fll = mean(diff) > 0) %>%
  full_join(dt.plot) 

# Now we make a plot and re-defining x coordinates back to months
ggplot(dt.plot,
       aes(month, diff, fill = factor(fll), group = gr))+
  geom_area() + 
  scale_x_continuous(breaks = 1:12, labels = month.name)

Voilà

Rplot01

2 Likes

Wow! Thank you so much! The result is perfect! But, it was more difficult than I thought to achieve it. I'm going to study your code to try to understand it better! Thank you, thank you, thank you!

Let me know if you need any additional clarifications about the code.

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.