1

I have been stuck with this for hours. When I run this :

library(ggmap)
set.seed(1)
n=100

df <- data.frame(x=rnorm(n, 0, 1), y=rnorm(n, 0, 1))

TestData <- ggplot (data = df) +
  stat_density2d(aes(x = x, y = y,fill = as.factor(..level..)),bins=4, geom = "polygon",) +
  geom_point(aes(x = x, y = y)) +
  scale_fill_manual(values = c("yellow","red","green","royalblue", "black"))

I get this error message :

Error: Unknown parameters: bins

Does anyone know why?

Mike Wise
  • 22,131
  • 8
  • 81
  • 104
hans glick
  • 2,431
  • 4
  • 25
  • 40
  • 2
    Why do you think there is a `bins` argument inside `stat_density2d`? It is not described in the help page. –  Dec 22 '15 at 08:06
  • 1
    It is not such a bad question. The OP should have posted this link though: http://stackoverflow.com/questions/19329318/how-to-correctly-interpret-ggplots-stat-density2d since the code was copied from there. – Mike Wise Dec 22 '15 at 09:43
  • Clearly the `bins` parameter has been removed, you can use the `n` parameter instead to change the contouring a bit, but I haven't seen how to directly control the number of levels generated. There probably is a way, but I need to research it more. – Mike Wise Dec 22 '15 at 09:44
  • Someone who knows more about this function will undoubtedly enlighten us soon. Read the last post in the above link for the most information. – Mike Wise Dec 22 '15 at 09:46
  • I don't think `stat_density2d` ever had a `bins` parameter. I checked version 0.8.6 (from 2010) and it was not there then. Version 2.0.0 is just more strict regarding accepting unexpected parameters. – Roland Dec 22 '15 at 11:01
  • It did not have a documented parameter per-se. But it had a parameter that was passed through to MASS:kde2d. Read the link I posted in the 2nd comment above for more information (and an example). And in a similar way you can still use the parameters `n` or `h` which is not documented. Try it. – Mike Wise Dec 22 '15 at 12:53

2 Answers2

4

Okay, adding this one as a second answer because I think the descriptions and comments in the first answer are useful and I don't feel like merging them. Basically I figured there must be an easy way to restore the regressed functionality. And after awhile, and learning some basics about ggplot2, I got this to work by overriding some ggplot2 functions:

library(ggmap)
library(ggplot2)

# -------------------------------
# start copy from stat-density-2d.R

stat_density_2d <- function(mapping = NULL, data = NULL, geom = "density_2d",
                            position = "identity", contour = TRUE,
                            n = 100, h = NULL, na.rm = FALSE,bins=0,
                            show.legend = NA, inherit.aes = TRUE, ...) {
  layer(
    data = data,
    mapping = mapping,
    stat = StatDensity2d,
    geom = geom,
    position = position,
    show.legend = show.legend,
    inherit.aes = inherit.aes,
    params = list(
      na.rm = na.rm,
      contour = contour,
      n = n,
      bins=bins,
      ...
    )
  )
}

stat_density2d <- stat_density_2d

StatDensity2d <- 
  ggproto("StatDensity2d", Stat,
          default_aes = aes(colour = "#3366FF", size = 0.5),

          required_aes = c("x", "y"),

          compute_group = function(data, scales, na.rm = FALSE, h = NULL,
                                   contour = TRUE, n = 100,bins=0) {
            if (is.null(h)) {
              h <- c(MASS::bandwidth.nrd(data$x), MASS::bandwidth.nrd(data$y))
            }

            dens <- MASS::kde2d(
              data$x, data$y, h = h, n = n,
              lims = c(scales$x$dimension(), scales$y$dimension())
            )
            df <- data.frame(expand.grid(x = dens$x, y = dens$y), z = as.vector(dens$z))
            df$group <- data$group[1]

            if (contour) {
              #  StatContour$compute_panel(df, scales,bins=bins,...) # bad dots...
              if (bins>0){
                StatContour$compute_panel(df, scales,bins)
              } else {
                StatContour$compute_panel(df, scales)
              }
            } else {
              names(df) <- c("x", "y", "density", "group")
              df$level <- 1
              df$piece <- 1
              df
            }
          }
  )

# end copy from stat-density-2d.R
# -------------------------------

set.seed(1)
n=100

df <- data.frame(x=rnorm(n, 0, 1), y=rnorm(n, 0, 1))

