2

I want to show two ribbons per variable e.g. (max - min ribbon, and a confidence level ribbon) with geom_ribbon() in ggplot2 in R, as in the example below. I've not been able to set the colours for each ribbon separately. Ideally, I can map a colour palette to each level of the categorical variable (type), and the two ribbons will take colours from these.

## Set up data
set.seed(999)
n <- 100

mn1 <- seq(0.5, 0.9, length.out = n)
mn2 <- seq(0.75, 0.25, length.out = n)

tmp1 <- lapply(seq_len(n), function(x) {
  
  x1 <- rnorm(n, mn1[x], 0.1)
  x2 <- rnorm(n, mn2[x], 0.1)
  
  rbind(cbind(min(x1), mean(x1)-sd(x1), mean(x1), mean(x1)+sd(x1), max(x1)),
        cbind(min(x2), mean(x2)-sd(x2), mean(x2), mean(x2)+sd(x2), max(x2))
  )
})

year <- seq(1900, 1900+n-1, 1)
type <- rep(c("all", "partial"), n)

df1 <- data.frame(rep(year,each = 2), do.call(rbind, tmp1), type)
colnames(df1) <- c("year", "xmin", "xsd_lwr", "xmn", "xsd_upr", "xmax", "type")
head(df1)                  
rm(tmp1, mn1, mn2, year, type, n)

This is what I have so far in ggplot2:

library(ggplot2)

ggplot(df1, aes(x = year, y = xmn, fill = type, col= type))+
  geom_ribbon(aes(ymin=xsd_lwr, ymax = xsd_upr), linetype = 0, alpha = 0.4)+
  geom_ribbon(aes(ymin=xmin, ymax = xmax), linetype = 0, alpha = 0.4)+
  scale_color_manual(values = c("black", "darkred"))+
  scale_fill_manual(values = c("grey10", "grey30"))+
  geom_line(aes(linetype= type), size = 1)+
  scale_x_continuous(breaks = seq(1900, 2000,10))

Double ribbon ggplot geom_ribbon

UPDATE: I've accepted the answer as it does give exact control for four different colours, however, I wanted to show that the comment by @teunbrand also works as the transparency, in effect, creates four colours too, and has a better legend. I've modified the suggestion to this below:

ggplot(df1, aes(x = year, y = xmn,col= type))+
  geom_ribbon(aes(ymin=xsd_lwr, ymax = xsd_upr, fill = type), linetype = 0, alpha = 0.5)+
  geom_ribbon(aes(ymin=xmin, ymax = xmax, fill = type), linetype = 0, alpha =0.5)+
  scale_fill_manual(values = c("tomato", "dodgerblue"))+
  scale_color_manual(values = c("black", "darkred"))+
  geom_line(aes(linetype= type), size = 1)+
  scale_x_continuous(breaks = seq(1900, 2000,10))

enter image description here

CCID
  • 1,368
  • 5
  • 19
  • 35
  • 2
    It's unclear to me: do you want 'partial' vs 'all' to be different colours, or do you want the xmin/xmax vs xsd_lwr/xsd_upr to have different colours? If it's the first, you could just do `scale_colour_manual(aesthetics = c("colour", "fill"), values = c("tomato", "dodgerblue"))` and that seems to give different colours to the different types. – teunbrand Feb 06 '21 at 16:56
  • I meant to be able to control all four colours, from the example above. However, this does work, as the transparencies give each colour two shades where they overlap. I have adapted this to `scale_colour_manual(aesthetics = "fill", values = c("tomato", "dodgerblue")), with `fill=type` inside each `geom_ribbon()`, so that the `scale_color_manual` also worked and not in the initial `ggplot(aes())`. – CCID Feb 07 '21 at 14:37

2 Answers2

1

You could define a specific fill group in the ribbon's aes, and associate the color you wish with it in scale_fill_manual:

ggplot(df1, aes(x = year, y = xmn, fill = type, col= type))+
  geom_ribbon(aes(ymin=xsd_lwr, ymax = xsd_upr), linetype = 0, alpha = 0.4,show.legend=F)+
  scale_fill_manual(values = c("grey10","red","grey30","green"))+
  geom_ribbon(aes(ymin=xmin, ymax = xmax,fill=ifelse(type=='all','all_minmax','partial_min_max')), linetype = 0, alpha = 0.4,show.legend=F)+
  scale_color_manual(values = c("black", "darkred"))+
  geom_line(aes(linetype= type), size = 1)+
  scale_x_continuous(breaks = seq(1900, 2000,10))

Note that I had to remove the legend for the ribbons to avoid to show the second legend with the new color groups. enter image description here

Waldi
  • 39,242
  • 6
  • 30
  • 78
1

For easiest and full control of as many colors/fills as you wish, use ggnewscale. This gives you also full legend control.

I am not on a console, coding on rdrr.io/snippets, therefore struggling to show a figure output. But reproducible it is

library(ggplot2)
library(ggnewscale)

ggplot(df1, aes(x = year, y = xmn, col = type))+
  geom_ribbon(aes(ymin=xsd_lwr, ymax = xsd_upr, fill = "SE"), linetype = 0, alpha = 0.4)+
  scale_fill_manual(name = NULL, values = c("tomato","darkred"))+
  new_scale_fill()+
  geom_ribbon(aes(ymin=xmin, ymax = xmax, fill= "range"), linetype = 0, alpha = 0.4)+
  scale_fill_manual(name = NULL, values = c("dodgerblue", "darkred"))+
  geom_line(aes(linetype= type), size = 1)+
  scale_color_manual(values = c("black", "darkred"))+
  scale_x_continuous(breaks = seq(1900, 2000,10)) 
tjebo
  • 21,977
  • 7
  • 58
  • 94