R中跨180°国际日期变更线的凸包绘制与面积计算
解决跨国际日期变更线凸包绘制异常问题
核心问题原因:
- 你使用的
map_data("world2")返回的是经度范围为0360的太平洋中心底图,而原始点位经度范围是-180180,二者坐标系逻辑不统一,导致凸包计算和绘图时出现跨线截断问题 - 直接对WGS84地理坐标系下的跨线点计算凸包,会默认按-180~180的经度顺序连线,不会自动适配太平洋中心的展示需求
修正后完整实现代码
1. 导入依赖包
library(tidyverse) library(maps) library(ggmap) library(sf) library(sp) library(rnaturalearth) library(rnaturalearthdata) library(ggspatial) library(mapproj)
2. 生成物种出现数据并统一经度逻辑
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))) # 将负经度转换为0~360范围,和world2底图对齐 df$longitude <- ifelse(df$longitude < 0, df$longitude + 360, df$longitude)
3. 绘制太平洋中心底图
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))
4. 构建sf对象并计算凸包
# 生成sf对象,指定WGS84坐标系 species.sf <- df %>% st_as_sf(coords = c("longitude", "latitude"), crs = 4326) # 计算凸包,不需要提前调用st_wrap_dateline hull <- species.sf %>% summarise(geometry = st_combine(geometry)) %>% st_convex_hull() # 提取凸包坐标点用于ggplot绘图,避免sf图层自动转换坐标系 hull_coords <- st_coordinates(hull) %>% as.data.frame()
5. 叠加点位和凸包绘制
map + geom_point(data = df, aes(x = longitude, y = latitude), size = 2, col = "red") + geom_polygon(data = hull_coords, aes(x = X, y = Y), fill = "blue", alpha = 0.2, col = "blue")
6. 计算准确凸包面积
# 转换为等面积投影(中心设置为研究区域中心)后计算面积,返回结果单位为平方米 hull_proj <- st_transform(hull, crs = "+proj=laea +lon_0=180 +lat_0=0") st_area(hull_proj)
修正说明
- 统一了点位和底图的经度范围为0~360,避免跨线时的逻辑冲突
- 提取凸包的坐标点用
geom_polygon绘制,规避了geom_sf默认适配-180~180坐标系的问题 - 面积计算时转换为等面积投影,数值准确性更高
内容的提问来源于stack exchange,提问作者Gemma Galbraith
相关产品推荐
相关产品推荐

