使用 ggplot2 更改罗宾逊投影的中央子午线时出现视觉错误

Visual bug when changing Robinson projection's central meridian with ggplot2

我正在尝试在中央子午线不同于 0 的罗宾逊投影中投影世界地图。根据 this Whosebug thread,这应该是一件容易的事情(尽管示例使用 sp ).

这是我的可重现代码:

library(sf)
library(ggplot2)
library(rnaturalearth)

world <- ne_countries(scale = 'small', returnclass = 'sf')

# Notice +lon_0=180 instead of 0
world_robinson <- st_transform(world, crs = '+proj=robin +lon_0=180 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs')

ggplot() +
geom_sf(data = world_robinson)

这是结果。多边形正在从投影的一侧向另一侧闭合。

尝试使用 sp 会产生相同的效果。我还尝试了一个 shapefile,其中仅包含来自 http://www.naturalearthdata.com/ 的海岸线(无政治边界)的多边形,效果相似。

我试图 运行 我在 Mac OS X 和 Ubuntu 18.04.

上的两个独立 R 安装上的片段

变换后,跨越子午线的多边形在地图上一直延伸。解决这个问题的一种方法是将这些多边形从中间分开,这样所有的多边形要么完全位于线的西边,要么完全位于线的东边。

# define a long & slim polygon that overlaps the meridian line & set its CRS to match
# that of world
polygon <- st_polygon(x = list(rbind(c(-0.0001, 90),
                                     c(0, 90),
                                     c(0, -90),
                                     c(-0.0001, -90),
                                     c(-0.0001, 90)))) %>%
  st_sfc() %>%
  st_set_crs(4326)

# modify world dataset to remove overlapping portions with world's polygons
world2 <- world %>% st_difference(polygon)

# perform transformation on modified version of world dataset
world_robinson <- st_transform(world2, 
                               crs = '+proj=robin +lon_0=180 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs')

# plot
ggplot() +
  geom_sf(data = world_robinson)

这是 的扩展(即首先使用该答案计算 world_robinson)。但是,可以添加另一个有用的步骤。投影后,由于在原始投影中从地图的一侧交叉到另一侧而由多个多边形组成的区域(参见南极洲、斐济和俄罗斯)在重新投影后仍然有这种分裂。例如,这是南极洲的特写,我们可以看到它在本初子午线上有一个边界,none 应该是:

为了将这些区域重新拼接在一起,我们可以首先通过找到穿过本初子午线的多边形来找出哪些多边形存在问题:

bbox = st_bbox(world_robinson)
bbox[c(1,3)] = c(-1e-5,1e-5)
polygon2 <- st_as_sfc(bbox)

crosses = world_robinson %>%
  st_intersects(polygon2) %>%
  sapply(length) %>%
  as.logical %>%
  which

现在我们可以 select 这些多边形并将它们的缓冲区大小设置为零:

library(magrittr)
world_robinson[crosses,] %<>%
  st_buffer(0) 

ggplot(world_robinson) + geom_sf() 

正如我们所见,地图不再沿着本初子午线分裂: