如何旋转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
相关产品推荐
相关产品推荐

