我想在ggplot2中添加路径到使用geom_sf生成的 map 中.

我熟悉使用以格林威治为中心的标准 map .但当我改变 map 设计时(?crs.通常的方法失败了.

"正常" map 运行良好

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')

Greenwich centered map

不起作用: map 使用不同的CRS或不在格林威治中心

但是,如果我更喜欢以太平洋为中心的 map ,或者椭圆形 map ,它们就失败了.

pacific centred map with sf::st_break_antimeridian()

对于太平洋中心的 map ,我使用了一个代码, 注意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')


Pacific centered 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')

Pacific centered with geom_spatial_segment

Ellipsis map

我也无法使geom_segment()geom_spatial_segment()工作,如果我转换为crs=2163.


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)


Ellipsis with geom_spatial_segment

我错过了什么? 当我们使用不同的CRS时,如何使用geom_segment()和/或geom_spatial_segment()ggplot2::geom_sf()

推荐答案

解决这个问题的最简单方法是在你的兴趣点之间生成线,然后geom_curve()这些线的从/到点.

我从这个例子中掉了ggrepel分,因为它就像打鼹鼠一样,当涉及到获得满意的结果.我还调整了线的曲率,因为默认值会使法国/东京线从自定义Robinson map 上弯曲.如果这些参数不适合,您可以在必要时调整它们.示例图包含一个箭头选项(注释掉),以防您想演示方向.

这适用于您的定制CRS和EPSG:9311(EPSG:2163的更新版本,已被弃用).要生成EPSG:9311版本的 map ,您需要做的唯一修改是将st_transform(robinson)替换为st_transform(9311).

另外请注意,省略号映射代码中有一个错误.你忽略了geom_text_repel()函数后的"+".可能是复制/粘贴错误,但geom_spatial_segment()仍然不会打印point_df2.但是,它将与在此解决方案中创建的sf_line对象一起工作.

下面是一个完整的工作repex:

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

# Your point data
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))

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

# Create 90W-centred version of ne_countries with custiom CRS
world_pac <- ne_countries(scale = "medium", returnclass = "sf") %>%
  st_break_antimeridian(lon_0 = -90) %>% 
  st_transform(robinson)

# Create sf of your point data
transpoint <- st_as_sf(point_df, coords = c("long","lat"), crs = 4326) %>%
  st_transform(robinson)

# Generate lines between France and the rest
sf_line <- transpoint %>%
  st_set_geometry("to") %>%
  mutate(from = to[location == "France"],
         line_geom = st_union(to, from, by_feature = TRUE)) %>%
  filter(!location == "France") %>%
  st_set_geometry("line_geom") %>%
  st_cast("LINESTRING") %>%
  mutate(x1 = st_coordinates(from)[,1],
         y1 = st_coordinates(from)[,2],
         x2 = st_coordinates(to)[,1],
         y2 = st_coordinates(to)[,2])

#Plot
ggplot() +
  geom_sf(data = world_pac, colour = "grey70") +
  geom_sf(data = transpoint, colour = "#DF536B", size = 3) +
  geom_curve(data = sf_line, 
             aes(x = x1, y = y1, 
                 xend = x2, yend = y2), 
             colour = "#0072B2",
             # arrow = arrow(length = unit(0.03, "npc"), type="closed"),
             curvature = 0.4) +
  geom_sf_text(data = transpoint,
               aes(label = location),
               size = 4,
               fun.geometry = st_centroid,
               vjust = 2,
               colour = "black") +
  theme(axis.title = element_blank())

Custom CRS result: result

EPSG:9311 result: result1

R相关问答推荐

查找满足SpatRaster中条件的单元格位置

是否可以 Select 安装不带文档的R包以更有效地存储?

基于现有类创建类的打印方法(即,打印tibles更长时间)

使用R中的Shapetime裁剪格栅文件

手动打印线型gplot

如何直接从R中的风险分数计算c指数?

如果可能,将数字列转换为整数,否则保留为数字

传递ggplot2的变量作为函数参数—没有映射级别以正确填充美学

使用Scale_*_MANUAL时在图例中保留未使用的系数级别

根据另一列中的值和条件查找新列的值

如何计算R glm probit中的线性预测因子?

如何对r中包含特定(未知)文本的行求和?

我如何使用循环来编写冗余的Rmarkdown脚本?

如何在条形图中的x和填充变量中包含多个响应变量?

如何使用包metaviz更改标签的小数位数?

为什么不能使用lApply在包装函数中调用子集

计算多变量的加权和

如何将图例文本添加到图例符号中

在GT()中的列之间添加空格

如何在分组蜂群小区中正确定位标签