Defining contour line levels for density2d

2,335 views
Skip to first unread message

Stavros Macrakis

unread,
May 13, 2009, 5:36:51 PM5/13/09
to ggplot2
How do I go about setting the levels for the contour lines for
density2d? If I use geom_tile, I can presumably do things like fill =
log(..density..) or fill = cut(..density.. , ...), but what if I want
to keep the contour line display but choose the values of the lines or
have them be at non-linear intervals?

Thanks!

-s

JiHO

unread,
May 13, 2009, 6:21:05 PM5/13/09
to macr...@alum.mit.edu, ggplot2

look at the "breaks" argument of stat_contour.

JiHO
---
http://jo.irisson.free.fr/

David Kahle

unread,
May 13, 2009, 7:32:17 PM5/13/09
to JiHO, macr...@alum.mit.edu, ggplot2
Hi Stavros - 

I think ideally what you want is something akin to scale_y_log10() or scale_colour_manual() for the contour lines, right?  Unfortunately, there's not a scale_contour.  Looking at the source, it doesn't appear that there's any way to specify where the lines are, either by enumeration or a function to determine them like log10.  

I've played around with the code for a little and learned from Hadley's source how to make a contour plot setting the levels manually, but my fix isn't pretty.

library(MASS)

mu <- c(0,0)
(si <- matrix(c(3,2,2,2), 2, 2, byrow = T))
df <- data.frame(mvrnorm(1000, mu = mu, Sigma = si))

ggplot(aes(x = X1, y = X2), data = df) +
  geom_point()

ggplot(aes(x = X1, y = X2), data = df) +
  geom_density2d()

  

## manually calculate the lines where you want them

dens <- kde2d(df$X1, df$X2, n = 100)

  

cl <- contourLines(
  x = dens$x,
  y = dens$y,
  z = dens$z,
  levels = fullseq(range(dens$z), .01)
)  

cl <- mapply(function(x, piece) {
  rbind(data.frame(x, piece = piece), c(NA, NA, NA))
  }, cl, seq_along(cl), SIMPLIFY = FALSE)
cl_df <- do.call('rbind', cl)

  


## make the plot with path  

ggplot() +
  geom_path(aes(x = x, y = y, group = piece, colour = level),
    data = cl_df) +
  scale_colour_continuous(breaks = na.omit(unique(cl_df$level)))

As you can see, the levels are set by the levels = command within the contourLines command.  The sequence can, of course, be anything.

Perhaps there's an easier way to do it, but this will get it done in a pinch.

Cheers
david.

JiHO

unread,
May 13, 2009, 8:53:05 PM5/13/09
to David Kahle, macr...@alum.mit.edu, ggplot2
On 2009-May-13 , at 19:32 , David Kahle wrote:

> ## manually calculate the lines where you want them
>
> dens <- kde2d(df$X1, df$X2, n = 100)
>

sorry for my first reply which overlooked the tiny problem that you
can't have two stats for one geom. So David is correct, you have to
compute the density outside of ggplot. However, once you do that,
there is no need to do all the rest manually too. You can use
geom_contour directly. See the second example in stat_density2d or :

library("ggplot2")
library("MASS")

d = data.frame(x=rnorm(1000),y=rnorm(1000))

dens = MASS::kde2d(d$x, d$y, n = 100)
densf = data.frame(expand.grid(x=dens$x, y=dens$y), z=as.vector(dens$z))

ggplot(densf, aes(x=x,y=y,z=z)) + geom_contour(breaks=seq(min(densf
$z), max(densf$z), length.out=10))
# this puts 10 equally spaced breaks but you could put whatever you
want in the breaks parameter

I hope this is more helpful.

JiHO
---
http://jo.irisson.free.fr/

David Kahle

unread,
May 13, 2009, 10:37:33 PM5/13/09
to JiHO, macr...@alum.mit.edu, ggplot2
Duh.

Clearly a far superior method. Thanks JiHO. :)

david.

Stavros Macrakis

unread,
May 13, 2009, 11:21:24 PM5/13/09
to JiHO, David Kahle, ggplot2
That's great, thank you!

-s
Reply all
Reply to author
Forward
0 new messages