在R语言中使用sf包绘制points与multipolygon对象的问题
解决sf包同时绘制Points和Multipolygon的显示问题
我之前也踩过sf base绘图的这个坑,确实会出现图层覆盖、元素丢失或者图例异常的情况,主要是因为sf的原生plot()函数在叠加图层时,默认会重置绘图设备的边界(bbox)和图例设置,导致图层之间的兼容性问题。咱们先复现你的问题代码,再一步步解决:
可复现问题代码
首先还原你提到的场景:
# 加载包 library(sf) library(magrittr) library(RColorBrewer) # 读取并处理nc数据 nc <- st_read(system.file("shape/nc.shp", package="sf")) %>% st_transform(4326) # 创建点sf对象 points_df <- data.frame( lon = c(-78, -79), lat = c(35, 36), p_cut = factor(c("A", "B")) ) points <- st_as_sf(points_df, coords = c("lon", "lat"), crs = 4326)
第一种异常情况:先画点,再叠加面
plot(points["p_cut"]) plot(st_geometry(nc), add = TRUE) # 结果:面元素不显示,因为绘图边界被点的范围限制了
第二种异常情况:先画面,再叠加点
plot(st_geometry(nc)) plot(points["p_cut"], add = TRUE) # 结果:点和图例丢失,因为叠加时没有保留点的图例设置,且可能点的范围超出了面的初始bbox
解决方案
方法1:用ggplot2 + ggspatial(推荐,最稳定)
ggplot的图层系统对sf对象的支持非常友好,能完美控制图层顺序、边界和图例,不会出现base plot的兼容性问题:
library(ggplot2) library(ggspatial) ggplot() + # 先画多边形底图 geom_sf(data = nc, fill = "lightgray", color = "white", linewidth = 0.3) + # 再画点图层,绑定颜色映射 geom_sf(data = points, aes(color = p_cut), size = 3) + # 设置颜色调色板(用你提到的RColorBrewer) scale_color_brewer(palette = "Set1") + # 可选:添加比例尺和指北针 annotation_scale(location = "bl") + annotation_north_arrow(location = "tr", style = north_arrow_fancy_orienteering) + theme_minimal()
这种方式会自动计算所有图层的合并边界,图层顺序明确,图例也能正常显示,完全避免你遇到的问题。
方法2:修复base plot的问题
如果坚持使用base plot,需要手动控制绘图边界和图例:
# 计算所有元素的合并边界(同时包含面和点) combined_bbox <- st_bbox(c(st_geometry(nc), st_geometry(points))) # 转换为sf对象方便提取范围 combined_bbox_sfc <- st_as_sfc(combined_bbox) # 先画多边形,设置xlim和ylim为合并边界 plot(st_geometry(nc), xlim = combined_bbox[c("xmin", "xmax")], ylim = combined_bbox[c("ymin", "ymax")], col = "lightgray", border = "white") # 叠加点图层,指定add=TRUE,同时设置点样式 plot(points["p_cut"], add = TRUE, pch = 19, # 点形状 cex = 1.5) # 点大小 # 手动添加图例(因为base plot叠加时不会自动保留点的图例) legend("bottomright", legend = levels(points$p_cut), col = brewer.pal(length(levels(points$p_cut)), "Set1"), pch = 19, title = "p_cut")
这里的关键是手动设置合并的bbox,确保绘图范围包含所有元素,同时手动添加图例解决叠加时的图例丢失问题。
额外说明
你提到的“随机成功、结果受窗口大小影响”,本质是因为base plot的sf绘图会根据当前窗口大小自动调整bbox,偶尔刚好包含了所有元素,但这种情况不可控。而ggplot的方法完全不会受窗口大小影响,始终能正确显示所有图层。
内容的提问来源于stack exchange,提问作者noriega
相关产品推荐
相关产品推荐

