从与R中的国际日期变更线交叉的多边形中移除线(例如,rnaturalearth中的俄罗斯)

zkure5ic  于 2023-02-10  发布在  其他
关注(0)|答案(3)|浏览(170)

**问题:**与国际日期变更线交叉的面通常有一条南北线穿过。rnaturalearth包中的东俄罗斯就是一个很好的例子,但我在使用其他空间数据时也遇到过这种情况。我希望能够删除这条线以便绘图。
**尝试:**我主要使用R中的sf包来进行Map,我尝试了各种解决方案,包括st_union、st_合并、st_wrap_dateline、st_remove_holes,以及使用其他包中的函数,如aggregate、merge和gUnaryUnion,但到目前为止我的努力毫无结果。
**示例:**以下代码使用流行的rnaturalearth包演示了俄罗斯沿着国际日期变更线的问题线。

library(tidyverse)
library(rnaturalearth)
library(sf)

#Import data
world <- ne_countries(scale = "medium",
                       returnclass = "sf") 

#I use the Alaska albers projection for this map,
#limit extent (https://spatialreference.org/ref/epsg/nad83-alaska-albers/)
xmin <- -2255938
xmax <- 1646517
ymin <- 449981
ymax <- 2676986

#plot
ggplot()+
  geom_sf(data=world, color="black", size=1)+
  coord_sf(crs=3338)+
  xlim(c(xmin,xmax))+ylim(c(ymin,ymax))+
  theme_bw()

谢谢!

7fyelxc5

7fyelxc51#

简短回答

EPSG:3338是问题所在-使用UTM(326 XX或327 XX)代码代替。

长答案

我的直觉是,这与将地理(经纬度)数据投影到平面上的挑战有关--投影的CRS,或者更简单地说,RStudio中绘图查看器窗格的平面。
我们知道,在地球的椭球模型中,-179和+179经度之间的(最小)地面距离与-1和+1经度之间的距离相同,为2度,但从数值Angular 来看,这两条经度线之间的距离为358度。
假设你是一个外星人(或者是一个平面地球),看着world的投影,你不知道地球是椭圆形的(或者你不知道这是一个投影),你会认为从俄罗斯的一个地方(红色)到另一个地方,你必须淋湿,我猜默认情况下,ggplot是一个平面地球。

假设上图中的每个多边形都是拼图的一部分。在你的图中,我猜你将原点设置为EPSG:3338(coord_sf(crs = 3338))的中心,我认为它在阿拉斯加/加拿大的某个地方?(我在这里猜测,因为我不使用这种符号,而是我更喜欢在发送到ggplot之前转换数据)。无论如何,ggplot知道它应该重新排列它的“拼图块”,所以经度-179和+179是彼此相邻的-但这是纯粹的视觉效果,就像你的图一样:

因此,我的猜测是,当你尝试使用st_union()st_simplify()时,多边形实际上在空间上并不相邻,因此没有连接。这就是投影CRS应该解决的问题,将坐标转换为相对于原点的值,而不是(长0,纬度0)。
我认为这是一个麻烦的来源-快速谷歌EPSG:3338说这是阿拉斯加的好,但没有提到俄罗斯。当我谷歌“utm俄罗斯”的第一件事是EPSG:32635。所以,让我们看看EPSG代码4326(WGS 84经度),3338(NAD 83阿拉斯加)和32635的经度值。

# pull out russia
world %>% 
  filter(
    str_detect(name_long, 'Russia')
  ) %>% 
  select(name_long, geometry) %>% 
  {. ->> russia}

# extract coords of each projection
russia %>% 
  st_transform(3338) %>% 
  {. ->> russia_3338} %>% 
  st_coordinates %>% 
  as_tibble %>% 
  select(X) %>% 
  mutate(
    crs = 'utm_3338'
  ) %>% 
  {. ->> russia_coords_3338}

russia %>% 
  st_transform(4326) %>% 
  {. ->> russia_4326} %>% 
  st_coordinates %>% 
  as_tibble %>% 
  select(X) %>% 
  mutate(
    crs = 'utm_4326'
  ) %>% 
  {. ->> russia_coords_4326}

russia %>% 
  st_transform(32635) %>% 
  {. ->> russia_32635} %>% 
  st_coordinates %>% 
  as_tibble %>% 
  select(X) %>% 
  mutate(
    crs = 'utm_32635'
  ) %>% 
  {. ->> russia_coords_32635}

让我们将它们组合起来,然后查看经度值的直方图

# inspect X coords on a histogram
bind_rows(
  russia_coords_3338,
  russia_coords_4326,
  russia_coords_32635,
) %>% 
  ggplot(aes(X))+
  geom_histogram()+
  facet_wrap(~crs, ncol = 1, scales = 'free')

