0

我正在尝试做的事情:使用 ggspatial::geom_sf() 绘制空间对象,使用 coord_sf() 或 ggspatial::layer_spatial() 和 ggspatial::annotation_spatial() 的组合来指定绘图的范围。

这种 ggplot/ggspatial 行为已在几篇文章中进行了描述,但“解决方案”只是临时黑客,无法确保问题不再发生。请参阅: 在更新 ggplot2 后使用 coord_sf 设置 x 和 y 的限制 在 RStudio 中在美国地图上绘制纬度和经度点时出错

这段代码工作得很好:

require(sf); require(ggspatial); require(rnaturalearth)    
country_polygons <- st_as_sf(ne_countries())
ggplot() + geom_sf(data=country_polygons)

就像这样:

ggplot() + geom_sf(data=country_polygons) + coord_sf(xlim=c(-100,100), ylim=c(-60,60))

但:

ggplot() + geom_sf(data=country_polygons) + coord_sf(xlim=c(-160,150), ylim=c(-60,60))

导致错误:st_cast.POINT(X[[i]], ...) 中的错误:无法从 POINT 创建 MULTILINESTRING

显然这不应该发生。我不明白为什么 geom_sf 调用 st_cast.POINT() 因为输入中不应该有任何点。我尝试了三种不同的世界地图(GADM 3.6 shapefile、rworldmap::countriesLow 和 rnaturalearth 之一),所以它似乎不是特定于数据集的。

使用这些 x 和 y 限制值,即使是简单的 sf 点对象也无法绘制!

set.seed(80085)
tibble(Lon=runif(1000,-180,180),
       Lat=runif(1000,-90,90)) %>% 
  st_as_sf(coords=1:2, remove=F, crs=4326) -> random_points

random_points %>% 
      ggplot() + geom_sf() + coord_sf(xlim=c(-160,150), ylim=c(-60,60))

错误消息再次是“无法从 POINT 创建 MULTILINESTRING”,我不知道它为什么会尝试创建 MULTILINESTRING。

更新:此处建议的解决方案不起作用: 为什么某些 xlims 和 ylims 在 ggplot 和 sf 中产生此错误?

random_points %>% 
  st_crop(xmin=-160, xmax=150, ymin=-60, ymax=60) %>% 
  ggplot() + geom_sf()

结果,奇怪的是,只有在 150oE 和 160oW 之间的点,即太平洋上空大约 180 经度,被保存下来。我尝试使用从 0 到 360 的经度并交换 xmin 和 xmax,但无济于事。

除了 st_crop 的错误行为,传递正确的裁剪对象再次给出相同的错误:

random_points %>% 
  filter(Lon<150, Lon>-160, Lat>-60, Lat<60) %>% 
  ggplot() + geom_sf()

> Error in st_cast.POINT(x[[1]], to, ...) : 
  cannot create MULTILINESTRING from POINT
In addition: Warning message:
In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) :
  only first part of geometrycollection is retained

结束更新

有解决方案或解决方法吗?

4

1 回答 1

0

我相信这与 s2 几何引擎以一种意想不到的方式表现有关。

TL;DR:考虑sf_use_s2(F)在您的代码中使用。

长版:

library(sf)
library(dplyr)
library(mapview)

set.seed(80085)

random_points <- tibble(Lon = runif(1000,-180,180),
                        Lat = runif(1000,-90,90)) %>% 
  st_as_sf(coords=1:2, remove=F, crs=4326) 


mapview(random_points)  # this is "truth"

在此处输入图像描述

area_of_interest <- matrix(c(-160, -60, 
                             150, -60, 
                             150, 60, 
                             -160, 60,
                             -160, -60), 
                           byrow = TRUE, 
                           ncol = 2) %>%
  list() %>% 
  st_polygon() %>% 
  st_sfc(crs = 4326) 

mapview(area_of_interest) # this is our area of interest

在此处输入图像描述

# an atribute of points - in AOI or not?
random_points$aoi <- st_contains(area_of_interest,
                                 random_points,
                                 sparse = F) %>% 
  t() %>% 
  c()

# a visual overview; this is _not_ expected!
# the topology of AOI was not applied correctly
mapview(random_points, zcol = "aoi")

在此处输入图像描述

# let us try turning S2 engine off, and fall back to good old GEOS
sf_use_s2(F)

# exactly the same code as before!!
random_points$aoi <- st_contains(area_of_interest,
                                 random_points,
                                 sparse = F) %>% 
  t() %>% 
  c()

# but the output behaves much better!
mapview(random_points, zcol = "aoi")

在此处输入图像描述

# a seletion of random points; cropped to area of interest
library(ggplot2)

random_points %>% 
  filter(aoi) %>% 
  ggplot() + geom_sf(pch = 4, color = "red")

在此处输入图像描述

于 2022-02-09T11:54:52.577 回答