TestData <- ggplot (data = df) +
  stat_density2d(aes(x = x, y = y,fill = as.factor(..level..)),bins=5,geom = "polygon") +
  geom_point(aes(x = x, y = y)) +
  scale_fill_manual(values = c("yellow","red","green","royalblue", "black"))
print(TestData)

Which yields the result. Note that varying the bins parameter has the desired effect now, which cannot be replicated by varying the n parameter.

enter image description here

Mike Wise
  • 22,131
  • 8
  • 81
  • 104
  • 1
    I just got a notice that this has been fixed in the github version of ggplot2, and the bug was closed by hadley. – Mike Wise Jan 01 '16 at 17:03
0

update:

After an extended discussion with Roland (see the comments), he determined it is probably a regression bug and filed a bug report.


As the question is "why is the bins parameter unknown?", and I spent a fair amount of time researching it, I will answer it.

Your example obviously comes from this link from Oct 2013, where the parameter is used. How to correctly interpret ggplot's stat_density2d

However it was never a documented parameter, and it is not clear that it is being used there. It is probably a parameter that is being passed through to other libraries (like MASS) that are being used by stat_density2d.

We can get the code to work by getting rid of the scale_fill_manual call and using this:

library(ggmap)
set.seed(1)
n=100

df <- data.frame(x=rnorm(n, 0, 1), y=rnorm(n, 0, 1))

TestData <- ggplot (data = df) +
  stat_density2d(aes(x = x, y = y,fill = as.factor(..level..)), geom = "polygon",) +
  geom_point(aes(x = x, y = y)) 
#  scale_fill_manual(values = c("yellow","red","green","royalblue", "black"))
print(TestData)

which yields this: enter image description here

Since this looks rather different from the plot posted in the original Oct 2013 link, I would say that stat_density2d has been extensively rewritten since then, or maybe MASS:kde2d (or another MASS routine), and that the bin parameter is no longer accepted. It is also not clear that that parameter ever did anything (read the link).

You can however vary the parameters n and h - also undocumented from the stat_density2d point-of-view (as far as I can tell).

Community
  • 1
  • 1
Mike Wise
  • 22,131
  • 8
  • 81
  • 104
  • `MASS::kde2d` doesn't have a `bins` parameter. – Roland Dec 22 '15 at 21:11
  • Maybe it used to. Clearly something else did. Did you read the post this originated from? They go over it in some detail there. – Mike Wise Dec 22 '15 at 21:13
  • I don't think so. See the second answer there. – Roland Dec 22 '15 at 21:15
  • The post from Bryan Hanson? He talks about `bins`. He doesn't understand what it does, or how it is used, but it clearly was a parameter that the function accepted. What is your point? – Mike Wise Dec 22 '15 at 21:23
  • Also take a careful look at the first two plots. The first one has `bins=4` and has 4 colored buckets of values. The second one has `bins=5`, and has 5 colored buckets. So that is what `bins` did apparently. And that functionality is now gone... And the OP here got hung up on that, because that is what he wanted to control. – Mike Wise Dec 22 '15 at 21:29
  • I checked. `kde2d` didn't have a `bins` parameter even back in 2009. `stat_density2d` didn't have one then either. You could check further back (the old versions are archivated on CRAN), but I don't think it ever had any effect. The OP of the linked questions even confirms that. – Roland Dec 23 '15 at 08:31
  • Then it was some other function that `stat_density2d` used. How else do you explain the appearance of the original post from 2013? We could chat about it if you want. I live in Germany so we are probably in the same timezone. – Mike Wise Dec 23 '15 at 09:04
  • OK, I had a closer look. The `bins` parameter was actually passed to `stat_contour`. Since the ellipses from `stat_density` are no longer passed to `stat_contour`, it is no longer possible to specify the number of bins. This seems like a regression. I'll file a bug report. – Roland Dec 23 '15 at 09:28
  • Yeah, I just found this. It is a very useful feature. https://github.com/trinker/embodied/blob/master/inst/example_plots/Density.md – Mike Wise Dec 23 '15 at 09:30
  • I think hans glick deserves an upvote for his suffering. I gave him one, but it only got him to 0. – Mike Wise Dec 23 '15 at 09:40
  • 2
    Sorry, but he won't get one from me unless he adds his `sessionInfo()` to the question. – Roland Dec 23 '15 at 09:45