如何用osmdata与ggplot2实现海洋/陆地填充?osm_line2poly报错求解
如何用{osmdata}和{ggplot2}实现海洋/陆地区域填充?
问题背景
需求是通过{osmdata}和{ggplot2}绘制包含海洋、陆地区域填充的地图,但实际操作中遇到阻碍:
- OpenStreetMap将海岸线存储为线条对象,{osmplotr}文档提及的
osm_line2poly()转换函数调用时报错:osmplotr::osm_line2poly(coast$osm_lines, bb) #> Error in FUN(X[[i]], ...): unbenutztes Argument (V = c(3, 1, 6, 7, 2, NA, 5)) - {tigris}包仅能提供美国区域的多边形数据,无法满足通用区域需求。
尝试的代码示例:
library(osmdata) library(osmplotr) library(sf) library(tidyverse) # define example bbox bb <- tribble( ~xy, ~min, ~max, "x", 12.00, 12.18, "y", 54.08, 54.20 ) %>% column_to_rownames("xy") %>% as.matrix() # get "water" water <- opq(bb) %>% add_osm_feature(key = "natural", value = "water") %>% osmdata_sf() # get "coastline" coast <- opq(bb) %>% add_osm_feature(key = "natural", value = "coastline") %>% osmdata_sf() # ggplot ggplot() + geom_sf( data = water$osm_multipolygons, fill = "navy", color = NA ) + geom_sf( data = coast$osm_lines, fill = "navy", color = "blue" )
解决方案
方案1:基于{sf}空间运算的通用方法
无需依赖{osmplotr},直接通过{sf}的差集运算生成海洋区域,步骤如下:
- 获取陆地多边形数据
OSM中natural=land标签对应陆地区域,直接获取:
land <- opq(bb) %>% add_osm_feature(key = "natural", value = "land") %>% osmdata_sf()
- 创建边界框多边形
将自定义的bbox转换为空间多边形,作为整个地图的范围基底:
bb_poly <- st_as_sfc(st_bbox(bb))
- 计算海洋区域
通过边界框减去所有陆地的合并多边形,得到海洋区域:
ocean <- st_difference(bb_poly, st_union(land$osm_multipolygons))
- 绘制填充地图
按照海洋→陆地→内陆水的层级顺序绘制,确保视觉正确:
ggplot() + # 填充海洋 geom_sf(data = ocean, fill = "navy", color = NA) + # 填充陆地 geom_sf(data = land$osm_multipolygons, fill = "forestgreen", color = NA) + # 填充内陆水域(湖泊、河流等) geom_sf(data = water$osm_multipolygons, fill = "navy", color = NA) + # 可选:添加海岸线边框 geom_sf(data = coast$osm_lines, color = "blue", size = 0.2) + theme_minimal()
方案2:修复{osmplotr}转换错误
若坚持使用{osmplotr},可尝试以下操作:
- 更新{osmplotr}至最新版本,旧版本可能存在参数兼容问题
- 先将分散的海岸线线条合并为单一多线对象,再调用转换函数:
# 合并海岸线线条为多线对象 coast_combined <- coast$osm_lines %>% st_combine() %>% st_cast("MULTILINESTRING") # 转换为多边形 coast_poly <- osmplotr::osm_line2poly(coast_combined, bb)
内容的提问来源于stack exchange,提问作者Paul Schmidt
相关产品推荐
相关产品推荐

