Search code examples
rggplot2ridgeline-plot

How to add geom_segment to geom_density_ridges_gradient?


I would like to add vertical segments to a ridgeline plot whose histograms show customized quantiles.

I managed to get the vertical segments if I map fill color with ..x... But I would like to show quantiles in the density plots. I wrote the following code:

library(datasets)
library(ggplot2)
data("iris")

iris_lines <- data.frame(Species = c("setosa", "versicolor", "virginica"),
                         x0 = c(5, 5.9, 6.5))

Figure1 <- ggplot(iris, aes(x=Sepal.Length, y=Species, fill=(..quantile..))) +
  geom_density_ridges_gradient(jittered_points = FALSE, calc_ecdf = TRUE, quantile_lines = c(TRUE), quantiles =c(0.1,0.25,0.75,0.9),scale=0.9, color='white')+
  geom_segment(data = iris_lines, aes(x = x0, xend = x0, y = as.numeric(Species), yend = as.numeric(Species) + c(.9,.5,.5)), color = "red") + scale_y_discrete(expand = c(0.01, 0))
Figure1

The code works if I map fill color as fill = ..x.. I get three vertical lines representing the mean of each density plot; however, if I map fill color as fill = ..quantile.. I get the following error:

Error in data.frame(..., check.names = FALSE) : 
  arguments imply differing number of rows: 1, 3

Solution

  • Nice chart!

    Add inherit.aes = F to the second geom so it doesn't try to match your data with the fill calculation in the ggplot(aes() call.

    Figure1 <- ggplot(iris, aes(x=Sepal.Length, y=Species, fill=(..quantile..))) +
          geom_density_ridges_gradient(jittered_points = FALSE, 
                                       calc_ecdf = TRUE, 
                                       quantile_lines = c(TRUE), 
                                       quantiles =c(0.1,0.25,0.75,0.9),
                                       scale=0.9, color='white') +
          geom_segment(data = iris_lines, 
                       aes(x = x0, xend = x0, 
                           y = as.numeric(Species), yend = as.numeric(Species) + c(.9,.5,.5)),
                       color = "red", inherit.aes = F) +   #### HERE ####
          scale_y_discrete(expand = c(0.01, 0))
    Figure1
    

    enter image description here


    Edit:

    OP asked in comment about selectively labeling some elements and adding a label for the median line. Here's an approach, probably not the pithiest.

    Figure1 <- ggplot(iris, aes(x=Sepal.Length, y=Species, 
                                fill = (..quantile..), 
                                color = (..quantile..))) +
      geom_density_ridges_gradient(jittered_points = FALSE, 
                                   calc_ecdf = TRUE, 
                                   quantile_lines = c(TRUE), 
                                   quantiles =c(0.1,0.25,0.75,0.9),
                                   scale=0.9, color='white') +
      geom_segment(data = iris_lines, 
                   aes(x = x0, xend = x0, fill = "median",
                       y = as.numeric(Species), 
                       yend = as.numeric(Species) + c(.9,.5,.5),
                       color = "median")) +   #### HERE ####
      scale_y_discrete(expand = c(0.01, 0)) +
    
      scale_color_manual(name = "quantile",
                         limits = c(1:3, "median"),
                         values = alpha("firebrick1", c(0, 0, 0, 1)),
                         labels = c("<10%", "10-25%", "IQR", "median")) +
      scale_fill_manual(name = "quantile",
        limits = c(1:3, "median"),
        values = c("cadetblue", "coral", "orange", "white"), 
        na.value = "gray30",
        labels = c("<10%", "10-25%", "IQR", "median"))
    Figure1
    

    enter image description here