简体   繁体   English

将 sf object 裁剪到 R 中另一个 sf 多边形的范围的问题

[英]problem cropping sf object to extent of another sf polygon in R

I often download large-scale climate data and crop it to the extent of some spatial object.我经常下载大规模的气候数据,并将其裁剪到一些空间 object 的范围内。 I have code that still works to do this with sea surface temperature data cropped to fall within a "bathymetric mask" (a shape that falls within a bounding box and is shallower than a certain depth in the oceans).我的代码仍然可以通过将海面温度数据裁剪为落入“测深掩码”(一种位于边界框内且比海洋中的某个深度浅的形状)来执行此操作。 I downloaded a new temperature dataset from here ("sst.mon.mean.nc") , and I can't figure out how to crop it correctly.我从这里 ("sst.mon.mean.nc")下载了一个新的温度数据集,但我不知道如何正确裁剪它。 Everything I have tried produces an empty sf object.我尝试过的所有东西都会产生一个空的 sf object。

Here is code to reproduce the issue having downloaded the dataset linked above:这是下载上面链接的数据集后重现问题的代码:

library(tidyverse)
library(raster)
library(sf)
library(oceanmap)

# set bounding box
latrange <- c(35, 45)
lonrange <- c(-78, -66) 

# download COBE data and put in working directory, then run: 
cobe.raw <- raster::stack("sst.mon.mean.nc")
cobe.tidy <- raster::as.data.frame(cobe.raw, xy=TRUE)  %>% 
  pivot_longer(cols=c(-x, -y), names_to="date", values_to="sst") %>%
  filter(!is.na(sst)) 

# get bathymetry with bounding box
bathy <- get.bathy(lon = lonrange, lat = latrange, visualize = F, res = 15) 

# get CRS for reprojecting COBE
bathy.crs <- bathy %>% 
  as("SpatialPolygonsDataFrame") %>% 
  st_as_sf() %>% 
  st_crs() 

# make bathymetry mask
bathy.mask <- bathy %>% 
  as("SpatialPolygonsDataFrame") %>% 
  st_as_sf() %>% # retains CRS 
  dplyr::filter(layer <= 300) # get rid of points over 300 m deep

# also tried making a polygon union 
bathy.mask.union <- st_union(bathy.mask)

# make COBE sf object
cobe.sf <- cobe.tidy %>% 
  mutate(x=x-180) %>% # change lon to -180/+180 from +360
  st_as_sf(coords=c("x","y"), crs = bathy.crs) 

I tried cobe.sf %>% st_intersect(bathy.mask) , cobe.sf %>% st_intersect(bathy.mask.union) , cobe.sf %>% st_filter(bathy.mask) , and cobe.sf %>% st_join(bathy.mask, left=FALSE) (which was in the original code and still works for all the other data files).我试过cobe.sf %>% st_intersect(bathy.mask)cobe.sf %>% st_intersect(bathy.mask.union)cobe.sf %>% st_filter(bathy.mask)cobe.sf %>% st_join(bathy.mask, left=FALSE) (在原始代码中,仍然适用于所有其他数据文件)。 They all produce an empty object, which makes me suspect I am missing something stupid about the raw COBE data.他们都产生了一个空的 object,这让我怀疑我错过了关于原始 COBE 数据的一些愚蠢的东西。 COBE is a very large dataset but I did plot cobe.sf and it has a global extent and looks like a normal map. COBE 是一个非常大的数据集,但我做了 plot cobe.sf ,它具有全局范围,看起来像普通的 map。 Any ideas?有任何想法吗? Here is the summary of each object:以下是每个 object 的摘要:

> cobe.sf
Simple feature collection with 67932249 features and 2 fields
geometry type:  POINT
dimension:      XY
bbox:           xmin: -179.5 ymin: -84.5 xmax: 179.5 ymax: 89.5
epsg (SRID):    4326
proj4string:    +proj=longlat +ellps=WGS84 +no_defs
# A tibble: 67,932,249 x 3
   date          sst      geometry
   <chr>       <dbl>   <POINT [°]>
 1 X1891.01.01 -1.80 (-179.5 89.5)
 2 X1891.02.01 -1.80 (-179.5 89.5)
 3 X1891.03.01 -1.80 (-179.5 89.5)
 4 X1891.04.01 -1.80 (-179.5 89.5)
 5 X1891.05.01 -1.80 (-179.5 89.5)
 6 X1891.06.01 -1.80 (-179.5 89.5)
 7 X1891.07.01 -1.80 (-179.5 89.5)
 8 X1891.08.01 -1.80 (-179.5 89.5)
 9 X1891.09.01 -1.80 (-179.5 89.5)
