4

I'm trying to get multiple area layers out of a ggproto object. I don't know if this is even possible but in case it is, I'm unable to figure out how.

For instance, how can I get the code below to produce two area layers where one has y coordinates as half of the other -

StatDensityHalf <- ggproto("StatDensity2", Stat, 
  required_aes = "x",
  default_aes = aes(y = ..density..),

  compute_group = function(data, scales, bandwidth = 1) {
    d <- density(data$x, bw = bandwidth)
    rbind(
       data.frame(x = d$x, density = d$y, fill = 1),
       data.frame(x = d$x, density = d$y/2, fill =2)
    )
  }  
)

stat_density_half <- function(mapping = NULL, data = NULL, geom = "line",
                                position = "identity", na.rm = FALSE, show.legend = NA, 
                                inherit.aes = TRUE, bandwidth = NULL,
                                ...) {
  layer(
    stat = StatDensityHalf, 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)) + 
  stat_density_half(bandwidth = 1, geom = "area", position = "stack")

Please note, I'm NOT looking for a workaround to produce the same plot as the example suggests. I'm looking for a generic solution to this problem.

Mike Wise
  • 22,131
  • 8
  • 81
  • 104
TheComeOnMan
  • 12,535
  • 8
  • 39
  • 54
  • The example does not work for me, I get an error `Aesthetics can not vary with a ribbon`, that I can google and remove by adding `aes(fill = ..x.. < 100)` , but frankly I am not sure what you are trying to do in this example. Can you explain better? – Mike Wise Jan 24 '16 at 19:24
  • Yes, that's right. Even if I change the geom argument to line, I still don't get two lines. Instead I get a ribbon of sorts with ymax = y and ymin = y/2. I would like to get two simple lines instead. – TheComeOnMan Jan 25 '16 at 02:34

1 Answers1

4

Okay, finally got around to finishing this up. This creates two layers:

library(ggplot2)

StatDensityHalf <- 
    ggproto("StatDensity2", Stat,
            required_aes = "x",
            default_aes = aes(y = ..density..),
            compute_group = function(data, scales, bandwidth = 1,fak=1,fillgrp="1"){
                 d <- density(data$x, bw = bandwidth)
                data.frame(x = d$x, density = d$y / fak, fill = fillgrp)
             }
    )

stat_density_half <- function(mapping = NULL, data = NULL, geom = "line", 
                              position = "identity", na.rm = FALSE, show.legend = NA,
                              inherit.aes = TRUE, bandwidth = NULL, ...) {
    list(
      layer(
        stat = StatDensityHalf, data = data, mapping = mapping, geom = geom,
        position = position, show.legend = show.legend, inherit.aes = inherit.aes,
        params = list(bandwidth = bandwidth, na.rm = na.rm, fak = 1, fillgrp = "1", ...)),

      layer(
        stat = StatDensityHalf, data = data, mapping = mapping, geom = geom,
        position = position, show.legend = show.legend, inherit.aes = inherit.aes,
        params = list(bandwidth = bandwidth, na.rm = na.rm, fak = 2, fillgrp = "2", ...))
      )
    }

ggplot(mpg, aes(cty)) +
  stat_density_half(bandwidth = 2, geom = "area", position = "stack") +
  scale_fill_manual(values = c("2" = "red", "1" = "blue"))

Yields:

enter image description here

Update:

In the first iteration I had two ggproto's because I didn't really see how to add parameters to a ggproto (here fak and fillgrp). The solution was to add them explicitly to the compute_group function in addition adding them to the params list, otherwise the ggproto wrapper complains and fails.

Mike Wise
  • 22,131
  • 8
  • 81
  • 104
  • Thanks! I should have probably explained this aspect better in the question. The issue is that the number of layers could also vary. The user might request for three layers with y values as 2/3rd and 1/3rd for instance. I'm unable to play with the `data` argument in the `stat_density_half` itself to be able to tell how many layers I need. If I could, I could probably pass the arguments for 1/3rd and 2/3rd in the `params` list. – TheComeOnMan Jan 25 '16 at 02:26
  • Hey. Sorry, I've been extremely busy and haven't had the time to look at it yet. I will try and get to this by the next weekend. – TheComeOnMan Mar 07 '16 at 10:16
  • Have a look at this one too. I think it has some related material. http://stackoverflow.com/questions/34876683/how-to-extend-ggplot2-boxplot-with-ggproto/35485110#35485110 – Mike Wise Mar 07 '16 at 13:38