ggspatial:geom_sf 因 coord_sf 中的某些 xlim 值而失败
ggspatial: geom_sf fails with certain xlim values in coord_sf
我正在尝试做的事情:使用 ggspatial::geom_sf()、使用 coord_sf() 或 ggspatial::layer_spatial() 和 ggspatial::annotation_spatial 的组合来绘制空间对象() 指定绘图的范围。
此 ggplot/ggspatial 行为已在多篇文章中进行了描述,但“解决方案”只是临时的黑客攻击,无法确保问题不会再次发生。看:
此代码工作正常:
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。
更新:此处建议的解决方案不起作用:
Why do some xlims and ylims produce this error in ggplot and 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
更新结束
是否有解决方案或解决方法?
我认为这与 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")
我正在尝试做的事情:使用 ggspatial::geom_sf()、使用 coord_sf() 或 ggspatial::layer_spatial() 和 ggspatial::annotation_spatial 的组合来绘制空间对象() 指定绘图的范围。
此 ggplot/ggspatial 行为已在多篇文章中进行了描述,但“解决方案”只是临时的黑客攻击,无法确保问题不会再次发生。看:
此代码工作正常:
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。
更新:此处建议的解决方案不起作用: Why do some xlims and ylims produce this error in ggplot and 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
更新结束
是否有解决方案或解决方法?
我认为这与 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")