10 X1891.10.01 -1.80 (-179.5 89.5)
# ... with 67,932,239 more rows
> bathy.mask
Simple feature collection with 497 features and 1 field
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -78 ymin: 35 xmax: -66 ymax: 45
epsg (SRID):    4326
proj4string:    +proj=longlat +ellps=WGS84 +no_defs
First 10 features:
   layer                       geometry
1      5 POLYGON ((-67.25 45, -67 45...
2     44 POLYGON ((-67 45, -66.75 45...
3    127 POLYGON ((-66.75 45, -66.5 ...
4    122 POLYGON ((-66.5 45, -66.25 ...
5     95 POLYGON ((-66.25 45, -66 45...
6      5 POLYGON ((-67.75 44.75, -67...
7     47 POLYGON ((-67.5 44.75, -67....
8     77 POLYGON ((-67.25 44.75, -67...
9     50 POLYGON ((-67 44.75, -66.75...
10   159 POLYGON ((-66.75 44.75, -66...
> bathy.mask.union
Geometry set for 1 feature 
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: -78 ymin: 35 xmax: -66 ymax: 45
epsg (SRID):    4326
proj4string:    +proj=longlat +ellps=WGS84 +no_defs
MULTIPOLYGON (((-75.5 39.5, -75.25 39.5, -75.25...

Your conversion from 0-360 longitude to -180-180 longitude was off.您从 0-360 经度到 -180-180 经度的转换已关闭。 See here for example: https://gis.stackexchange.com/questions/201789/verifying-formula-that-will-convert-longitude-0-360-to-180-to-180例如,请参见此处: https://gis.stackexchange.com/questions/201789/verifying-formula-that-will-convert-longitude-0-360-to-180-to-180

Data: Note that I sampled 10,000 rows.数据:请注意,我抽样了 10,000 行。

# cobe.tidy
set.seed(123)
cobe.tidy <- raster::as.data.frame(cobe.raw, xy=TRUE)  %>% 
  pivot_longer(cols=c(-x, -y), names_to="date", values_to="sst") %>%
  filter(!is.na(sst))

cobe.sample <- cobe.tidy %>% 
  sample_n(10000)

Original version: cobe gets projected incorrectly and your bathymetry ends up in China/Mongolia (or rather, China/Mongolia end up in New England).原始版本: cobe投影不正确,您的测深仪最终出现在中国/蒙古(或者更确切地说,中国/蒙古最终出现在新英格兰)。

# make COBE sf object
cobe.sf <- cobe.sample %>% 
  mutate(x=x-180) %>% # change lon to -180/+180 from +360
  st_as_sf(coords=c("x","y"), crs = bathy.crs) 

ggplot() +
  geom_sf(data = cobe.sf) +
  geom_sf(data = bathy.mask.union, fill = "red")

在此处输入图像描述

New version: Bathymetry correctly appears off of New England.新版本:测深仪正确出现在新英格兰附近。

# make COBE sf object
cobe.sf <- cobe.sample %>% 
  mutate(x= ifelse(x >= 180, x-360, x)) %>% # change lon to -180/+180 from +360
  st_as_sf(coords=c("x","y"), crs = bathy.crs) 

ggplot() +
  geom_sf(data = cobe.sf) +
  geom_sf(data = bathy.mask.union, fill = "red")

在此处输入图像描述

To clip, we use st_intersection() .要剪辑,我们使用st_intersection() In this case, you could also do cobe.sf[bathy.mask.union,] .在这种情况下,您也可以执行cobe.sf[bathy.mask.union,]

output <- cobe.sf %>% 
  st_intersection(bathy.mask)

ggplot() +
  geom_sf(data = output) +
  geom_sf(data = bathy.mask.union, fill = "red", alpha = 0.5)

output

Simple feature collection with 10 features and 2 fields
geometry type:  POINT
dimension:      XY
bbox:           xmin: -77.5 ymin: 36.5 xmax: -67.5 ymax: 43.5
CRS:            +proj=longlat +ellps=WGS84
# A tibble: 10 x 3
   date          sst     geometry
   <chr>       <dbl>  <POINT [°]>
 1 X1992.11.01  8.42 (-77.5 43.5)
 2 X1896.10.01 15.4  (-67.5 40.5)
 3 X1913.09.01 19.1  (-70.5 40.5)
 4 X1911.01.01  8.03 (-67.5 40.5)
 5 X1932.12.01  7.34 (-69.5 42.5)
 6 X1928.03.01  2.67 (-70.5 42.5)
 7 X1974.07.01 20.4  (-73.5 40.5)
 8 X2013.02.01  4.32 (-67.5 43.5)
 9 X1899.11.01 11.4  (-71.5 41.5)
10 X1941.06.01 22.1  (-75.5 36.5)

在此处输入图像描述

Seems like what you need to do is似乎你需要做的是

cobe.raw <- raster::stack("sst.mon.mean.nc")
cobe.rawr <- rotate(cobe.raw)

And take it from there从那里拿走

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM