Search code examples
rggplot2kernel-density

geom_density - customize KDE


I would like to use a different KDE method than stats::density which is used by stat_density/geom_density to plot a KDE for a distrubtion. How should I go about this?


Solution

  • I realized that this can be done by extending ggplot2 with ggproto. The ggproto vignette has an example that can be adapted pretty easily:

    StatDensityCommon <- ggproto("StatDensityCommon", Stat, 
      required_aes = "x",
    
      setup_params = function(data, params) {
        if (!is.null(params$bandwidth))
          return(params)
    
        xs <- split(data$x, data$group)
        bws <- vapply(xs, bw.nrd0, numeric(1))
        bw <- mean(bws)
        message("Picking bandwidth of ", signif(bw, 3))
    
        params$bandwidth <- bw
        params
      },
    
      compute_group = function(data, scales, bandwidth = 1) {
        ### CUSTOM FUNCTION HERE ###
        d <- locfit::density.lf(data$x)  #FOR EXAMPLE
        data.frame(x = d$x, y = d$y)
      }  
    )
    
    stat_density_common <- function(mapping = NULL, data = NULL, geom = "line",
                                    position = "identity", na.rm = FALSE, show.legend = NA, 
                                    inherit.aes = TRUE, bandwidth = NULL,
                                    ...) {
      layer(
        stat = StatDensityCommon, data = data, mapping = mapping, geom = geom, 
        position = position, show.legend = show.legend, inherit.aes = inherit.aes,
        params = list(bandwidth = bandwidth, na.rm = na.rm, ...)
      )
    }
    
    ggplot(mpg, aes(displ, colour = drv)) + stat_density_common()