3

I want that when the line is below 0 on the graph to be red and above green. I tried to figure out my self, however, the code gives me a color ("red" as it is below 0) for the whole part of Friday-Saturday when I need this colour only below y=0.

a<-structure(list(group = c("Total", "Total", "Total", "Total", 
"Total", "Total", "Total"), measure = c("sales", "sales", "sales", 
"sales", "sales", "sales", "sales"), day = structure(1:7, .Label = c("MONDAY", 
"TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"
), class = "factor"), variable = structure(c(1L, 1L, 1L, 1L, 
1L, 1L, 1L), .Label = c("ALL", "DE", "BE", "NL", "AUS", "ES", 
"IT", "FR", "PO"), class = "factor"), value = c(2400000, 3750000, 
3400000, 3100000, 2300000, 3600000, 3100000), per_mtoday = c(2400000, 
2400000, 2400000, 2400000, 2400000, 2400000, 2400000), per_mtoday_perc = c(0, 
0.5625, 0.416666666666667, 0.291666666666667, -0.0416666666666667, 
0.5, 0.291666666666667), colour1 = c("green", "green", "green", 
"green", "red", "green", "green")), row.names = c(1L, 15L, 29L, 
43L, 57L, 71L, 85L), class = "data.frame")


ggplot(a, aes(x=day, y=per_mtoday_perc,fill = colour1, color= colour1,group = 1)) +  
  geom_line(lwd=1.5)+
  scale_y_continuous(labels = scales::percent)
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
Priit Mets
  • 465
  • 2
  • 14
  • You're probably looking for `scale_colour_steps*`. Check `help("scale_colour_stepsn")` for example – Oliver Mar 26 '21 at 13:08
  • 1
    @Oliver I don’t think that’s (directly) related. In fact, a simple `scale_color_manual` would suffice. The issue is that OP first needs to interpolate the values. – Konrad Rudolph Mar 26 '21 at 13:10

1 Answers1

7

The correct thing to do here would be, as Konrad Rudolph suggested, to interpolate the values to find the zero-crossing points on the y axis. Since that can be a little bit laborious to do properly, here is a quick way to approximate this using ggforce::geom_link2(). The function already interpolates between the xy-coordinates of points through the stat-part of the layer, so we can colour depending on the y-values of the interpolated points using the after_stat() function.

library(ggplot2)
library(ggforce)

ggplot(a, aes(x=day, y=per_mtoday_perc,fill = colour1, color= colour1,group = 1)) +  
  geom_link2(lwd=1.5,
             aes(colour = after_stat(y < 0)))+
  scale_colour_manual(
    values = c("limegreen", "red")
  ) +
  scale_y_continuous(labels = scales::percent)

enter image description here

teunbrand
  • 33,645
  • 4
  • 37
  • 63
  • Very clever. I like it! – Limey Mar 26 '21 at 13:23
  • Thank you, it is working. But do you know is it somehow possible to add a bar chart like `geom_bar(aes(x=day, y=value,fill = variable, color=variable),stat="identity",position="dodge")) ` (or instead of `fill = variable, color=variable` use `group=1`) – Priit Mets Mar 26 '21 at 13:28
  • Ugh, of course ‘ggforce’ does this out of the box. While you posted this I was still faffing around with ‘tweenr’ to do the same, just manually. – Konrad Rudolph Mar 26 '21 at 13:30
  • @Priit Mets, yeah you can but you should probably use `geom_col()` instead of `geom_bar()` if you have predefined y-values. @Konrad Rudolph I know this feeling all to well! I had previously built a stat that should have worked for exactly these kind of cases, interpolating just the exact cross-over point, but I somehow bugged out on discrete x scales :( – teunbrand Mar 26 '21 at 13:34