因此,正如您所看到的,投影4326和3338在地球的两端具有两组不同的坐标,其中有一个大的中断(跨度x = 0)之间。虽然投影32635只有一组坐标,这表明俄罗斯的两个部分,根据这个投影,投影32635的工作原理是因为它将坐标转换为“距原点的(最小?)距离”;其原点(与经纬度坐标不同)不在地球的另一端,并且不需要绕地球仪两个不同的方向来确定到国家两端的最小距离(这是导致其他两个投影的经度坐标断裂的原因)。我对EPSG:3338了解不够,无法解释其为什么也会发生这种情况,但我怀疑是因为它以阿拉斯加为重点,所以他们没有考虑跨越180度经线。
如果我们绘制russia_32635,我们可以看到这两个多边形是相邻的,但是记住我们现在还不信任ggplot。当我们使用st_simplify()时,这条日期线(红色)消失了,证明这两个多边形是相邻的,可以简化/合并。

ggplot()+
  geom_sf(data = russia_32635, colour = 'red')+
  geom_sf(data = russia_32635 %>% st_simplify, fill = NA)

st_simplify()已经融合了日期变更线上的2个边界,从而将单个多边形的数量从100个减少到98个。

russia_32635 %>% 
  st_cast('POLYGON')

# Simple feature collection with 100 features and 1 field
# Geometry type: POLYGON
# Dimension:     XY
# Bounding box:  xmin: 21006.08 ymin: 4772449 xmax: 6273473 ymax: 13233690
# Projected CRS: WGS 84 / UTM zone 35N

russia_32635 %>% 
  st_simplify %>% 
  st_cast('POLYGON')

# Simple feature collection with 98 features and 1 field
# Geometry type: POLYGON
# Dimension:     XY
# Bounding box:  xmin: 21006.08 ymin: 4772449 xmax: 6273473 ymax: 13233690
# Projected CRS: WGS 84 / UTM zone 35N

或者,看起来st_union(..., by_feature = TRUE)也可以工作-请参见?st_union
如果by_feature为TRUE,则每个特征几何体都是联合的。例如,这可用于在使用st_combine组合多边形之后解析内部边界。

russia_32635 %>% 
  st_union(by_feature = TRUE) %>% 
  st_cast('POLYGON')

# Simple feature collection with 98 features and 1 field
# Geometry type: POLYGON
# Dimension:     XY
# Bounding box:  xmin: 21006.08 ymin: 4772449 xmax: 6273473 ymax: 13233690
# Projected CRS: WGS 84 / UTM zone 35N

所以,从技术上讲,你的俄罗斯Map上没有日期变更线。我认为俄罗斯Map很难绘制,因为a)它靠近两极,b)它覆盖了如此广阔的地区,这意味着大多数预测都会从国家的一端倾斜到另一端。
然而对我来说,将绘图定向为“北向上”是有意义的。一种方法是制作你自己的“Mollweide”投影,并将原点指定为俄罗斯的大致中心(lon 99,lat 65)。如果没有st_buffer(0),出于某种原因,这将使用日期变更线绘图(参见herehere的示例,以及此处的第6.5节的解释)。

my_proj <- '+proj=moll +lon_0=99 +lat_0=65 +units=m'

russia_32635 %>% 
  st_buffer(0) %>% 
  st_transform(crs(my_proj)) %>%
  st_simplify %>% 
  ggplot()+
  geom_sf()

奖金

我试着用tmapleaflet绘制russia_32635 %>% st_simplify,但是没有得到想要的结果,我想这是因为这些软件包更喜欢地理坐标;leaflet只接受longlat,虽然tmap可以处理投影数据,但我猜它会将投影数据转换(或类似转换)为首选投影。如果您真的需要这种可视化效果,可以在上面的链接中找到解决方法(hereherehere)。

library(tmap)

russia_32635 %>% 
  st_simplify %>% 
  tm_shape()+
  tm_polygons()

library(leaflet)

russia_32635 %>% 
  st_simplify %>%
  st_transform(4326) %>% # because leaflet only works with longlat projections
  leaflet %>% 
  addTiles %>% 
  addPolygons()

第一节第五节第一节第六节第一节

最终,在投影数据时只能保留2/3的主要特征:区域、方向或距离。当投影像俄罗斯这样大而极地的东西时,这一点会变得更加明显。希望这些选项中有一个适合你的问题。

ffx8fchx

ffx8fchx2#

我觉得我取得了重大进展,所以我张贴,但这不是一个完整的答案。

# This is the portion containing the international dateline
df <- world[184, ]
# Split MULTIPOLYGON into individuals
df2 <- st_cast(df, "POLYGON")
# The little blob at the top is in df2[36, ] and df[38, ]
# Simplify it with the right tolerance and the line is gone
ggplot()+
  geom_sf(data=st_simplify(st_union(df2[36, ], df2[38, ]), dTolerance = 2), color="black", size=1)+
  coord_sf(crs=3338)+
  xlim(c(xmin,xmax))+ylim(c(ymin,ymax))+
  theme_bw()

结果:

oaxa6hgo

oaxa6hgo3#

另一种解决方案是使用rmapshaper包中的ms_dissolve()

chukotka %>% 
st_transform(32660) %>% 
rmapshaper::ms_dissolve() %>% 
ggplot()+
geom_sf()

相关问题