【问题标题】:Plotting convex hulls crossing 180 degree international date line and calculating area绘制跨越 180 度国际日期变更线的凸包并计算面积
【发布时间】:2021-12-24 13:13:14
【问题描述】:

我正在尝试使用凸包绘制物种范围区域,然后计算面积并创建一个图形。

180 度国际日期变更线有一个众所周知的问题,我一直在尝试解决 SE 上的许多示例,例如:

How to remedy a path that crosses the international dateline with R

这接近我的目标,但在 mapview 中绘制的不是 ggplot2: How to construct/plot convex hulls of polygons from points by factor using sf?

这是我的尝试:

library(tidyverse)
library(maps)
library(ggmap)
library(sf)
library(sp)
library(rnaturalearth)
library(rnaturalearthdata)
library(ggspatial)
library(mapproj)

生成物种出现数据,其中一些点跨越 180 经度


df <- data.frame(species = rep("sp1",8),
                 longitude = as.double(c(-170.2, -179.5, 55.9, 167.6, 154.3, 101.7, 70.54, -165.94)),
                  latitude = as.double(c(8.25, -24.75, 24.25,19.25, 33.45, -15.5, 5.56, 4.6)))

来自 map_data 和 plot 的以太平洋为中心的世界地图

world <- map_data("world2") 

map<-ggplot() +
geom_polygon(data = world, aes(x = long, y = lat, group = group),
col = "#78909C", fill = "#78909C", lwd = 0)+
coord_map(orientation = c(90,0, 150), ylim = c(-40, 40), xlim = c(20,210))

my map

向地图添加发生点

map +
geom_point(data = df, mapping = aes(x = longitude, y = latitude))

map with points

根据物种出现数据构造最小凸包。

species.sf <- df %>%
  st_as_sf( coords = c( "longitude", "latitude" ))

创建船体并环绕日期线

hull<- species.sf %>%
  summarise( geometry = st_combine( geometry ) ) %>%
  st_convex_hull()

hull<-st_wrap_dateline(hull,options = c("WRAPDATELINE=YES", "DATELINEOFFSET=180"),
   quiet = TRUE)

绘制船体 - 在 180 处切割,但显然不包括所有出现点


map +
geom_point(data = df, mapping = aes(x = longitude, y = latitude))+
geom_sf(data=hull, inherit.aes = TRUE)

incorrect hull

计算船体面积 - 必须根据船体形状不正确

st_area(hull)

我还尝试将太平洋中心 CRS 应用于地图、点和船体,但怀疑我以错误的顺序或错误的位置应用这些?我对使用 R 进行空间分析非常陌生,所以任何帮助都非常有用。谢谢。

【问题讨论】:

    标签: r ggplot2 maps mapping sf


    【解决方案1】:

    请在下面找到您的问题的解决方案。我使用了 sf 包中的函数 st_shift_longitude()

    Reprex

    • 您的数据(无更改)
    df <- data.frame(species = rep("sp1",8),
                     longitude = as.double(c(-170.2, -179.5, 55.9, 167.6, 154.3, 101.7, 70.54, -165.94)),
                     latitude = as.double(c(8.25, -24.75, 24.25,19.25, 33.45, -15.5, 5.56, 4.6)))
    
    
    
    world <- map_data("world2") 
    
    map<-ggplot() +
      geom_polygon(data = world, aes(x = long, y = lat, group = group),
                   col = "#78909C", fill = "#78909C", lwd = 0) + 
      coord_map(orientation = c(90,0, 150), ylim = c(-40, 40), xlim = c(20,210))
    map
    

    • dataframe“df”转换为sf对象“species.sf”并用st_shift_longitude()移动经度
    species.sf <- df %>% 
      st_as_sf(coords = c("longitude", "latitude"), crs = 4326) %>% 
      st_shift_longitude()
    
    
    map + 
      geom_sf(data = species.sf, inherit.aes = TRUE) + 
      coord_sf(xlim = c(40, 210), ylim = c(-40, 40))
    

    • 基于sf 对象“species.sf”和group_by(species) 计算凸包多边形(适用于您的一般情况)
    hull <- species.sf %>%
      group_by(species) %>% 
      summarise( geometry = st_combine( geometry ) ) %>%
      st_convex_hull()
    
    • sf对象“hull”转换回dataframe对象“hullDF”
    hullDF <- hull %>% 
      st_geometry() %>% 
      st_coordinates() %>% 
      as.data.frame() 
    
    • 最终结果的可视化
    map + 
      geom_point(data = df, mapping = aes(x = longitude, y = latitude)) +
      geom_polygon(data = hullDF, mapping = aes(x = X, y = Y), fill = "lightgreen", alpha = 0.5)
    

    • 计算船体多边形的面积(需要units 库将结果转换为平方千米)
    library(units)
    
    hull_area <- hull %>%  
      st_area() %>% 
      set_units(km^2)
    
    hull_area
    #> 74714882 [km^2]
    

    reprex package (v2.0.1) 于 2021 年 11 月 12 日创建

    【讨论】:

    • 嗨@Gemma Galbraith。我希望以上答案能满足您的需求。如果是这样,请考虑将此答案标记为“已接受”,以便其他 SO 用户更容易找到正确答案。如果没有,请告诉我出了什么问题。干杯
    • 感谢@lovalery,这正是我所追求的解决方案。如果我想向该地图添加其他空间图层,st_shift_longitude() 是否也可以使用?例如来自自然地球包的珊瑚礁矢量?这里的目标不仅是绘制珊瑚礁栖息地的地图,而且还要计算凸壳内珊瑚礁的面积。不过,作为一个单独的问题,这可能会更好。感谢您的帮助!
    • 嗨@Gemma。不客气。很高兴我能提供帮助并感谢您验证答案。总是很难在没有看到数据的情况下制作建设性的 cmets,但是是的,我认为您应该能够使用此处开发的相同方法来实现您的目标。我祝你工作顺利。干杯。
    • 另一个跟进这个问题@lovalery。如果我在发生数据中有多个物种,我将如何将 st_shift_longitude 应用于多个船体?我已经尝试实现 group_by ,它适用于第一步: hulls% group_by(Species) %>% summarise( geometry = st_combine( geometry ) ) %>% st_convex_hull() # 但是,在转变之后出现错误st_crs(hulls) % st_shift_longitude(st_geometry(hulls)) st_shift_longitude(., st_geometry(hulls)) 中的错误:未使用的参数 (st_geometry(hulls))
    • 嗨@Gemma。好的。我分两步给你答案。 1°)您收到的错误消息与您的“整洁”代码中的语法错误有关。为此,%&gt;% st_shift_longitude(st_geometry(hulls)) 部分应修改如下:%&gt;%st_geometry()%&gt;%st_shift_longitude()(此外,括号中不应显示“船体”)。但是,不要进行任何更改,等待第 2 点 ;-)
    猜你喜欢
    • 2021-08-16
    • 2015-07-11
    • 1970-01-01
    • 2022-08-03
    • 2011-08-15
    • 2020-02-16
    • 1970-01-01
    • 2012-03-25
    相关资源
    最近更新 更多