I am creating density plots with kde2d (MASS) on lat and lon data. I would like to know which points from the original data are within a specific contour.
I create
You can use point.in.polygon
from sp
## Interactively check points
plot(bw)
identify(bw$lon, bw$lat, labels=paste("(", round(bw$lon,2), ",", round(bw$lat,2), ")"))
## Points within polygons
library(sp)
dens <- kde2d(x, y, n=200, lims=c(c(-73, -70), c(-13, -12))) # don't clip the contour
ls <- contourLines(dens, level=levels)
inner <- point.in.polygon(bw$lon, bw$lat, ls[[2]]$x, ls[[2]]$y)
out <- point.in.polygon(bw$lon, bw$lat, ls[[1]]$x, ls[[1]]$y)
## Plot
bw$region <- factor(inner + out)
plot(lat ~ lon, col=region, data=bw, pch=15)
contour(dens, levels=levels, labels=prob, add=T)
I think this is the best way I can think of. This uses a trick to convert the contour lines to SpatialLinesDataFrame
objects using the ContourLines2SLDF()
function from the maptools
package. Then I use a trick outlined in Bivand, et al.'s Applied Spatial Data Analysis with R for converting the SpatialLinesDataFrame
object to SpatialPolygons
. These can then be used with the over()
function to extract points within each contour polygon:
## Simulate some lat/lon data:
x <- rnorm(363, 45, 10)
y <- rnorm(363, 45, 10)
## Version 1 (without ggplot2):
library(MASS)
dens <- kde2d(x, y, n=200)
## The contours to plot:
prob <- c(0.9, 0.5)
dx <- diff(dens$x[1:2])
dy <- diff(dens$y[1:2])
sz <- sort(dens$z)
c1 <- cumsum(sz) * dx * dy
levels <- sapply(prob, function(x) {
approx(c1, sz, xout = 1 - x)$y
})
plot(x,y)
contour(dens, levels=levels, labels=prob, add=T)
## Create spatial objects:
library(sp)
library(maptools)
pts <- SpatialPoints(cbind(x,y))
lines <- ContourLines2SLDF(contourLines(dens, levels=levels))
## Convert SpatialLinesDataFrame to SpatialPolygons:
lns <- slot(lines, "lines")
polys <- SpatialPolygons( lapply(lns, function(x) {
Polygons(list(Polygon(slot(slot(x, "Lines")[[1]],
"coords"))), ID=slot(x, "ID"))
}))
## Construct plot from your points,
plot(pts)
## Plot points within contours by using the over() function:
points(pts[!is.na( over(pts, polys[1]) )], col="red", pch=20)
points(pts[!is.na( over(pts, polys[2]) )], col="blue", pch=20)
contour(dens, levels=levels, labels=prob, add=T)