I'm using lattice
to create a scatterplot matrix with an overlaid contour plot of a bivariate kernel density function. The following code is giving a strange behavior, where the contour plots are only drawn partially, starting from the bottom and getting cut off at the top. How much gets drawn depends on the value of n
in MASS::kde2d
.
library(lattice)
library(MASS)
splom(iris, upper.panel = function(x, y, ...) {
if(is.numeric(x) & is.numeric(y)){
# calculate bivariate kernel density
f1 <- kde2d(x = x, y = y, n = 20) #, lims = c(0, 10 ,0, 10))
f <- data.frame(x = f1$x, y = rep(f1$y, each = length(f1$x)),
z = as.vector(f1$z))
panel.contourplot(x = f$x, y = f$y, z = f$z,
contour = TRUE, ...)
}
panel.xyplot(x, y, ...)
})
Poking around and printing summaries of the intermediate values seems to indicate that the functions are behaving as expected and giving values in the expected range. Any idea what's going on?
Okay, so it turns out the ...
was passing the old subscripts argument to the new panel function. Since the iris
data had 25*25 = 125 subscripts, the panel.contourplot
was only considering the first 125 elements of its x
, y
, and z
arguments. The following takes care of that.
splom(iris, upper.panel = function(x, y, subscripts, ...) {
if(is.numeric(x) & is.numeric(y)){
# calculate bivariate kernel density
v <- current.panel.limits() # allows full bleed by setting limits explicitly
f1 <- kde2d(x = x, y = y, n = 50, lims = c(v$xlim, v$ylim))
f <- data.frame(x = f1$x, y = rep(f1$y, each = length(f1$x)),
z = as.vector(f1$z))
panel.contourplot(f$x, f$y, f$z, contour = TRUE,
subscripts = 1:dim(f)[1], ...)
}
panel.xyplot(x, y, subscripts = subscripts, ...)
})
While we're at it, I threw in some code to make the levelplot
take up the entire panel instead of having nasty white borders around the edges. Much better!