R 4.3.2中不用ggsn,ggmap+ggspatial添加比例尺报错求助
解决ggspatial::annotation_scale在ggmap生成的地图上报错问题
问题原因
你遇到的错误源于ggmap返回的ggplot对象使用旧版CoordMap坐标系,而ggspatial::annotation_scale对该坐标系的支持不完善,无法自动计算比例尺参数。
解决方案1:改用sf格式绘制地图(推荐)
将地图转换为sf对象,使用ggplot2的coord_sf()坐标系,让ggspatial工具能正确识别并计算比例尺:
library(ggplot2) library(ggmap) library(ggspatial) library(sf) # 获取地图并转换为sf格式 cy <- c(left = 32.2, bottom = 34.5, right = 34.8, top = 35.8) CY_map_sf <- get_stadiamap(cy, zoom = 10, maptype = "stamen_terrain") %>% ggmap::get_map_data() %>% sf::st_as_sf(coords = c("lon", "lat"), crs = 4326) %>% sf::st_bbox() %>% sf::st_as_sfc() %>% sf::st_sf() # 准备点位数据并转为sf格式 long <- c(33.0, 33.5) lat <- c(34.75, 35.0) df <- data.frame(long, lat) %>% sf::st_as_sf(coords = c("long", "lat"), crs = 4326) # 绘制地图并添加图层 ggCY <- ggplot() + geom_sf(data = CY_map_sf, fill = "transparent") + ggspatial::annotation_map_tile(type = "stamen_terrain", zoom = 10, cachedir = tempdir()) + geom_sf(data = df, color = "red", size = 3.5) + xlab("Longitude (°E)") + ylab("Latitude (°S)") + theme(axis.text.x = element_text(size = 20), axis.text.y = element_text(size = 20), axis.title.x = element_text(size = 26), axis.title.y = element_text(size = 26), legend.title=element_text(size=15), legend.text=element_text(size=15), legend.position = c(0.93, 0.13)) + scale_color_gradientn(colours = c('#5749a0', '#0f7ab0', '#00bbb1', '#bef0b0', '#fdf4af', '#f9b64b', '#ec840e', '#ca443d', '#a51a49')) # 添加指北针和比例尺 ggCY_final <- ggCY + ggspatial::annotation_north_arrow( location = "tl", pad_x = unit(0.4, "in"), pad_y = unit(0.4, "in"), style = ggspatial::north_arrow_nautical( fill = c("grey40", "white"), line_col = "grey20", text_family = "ArcherPro Book" ) ) + ggspatial::annotation_scale(location = "bl", width_hint = 0.5) ggCY_final
说明:使用annotation_map_tile直接加载Stamen瓦片,配合sf坐标系,可让ggspatial自动适配比例尺计算逻辑。
解决方案2:手动添加比例尺(适配原ggmap代码)
如果不想切换sf格式,可通过计算经纬度与实际距离的转换关系,手动绘制比例尺:
library(ggplot2) library(ggmap) library(ggspatial) library(grid) # 原代码生成地图 cy <- c(left = 32.2, bottom = 34.5, right = 34.8, top = 35.8) CY_map <- get_stadiamap(cy, zoom = 10, maptype = "stamen_terrain") %>% ggmap() long <- c(33.0, 33.5) lat <- c(34.75, 35.0) df <- data.frame(long, lat) ggCY <- CY_map + geom_point(data = df, aes(x = long, y = lat), col="red", size = 3.5) + xlab("Longitude (°E)") + ylab("Latitude (°S)") + theme(axis.text.x = element_text(size = 20), axis.text.y = element_text(size = 20), axis.title.x = element_text(size = 26), axis.title.y = element_text(size = 26), legend.title=element_text(size=15), legend.text=element_text(size=15), legend.position = c(0.93, 0.13)) + scale_color_gradientn(colours = c('#5749a0', '#0f7ab0', '#00bbb1', '#bef0b0', '#fdf4af', '#f9b64b', '#ec840e', '#ca443d', '#a51a49')) + ggspatial::annotation_north_arrow( location = "tl", pad_x = unit(0.4, "in"), pad_y = unit(0.4, "in"), style = ggspatial::north_arrow_nautical( fill = c("grey40", "white"), line_col = "grey20", text_family = "ArcherPro Book" ) ) # 计算当前纬度下,10公里对应的经度差(35°纬度处,1经度≈88.5公里) km_per_degree_lon <- 111.32 * cos(35 * pi/180) degree_for_10km <- 10 / km_per_degree_lon # 创建自定义比例尺grob scale_grob <- grobTree( segmentsGrob( x0 = unit(0.05, "npc"), y0 = unit(0.05, "npc"), x1 = unit(0.05 + degree_for_10km/(cy["right"] - cy["left"]), "npc"), y1 = unit(0.05, "npc"), gp = gpar(lwd = 2, col = "black") ), textGrob( label = "10 km", x = unit(0.05 + degree_for_10km/(2*(cy["right"] - cy["left"])), "npc"), y = unit(0.03, "npc"), gp = gpar(fontsize = 12) ) ) # 添加手动比例尺 ggCY_final <- ggCY + annotation_custom(scale_grob) ggCY_final
说明:通过地理公式计算经纬度与公里数的转换关系,手动绘制固定长度的比例尺,无需修改原有ggmap绘图逻辑。
内容的提问来源于stack exchange,提问作者ΚΩΝΣΤΑΝΤΙΝΟΣ ΠΑΝΑΓΙΩΤΟΥ
相关产品推荐
相关产品推荐

