R - 如何在特定轮廓内找到点
R - How to find points within specific Contour
我正在使用 kde2d (MASS) 在纬度和经度数据上创建密度图。我想知道原始数据中的哪些点在特定轮廓内。
我使用两种方法创建 90% 和 50% 的轮廓。我想知道哪些点在 90% 等高线内,哪些点在 50% 等高线内。 90% 轮廓中的点将包含 50% 轮廓内的所有点。最后一步是找到 90% 等高线内不在 50% 等高线内的点(这一步我不一定需要帮助)。
# bw = data of 2 cols (lat and lon) and 363 rows
# two versions to do this:
# would ideally like to use the second version (with ggplot2)
# version 1 (without ggplot2)
library(MASS)
x <- bw$lon
y <- bw$lat
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)
这是版本 2 - 使用 ggplot2。理想情况下,我想使用这个版本来找到 90% 和 50% 轮廓内的点。
# version 2 (with ggplot2)
getLevel <- function(x,y,prob) {
kk <- MASS::kde2d(x,y)
dx <- diff(kk$x[1:2])
dy <- diff(kk$y[1:2])
sz <- sort(kk$z)
c1 <- cumsum(sz) * dx * dy
approx(c1, sz, xout = 1 - prob)$y
}
# 90 and 50% contours
L90 <- getLevel(bw$lon, bw$lat, 0.9)
L50 <- getLevel(bw$lon, bw$lat, 0.5)
kk <- MASS::kde2d(bw$lon, bw$lat)
dimnames(kk$z) <- list(kk$x, kk$y)
dc <- melt(kk$z)
p <- ggplot(dc, aes(x=Var1, y=Var2)) + geom_tile(aes(fill=value))
+ geom_contour(aes(z=value), breaks=L90, colour="red")
+ geom_contour(aes(z=value), breaks=L50, color="yellow")
+ ggtitle("90 (red) and 50 (yellow) contours of BW")
我用绘制的所有纬度和经度点以及 90% 和 50% 等高线创建了地块。我只是想知道如何提取 90% 和 50% 轮廓内的确切点。
我试图找到与每行纬度和经度值相关联的 z 值(来自 kde2d 的密度图的高度),但没有成功。我还想我可以在数据中添加一个 ID 列来标记每一行,然后在使用 melt()
之后以某种方式将其传输过来。然后我可以简单地将具有 z 值的数据与我想要的每个轮廓相匹配,并查看它们与基于 ID 列的原始 BW 数据进行比较的纬度和经度。
这是我正在谈论的图片:
我想知道哪些红点在 50% 轮廓(蓝色)内,哪些在 90% 轮廓(红色)内。
注意:大部分代码来自其他问题。向所有做出贡献的人大声喊叫!
我认为这是我能想到的最好的方法。这使用了一个技巧,使用 maptools
包中的 ContourLines2SLDF()
函数将轮廓线转换为 SpatialLinesDataFrame
对象。然后我使用 Bivand 等人的 Applied Spatial Data Analysis with R 中概述的技巧将 SpatialLinesDataFrame
对象转换为 SpatialPolygons
。然后这些可以与 over()
函数一起使用以提取每个轮廓多边形内的点:
## 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)
您可以使用 point.in.polygon
来自 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)
我正在使用 kde2d (MASS) 在纬度和经度数据上创建密度图。我想知道原始数据中的哪些点在特定轮廓内。
我使用两种方法创建 90% 和 50% 的轮廓。我想知道哪些点在 90% 等高线内,哪些点在 50% 等高线内。 90% 轮廓中的点将包含 50% 轮廓内的所有点。最后一步是找到 90% 等高线内不在 50% 等高线内的点(这一步我不一定需要帮助)。
# bw = data of 2 cols (lat and lon) and 363 rows
# two versions to do this:
# would ideally like to use the second version (with ggplot2)
# version 1 (without ggplot2)
library(MASS)
x <- bw$lon
y <- bw$lat
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)
这是版本 2 - 使用 ggplot2。理想情况下,我想使用这个版本来找到 90% 和 50% 轮廓内的点。
# version 2 (with ggplot2)
getLevel <- function(x,y,prob) {
kk <- MASS::kde2d(x,y)
dx <- diff(kk$x[1:2])
dy <- diff(kk$y[1:2])
sz <- sort(kk$z)
c1 <- cumsum(sz) * dx * dy
approx(c1, sz, xout = 1 - prob)$y
}
# 90 and 50% contours
L90 <- getLevel(bw$lon, bw$lat, 0.9)
L50 <- getLevel(bw$lon, bw$lat, 0.5)
kk <- MASS::kde2d(bw$lon, bw$lat)
dimnames(kk$z) <- list(kk$x, kk$y)
dc <- melt(kk$z)
p <- ggplot(dc, aes(x=Var1, y=Var2)) + geom_tile(aes(fill=value))
+ geom_contour(aes(z=value), breaks=L90, colour="red")
+ geom_contour(aes(z=value), breaks=L50, color="yellow")
+ ggtitle("90 (red) and 50 (yellow) contours of BW")
我用绘制的所有纬度和经度点以及 90% 和 50% 等高线创建了地块。我只是想知道如何提取 90% 和 50% 轮廓内的确切点。
我试图找到与每行纬度和经度值相关联的 z 值(来自 kde2d 的密度图的高度),但没有成功。我还想我可以在数据中添加一个 ID 列来标记每一行,然后在使用 melt()
之后以某种方式将其传输过来。然后我可以简单地将具有 z 值的数据与我想要的每个轮廓相匹配,并查看它们与基于 ID 列的原始 BW 数据进行比较的纬度和经度。
这是我正在谈论的图片:
我想知道哪些红点在 50% 轮廓(蓝色)内,哪些在 90% 轮廓(红色)内。
注意:大部分代码来自其他问题。向所有做出贡献的人大声喊叫!
我认为这是我能想到的最好的方法。这使用了一个技巧,使用 maptools
包中的 ContourLines2SLDF()
函数将轮廓线转换为 SpatialLinesDataFrame
对象。然后我使用 Bivand 等人的 Applied Spatial Data Analysis with R 中概述的技巧将 SpatialLinesDataFrame
对象转换为 SpatialPolygons
。然后这些可以与 over()
函数一起使用以提取每个轮廓多边形内的点:
## 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)
您可以使用 point.in.polygon
来自 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)