You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非格林尼治中心的sf对象如何使用geom_segment或geom_spatial_segment?

在ggplot2的geom_sf地图中添加路径:非格林尼治中心/不同CRS下的解决方案

我想在ggplot2的geom_sf生成的地图里添加路径,熟悉以格林尼治为中心的标准地图绘制,但更改地图CRS后,常规方法就失效了。

正常工作的格林尼治中心地图

这段代码可在格林尼治中心的WGS84(EPSG:4326)地图上正常绘制点和路径:

point_df=data.frame(
  location=c('Tokyo','Brasilia','France'),
  lat=c(35.65,-15.79,48.86),
  long=c(139.84,-47.88,2.35)
)
point_df2=data.frame(
  from_location=c('Tokyo','Brasilia'),
  from_lat=c(35.65,-15.79),
  from_long=c(139.84,-47.88),
  to_location=c('France'),
  to_lat=c(48.86),
  to_long=c(2.35)
)

library("rnaturalearth")
world <- ne_countries(scale = "medium", returnclass = "sf")
transpoint = st_as_sf(point_df,coords=c("long","lat"),crs=4326)
world_sf <- st_transform(world, crs=4326)

ggplot(world_sf)+geom_sf()+
  geom_point(data=transpoint,aes(geometry=geometry,color=location),stat="sf_coordinates")+
  geom_text_repel(data=transpoint,aes(geometry=geometry,label=location),stat="sf_coordinates")+
  geom_curve(data=point_df2,aes(x=from_long,y=from_lat,xend=to_long,yend=to_lat),colour='blue')

(对应效果:格林尼治中心地图,点和路径均正常显示)

失效场景:非格林尼治中心或不同CRS的地图

但换成以太平洋为中心的地图或椭圆投影地图时,原有方法完全失效。

基于sf::st_break_antimeridian()的太平洋中心地图

针对太平洋中心地图,改编代码后geom_point可正常工作,但geom_segment完全失效:

robinson <- "+proj=robin +lon_0=-90 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"

world_pac <- world_sf %>%
  st_break_antimeridian(lon_0 = -90) %>% 
  st_transform(crs = robinson)

transpoint = st_as_sf(point_df,coords=c("long","lat"),crs=4326)
dtran = st_transform(transpoint,robinson)
library(ggrepel)
ggplot(world_pac)+geom_sf()+
  geom_point(data=dtran,aes(geometry=geometry,color=location),stat="sf_coordinates")+
  geom_text_repel(data=dtran,aes(geometry=geometry,label=location),stat="sf_coordinates")+
  geom_segment(data=point_df2, aes(x=from_long,y=from_lat,xend=to_long,yend=to_lat),colour='blue')

(对应效果:太平洋中心地图使用geom_segment,路径完全不显示)

尝试使用ggspatial::geom_spatial_segment()能显示线段,但效果异常:

ggplot(world_pac)+geom_sf()+
  geom_point(data=dtran,aes(geometry=geometry,color=location),stat="sf_coordinates")+
  geom_text_repel(data=dtran,aes(geometry=geometry,label=location),stat="sf_coordinates")+
  geom_spatial_segment(data=point_df2, aes(x=from_long,y=from_lat,xend=to_long,yend=to_lat),crs=4326,wrap_dateline = FALSE,colour='blue')

(对应效果:太平洋中心地图使用geom_spatial_segment,路径穿过地图边缘,显示异常)

椭圆投影地图(CRS=2163)

转换为CRS=2163时,geom_segment和geom_spatial_segment都无法正常工作:

world_ellipse <- world_sf %>%
  st_transform(crs=2163)

transpoint = st_as_sf(point_df,coords=c("long","lat"),crs=4326)
dtran = st_transform(transpoint,crs=2163)

ggplot(world_ellipse)+geom_sf()+
  geom_point(data=dtran,aes(geometry=geometry,color=location),stat="sf_coordinates")+
  geom_text_repel(data=dtran,aes(geometry=geometry,label=location),stat="sf_coordinates")+
geom_spatial_segment(data=point_df2,aes(from_long, from_lat, xend = to_long, yend = to_lat),crs = 2163,wrap_dateline = FALSE)

(对应效果:椭圆投影地图使用geom_spatial_segment,路径显示异常)

问题核心与解决方案

你忽略的关键点

  1. CRS不匹配:地图转换为目标CRS后,仍用WGS84经纬度直接绘制路径,坐标系统不兼容导致路径无法正确映射。
  2. 跨日界线处理缺失:太平洋中心地图跨越日界线,常规线段绘制不会自动拆分路径,导致穿模或不显示。
  3. 参数错误:椭圆投影场景中,geom_spatial_segment的crs参数应传入原始数据的WGS84(4326),而非目标地图的2163。

通用解决方案:将路径转换为sf的LINESTRING对象,统一CRS

正确做法是先把路径数据转为sf的LINESTRING类型,再和地图统一转换到目标CRS,让geom_sf直接识别绘制。

步骤1:将路径数据转换为sf的LINESTRING

# 生成路径的LINESTRING对象
paths_sf <- point_df2 %>%
  rowwise() %>%
  mutate(geometry = st_linestring(rbind(c(from_long, from_lat), c(to_long, to_lat)))) %>%
  st_sfc(crs = 4326) %>%
  st_sf()

步骤2:太平洋中心地图适配

对路径进行日界线拆分后转换CRS:

robinson <- "+proj=robin +lon_0=-90 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"

# 拆分路径日界线并转换CRS
paths_pac <- paths_sf %>%
  st_break_antimeridian(lon_0 = -90) %>%
  st_transform(crs = robinson)

# 绘制地图
ggplot(world_pac) +
  geom_sf() +
  geom_point(data=dtran,aes(geometry=geometry,color=location),stat="sf_coordinates") +
  geom_text_repel(data=dtran,aes(geometry=geometry,label=location),stat="sf_coordinates") +
  geom_sf(data = paths_pac, color = "blue")

步骤3:椭圆投影(CRS=2163)适配

直接将路径转换到目标CRS即可:

# 转换路径到2163 CRS
paths_ellipse <- paths_sf %>%
  st_transform(crs = 2163)

# 绘制地图
ggplot(world_ellipse) +
  geom_sf() +
  geom_point(data=dtran,aes(geometry=geometry,color=location),stat="sf_coordinates") +
  geom_text_repel(data=dtran,aes(geometry=geometry,label=location),stat="sf_coordinates") +
  geom_sf(data = paths_ellipse, color = "blue")

额外提示:曲线路径替代方案

如果需要曲线路径,可使用ggforce::geom_bezier配合转换后的sf点坐标,核心依然是先统一CRS。


内容的提问来源于stack exchange,提问作者hamagust

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 08:31:10