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

如何使用sf包围绕多边形放置地理坐标标签?

问题描述

我绘制了如下多边形:

library(ggplot2)
library(sf)
#> Linking to GEOS 3.11.1, GDAL 3.6.2, PROJ 9.1.1; sf_use_s2() is TRUE

poly <- st_polygon(list(rbind(
  c(-90, 70),
  c(-40, 70),
  c(-40, 74),
  c(-90, 74),
  c(-90, 70)
))) |>
  st_sfc() |>
  st_segmentize(5) |>
  st_set_crs(4326) |>
  st_as_sf() |>
  st_transform(3413) |>
  st_cast("POLYGON")

ggplot() +
  geom_sf(data = poly) +
  theme(
    panel.background = element_blank()
  )

绘制出的梯形多边形

请问是否可以设置坐标标签的位置,使其贴合多边形的形状(而非绘图区域的形状)?

解决方案

可以通过提取多边形边界坐标、手动放置标签的方式实现,以下是两种可行方法:

方法1:提取边缘点添加对应标签

先从多边形中提取边界坐标,筛选出左右两侧、上下边缘的关键点,将经纬度坐标转换后作为标签放置在贴合边缘的位置:

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

# 生成原始多边形
poly <- st_polygon(list(rbind(
  c(-90, 70),
  c(-40, 70),
  c(-40, 74),
  c(-90, 74),
  c(-90, 70)
))) |>
  st_sfc() |>
  st_segmentize(5) |>
  st_set_crs(4326) |>
  st_as_sf() |>
  st_transform(3413) |>
  st_cast("POLYGON")

# 提取多边形边界坐标并转换为数据框
poly_coords <- st_coordinates(poly) |>
  as.data.frame() |>
  rename(x = X, y = Y)

# 筛选左右两侧的边缘点
left_edge <- poly_coords |> filter(x == min(x))
right_edge <- poly_coords |> filter(x == max(x))

# 筛选上下边缘的点
bottom_edge <- poly_coords |> filter(y == min(y))
top_edge <- poly_coords |> filter(y == max(y))

# 生成x轴标签数据(转换回WGS84经纬度)
x_label_data <- bind_rows(
  left_edge |> slice(seq(1, nrow(left_edge), length.out = 3)) |> 
    mutate(label = round(st_transform(st_sfc(st_point(c(x,y)), 3413), 4326)[[1]][1], 1)),
  right_edge |> slice(seq(1, nrow(right_edge), length.out = 3)) |> 
    mutate(label = round(st_transform(st_sfc(st_point(c(x,y)), 3413), 4326)[[1]][1], 1))
)

# 生成y轴标签数据
y_label_data <- bind_rows(
  bottom_edge |> slice(seq(1, nrow(bottom_edge), length.out = 3)) |> 
    mutate(label = round(st_transform(st_sfc(st_point(c(x,y)), 3413), 4326)[[1]][2], 1)),
  top_edge |> slice(seq(1, nrow(top_edge), length.out = 3)) |> 
    mutate(label = round(st_transform(st_sfc(st_point(c(x,y)), 3413), 4326)[[1]][2], 1))
)

# 绘图:隐藏默认坐标轴,添加自定义标签
ggplot() +
  geom_sf(data = poly) +
  # 添加x轴标签(偏移避免覆盖多边形)
  geom_text(data = x_label_data, aes(x = x - 50000, y = y, label = label), size = 3) +
  # 添加y轴标签
  geom_text(data = y_label_data, aes(x = x, y = y + 30000, label = label), size = 3) +
  # 隐藏默认坐标轴元素
  theme(
    panel.background = element_blank(),
    axis.text = element_blank(),
    axis.ticks = element_blank(),
    axis.title = element_blank()
  )

方法2:使用annotation_custom手动定位标签

通过st_bbox获取多边形的边界范围,用annotation_custom将标签直接放置在贴合边缘的位置:

library(ggplot2)
library(sf)
library(grid)

# 生成原始多边形(代码同前)
poly <- st_polygon(list(rbind(
  c(-90, 70),
  c(-40, 70),
  c(-40, 74),
  c(-90, 74),
  c(-90, 70)
))) |>
  st_sfc() |>
  st_segmentize(5) |>
  st_set_crs(4326) |>
  st_as_sf() |>
  st_transform(3413) |>
  st_cast("POLYGON")

# 获取多边形边界框
poly_bbox <- st_bbox(poly)

ggplot() +
  geom_sf(data = poly) +
  # 左侧x轴标签
  annotation_custom(
    grob = textGrob(label = "-90", rot = 90, size = 10),
    xmin = poly_bbox[1] - 60000, xmax = poly_bbox[1] - 60000,
    ymin = poly_bbox[2], ymax = poly_bbox[4]
  ) +
  # 右侧x轴标签
  annotation_custom(
    grob = textGrob(label = "-40", rot = 90, size = 10),
    xmin = poly_bbox[3] + 60000, xmax = poly_bbox[3] + 60000,
    ymin = poly_bbox[2], ymax = poly_bbox[4]
  ) +
  # 底部y轴标签
  annotation_custom(
    grob = textGrob(label = "70", size = 10),
    xmin = poly_bbox[1], xmax = poly_bbox[3],
    ymin = poly_bbox[2] - 40000, ymax = poly_bbox[2] - 40000
  ) +
  # 顶部y轴标签
  annotation_custom(
    grob = textGrob(label = "74", size = 10),
    xmin = poly_bbox[1], xmax = poly_bbox[3],
    ymin = poly_bbox[4] + 40000, ymax = poly_bbox[4] + 40000
  ) +
  theme(
    panel.background = element_blank(),
    axis.text = element_blank(),
    axis.ticks = element_blank(),
    axis.title = element_blank()
  )

注意事项

  • 偏移量(如x - 50000)需要根据多边形的实际尺寸调整,确保标签不覆盖图形;
  • 标签显示的是转换回WGS84的经纬度,若需显示投影坐标系的坐标,可直接使用x或y值。

内容的提问来源于Stack Exchange,提问作者Philippe Massicotte

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 15:55:15