ggplot2 z order of multiple geoms (background to foreground)

Viewed 657

I am trying to plot multiple lines with surrounding area, using ggplot2, with geom_ribbon for the are, and a centerline with geom_line. The values are overlapping, but I'd like each ribbon/line combination to be either bottom or top as a combination.

Here's a reproducible example:

library(ggplot2)
x <- 1:10
y <- c(1+x/100, 2-x, .1*x^2)
data <- data.frame(x=rep(x,3), y=y, lower=y-1, upper=y+1, color=rep(c('green', 'blue', 'yellow'), each=10))

In the example I can get the plot I want by using this code:

ggplot() +
  geom_ribbon(data=data[data$color=='green',],aes(x=x, ymin=lower, ymax=upper, fill=paste0('light',color))) +
  geom_line(data=data[data$color=='green',],aes(x=x, y=y, col=color)) +
  geom_ribbon(data=data[data$color=='blue',],aes(x=x, ymin=lower, ymax=upper, fill=paste0('light',color))) +
  geom_line(data=data[data$color=='blue',],aes(x=x, y=y, col=color)) +
  geom_ribbon(data=data[data$color=='yellow',],aes(x=x, ymin=lower, ymax=upper, fill=paste0('light',color))) +
  geom_line(data=data[data$color=='yellow',],aes(x=x, y=y, col=color)) +
  scale_color_identity() +
  scale_fill_identity()

enter image description here

But when I keep it simple and us this this code

plot <- ggplot(data=data) +
  geom_ribbon(aes(x=x, ymin=lower, ymax=upper, fill=paste0('light',color))) +
  geom_line(aes(x=x, y=y, col=color)) +
  scale_color_identity() +
  scale_fill_identity()

enter image description here

the lines of the background data go over the 'top' ribbons, or if I switch the geom_line and geom_ribbon, my middle-lines are no longer visible.

For this example, the lengthy call works, but in my real data, I have a lot more lines, and I'd like to be able to switch lines from background to foreground dynamically.

Is there any way that I can tell ggplot2 that there is an ordering that has to switch between my different geoms?

P.S. I can't post images yet, sorry if my question seems unclear.

1 Answers

You could save some typing with a loop

 ggplot(data=data) +
   purrr::map(.x = split(data, f = data$color),  
              .f = function(d){
     list(geom_ribbon(data=d,aes(x=x, ymin=lower, ymax=upper), fill=paste0('light',unique(d$color))), 
       geom_line(data=d,aes(x=x, y=y), col=unique(d$color)))
   }) 
Related