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

如何旋转ggplot2制作的地图并添加指向正北的指北针?

解决旋转ggplot2地图后添加正北指北针的问题

问题核心在于ggsn::north依赖数据的坐标系,当使用**斜墨卡托(oblique mercator)**投影旋转地图后,坐标系的"向上"方向不再对应地理正北,导致指北针要么消失,要么指向错误。以下是两种可靠的解决方案:

方法一:计算正北角度,旋转自定义指北针

通过计算投影后地理正北在地图中的实际角度,创建并旋转指北针图形,确保其始终指向正北:

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

# 加载并筛选数据
places <- places(state = 42) |> filter(NAME == "Philadelphia")
roads <- roads(state = "42", county = "101") |> filter(RTTYP == "S")

# 定义斜墨卡托投影参数
crs_string <- "+proj=omerc +lat_0=39.95276 +lonc=-75.16340 +alpha=0 +k_0=1 +datum=WGS84 +units=m +no_defs +gamma=-11"

# 计算投影后正北方向的旋转角度
# 1. 获取地图中心点
center <- st_centroid(places)
# 2. 创建地理正北方向的参考点(向北偏移0.1度)
north_geo <- st_sfc(st_point(c(st_coordinates(center)[1], st_coordinates(center)[2] + 0.1)), 
                    crs = st_crs(places))
# 3. 将中心点和正北参考点转换到目标投影
center_proj <- st_transform(center, crs = crs_string)
north_proj <- st_transform(north_geo, crs = crs_string)
# 4. 计算正北方向与图形y轴的夹角(逆时针为正)
vec <- st_coordinates(north_proj) - st_coordinates(center_proj)
north_angle <- atan2(vec[1], vec[2]) * (180/pi)

# 创建自定义指北针图形
north_grob <- grobTree(
  # 绘制箭头头部
  polygonGrob(x = c(0.5, 0.3, 0.5, 0.7), y = c(1, 0.6, 0.5, 0.6), 
              gp = gpar(fill = "black", col = "black")),
  # 绘制箭杆
  linesGrob(x = c(0.5, 0.5), y = c(0, 0.5), gp = gpar(lwd = 2)),
  # 添加正北标识文字
  textGrob("N", x = 0.5, y = 0.8, gp = gpar(fontsize = 12, fontface = "bold"))
)

# 旋转指北针至正北方向
north_grob_rotated <- editGrob(north_grob, vp = viewport(angle = north_angle, clip = "off"))

# 获取投影后地图的边界,设置指北针位置(左上角)
bbox <- st_bbox(st_transform(places, crs = crs_string))
x_min <- bbox[["xmin"]] + 0.02*(bbox[["xmax"]] - bbox[["xmin"]])
y_max <- bbox[["ymax"]] - 0.05*(bbox[["ymax"]] - bbox[["ymin"]])
pin_size <- 0.05*(bbox[["xmax"]] - bbox[["xmin"]])

# 绘制最终地图
ggplot() +
  geom_sf(data = places, fill = NA, color = 'black', linewidth = 1) +
  geom_sf(data = roads, color = "black", linewidth = 1) +
  annotation_custom(north_grob_rotated,
                    xmin = x_min, xmax = x_min + pin_size,
                    ymin = y_max - pin_size, ymax = y_max) +
  coord_sf(datum = NA, crs = crs_string)

方法二:使用ggspatial替代ggsn

ggspatial包的annotation_north_arrow支持直接指定指北针的旋转角度,适配投影后的正北方向,操作更简洁:

library(ggspatial)

# 复用前面计算的north_angle参数
ggplot() +
  geom_sf(data = places, fill = NA, color = 'black', linewidth = 1) +
  geom_sf(data = roads, color = "black", linewidth = 1) +
  annotation_north_arrow(
    location = "tl", # 指北针位置:左上角
    style = north_arrow_fancy_orienteering, # 选择指北针样式
    rotation = north_angle # 旋转至正北角度
  ) +
  coord_sf(datum = NA, crs = crs_string)

关键说明

  • 斜墨卡托投影的gamma参数控制地图旋转角度,本例中gamma=-11意味着地图顺时针旋转了11度,因此需要将指北针逆时针旋转约11度(计算得到的north_angle值与之对应)。
  • ggspatial的指北针工具比ggsn更灵活,支持直接设置旋转角度,是处理投影地图指北针需求的更优选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 00:25:18