r - 对于给定的点,找到最近的负值网格单元,R
问题描述
我在 R 中有一个栅格类型对象,它是一个纬度/经度网格,每个单元格都有一个值,即该单元格的深度或高度(从 marmap 下载getNOAA.bathy()
,bathymap
在玩具示例中)。
然后我有一个带有经纬度坐标(points
)的点列表。对于每个点,我想找到最接近具有负(深度)值的点的网格单元。如果有多个单元格,那么我想随机选择其中一个。一旦我有/一个最近的负网格单元格,然后我想找到并保存一个随机的 lat,long 落在这个单元格内。
这里的最终目标是将每个点“移动”到最近的单元格中具有负值的随机位置。
请注意,当前未投影这些点和深海图。它们只是十进制度的纬度和经度。
这是一个可以使用的玩具设置:
library(marmap)
library(ggplot2)
#get a map
bathymap <- getNOAA.bathy(lat1 = -30, lon1 = 65, lat2 = 55, lon2 = 155, resolution = 10, keep = FALSE, antimeridian = FALSE, path = NULL)
#sample points
points = data.frame("x" = c(138.605,139), "y" = c(35.0833,35.6))
#visualize the problem/set-up
ggplot() +
#build map
geom_raster(data = bathymap, aes(x=x, y=y, fill=z)) +
geom_contour(data = bathymap, aes(x=x, y=y, z=z),
breaks=0, #contour for land
colour="black", size=0.3) +
scale_fill_gradient2(low="skyblue", mid="white", high="navy", midpoint = 0) +
#add points
geom_point(data = points, aes(x=x, y=y), color = "blue", alpha = 1, size = 1) +
lims(x = c(138,139.5),
y = c(34,36)) +
coord_fixed() +
geom_text(data = bathymap, aes(x=x, y=y, fill=z, label=z), size = 2)```
解决方案
这是一个解决方案。基本上,对于每个原始地理点,我做了以下工作:
- 我曾经
marmap::dist2isobath()
沿着给定的等深线定位具有负值的最近点。 - 由于等深线的位置在低分辨率水深测量中可能相当不精确,因此负等深线有时会穿过具有正值的单元格。因此,我用 . 检查了上面确定的每个点的深度
marmap::get.depth()
。如果返回的深度是负数,那么这是成功的,如果不是,我回到步骤 1 并沿着更深的等深线寻找最近的点(因此depth_increment
争论)。因此,这是一个增量过程,仅当一个点最终位于负单元格中时才会停止。 - 我将所有这些打包在
find_closest_negative()
函数中,您可以将其应用于数据集中的每个点purrr::map2_df()
。
该函数返回一个表:
- 每个点的原始坐标,
- 最近负单元格中最近点的坐标,以及
- 新位置的深度。
最初位于负单元格中的点不受该函数的影响。小心:大水深和许多点可能会相当耗时......
library(marmap)
library(tidyverse)
# Custom function to get location of closest point along a given isobath
# bathy: bathymetric object from marmap::getNOAA.bathy
# x, y: longitude and latitude of a single point
# isobath: negative integer. Minimum depth at which the point should be located
# depth_increment: positive integer to look for deeper cells. Big values allow
# the function to run faster but might lead to more imprecise results
find_closest_negative <- function(bathy, x, y, isobath = -1, depth_increment = 50) {
# Duplicate point to avoid weird dist2isobath() error message
point <- data.frame(x, y)
a <- point[c(1,1), ]
depth_a <- get.depth(bathy, a, locator = FALSE)
depth <- unique(depth_a$depth)
if (depth < 0) {
return(unique(depth_a))
} else {
while(depth >= 0 ) {
b <- dist2isobath(bathy, a, isobath = isobath)
depth_b <- get.depth(bathy, b[,4:5], locator = FALSE)
depth <- unique(depth_b$depth)
isobath <- isobath - depth_increment
}
return(unique(depth_b))
}
}
# Get (a small) bathymetric data
bathymap <- getNOAA.bathy(lat1 = 34, lon1 = 138, lat2 = 36, lon2 = 140,
resolution = 10)
# Sample points
points <- data.frame("x" = c(138.605, 139, 138.5, 138.85, 138.95, 139.5),
"y" = c(35.0833, 35.6, 34.2, 35.0, 34.8, 34.4))
# For each point, find the closest location within a negative cell
points2 <- points %>%
mutate(map2_df(x, y, .f = ~find_closest_negative(bathymap, .x, .y,
isobath = -1,
depth_increment = 50)))
points2
#> x y lon lat depth
#> 1 138.605 35.0833 138.5455 34.99248 -1111
#> 2 139.000 35.6000 139.2727 35.36346 -311
#> 3 138.500 34.2000 138.5000 34.20000 -2717
#> 4 138.850 35.0000 138.7882 35.00619 -101
#> 5 138.950 34.8000 139.0053 34.79250 -501
#> 6 139.500 34.4000 139.5000 34.40000 -181
# Some data wrangling to plot lines between pairs of points below
origin <- points2 %>%
mutate(id = row_number()) %>%
select(lon = x, lat = y, id)
destination <- points2 %>%
mutate(id = row_number()) %>%
select(lon, lat, id)
global <- bind_rows(origin, destination)
# Plot the original points and their new location
bathymap %>%
ggplot(aes(x, y)) +
geom_tile(aes(fill = z)) +
geom_contour(aes(z = z), breaks = 0, colour = 1, size = 0.3) +
geom_text(aes(label = z), size = 2) +
geom_point(data = points2, aes(x = lon, y = lat), color = "red", size = 2) +
geom_point(data = points2, aes(x = x, y = y), color = "blue") +
geom_line(data = global, aes(x = lon, y = lat, group = id), size = 0.4) +
scale_fill_gradient2(low = "skyblue", mid = "white", high = "navy",
midpoint = 0) +
coord_fixed()
推荐阅读
- amazon-web-services - 如何从使用临时 saml 凭证创建的 AmazonSecurityTokenServiceClient 中获取会话令牌?
- java - MongoDb Criteria Query LTE 不适用于数字
- html - 使用 flex 垂直和水平居中时从跨度中删除下划线
- sql - 筛选在 SQL 选择查询中未找到的名称
- google-maps - 如何自定义 Google 地图上的 myLocationEnabled 按钮?
- java - Android Studio Firebase 获取数据
- python - 始终在 Python 日志记录文件中包含特定文本作为最后一行?
- c# - DatePicker 其他格式的默认日期
- php - 尽管@if() 查询不是真的 Laravel 5.8,但我得到了真实的
- macos - Is OpenGL on macOS deprecated?