Search code examples
rggplot2tidyverseggpmisc

What is the best way to calculate and display peaks of a ggplot2::geom_density() object?


I'm trying to find an easy and intuitive way to calculate and display the peaks of a ggplot2::geom_density() object.

This blog explains how to do it in base R, but it is a multistep process.

But it seems much more intuitive to use the stat_peaks() function of the ggpmisc package.

However, when running the code below, I get the error: stat_peaks requires the following missing aesthetics: y

library(tidyverse)
library(ggpmisc)

ggplot(iris, aes(x = Petal.Length)) +
  geom_density() +
  stat_peaks(colour = "red")

When creating a geom_density() you don't need to supply a y aesthetic.

So if indeed stat_peaks is the way to go, is there a work around to this issue? Perhaps there is a better solution to my problem.


Solution

  • Here is a simple workaround. The idea is to call ggplot_build, let ggplot do the calculations for you and then extract the needed y aesthetic from the resulting object, which is density in your case.

    library(ggplot2)
    library(ggpmisc)
    
    p <- ggplot(iris, aes(x = Petal.Length)) +
      geom_density()
    
    pb <- ggplot_build(p)
    p + stat_peaks(
      data = pb[['data']][[1]], # take a look at this object
      aes(x = x, y = density),
      colour = "red",
      size = 3
    )
    

    enter image description here

    I'm sure that this approach can be improved by one of the ggplot2 wizards around that can explain why this is not working...

    ggplot(iris, aes(x = Petal.Length, y = stat(density))) +
      geom_density() +
      stat_peaks()
    

    error: stat_peaks requires the following missing aesthetics: y

    ... which was my first guess.