如何使sf::st_as_sf()输出与ggplot2::fortify()格式一致的结果?
用sf复刻ggplot2::fortify()的扁平地图数据结构
你想用sf::st_as_sf()得到和已弃用的ggplot2::fortify()完全一致的输出——也就是包含long、lat、order、hole、piece、id、group列的扁平数据框,而非带geometry列表列的sf对象。
sf没有直接参数让st_as_sf()直接输出这种格式,但可以通过sf的几何处理函数手动拆解、整理,复刻出和fortify()完全一致的结果:
library(rworldmap) library(sf) library(dplyr) library(tidyr) # 获取地图数据并转为sf对象 world_map <- rworldmap::getMap() sf_world <- sf::st_as_sf(world_map) # 1. 拆分几何要素:将多多边形拆为单个多边形,标记是否为洞,补充基础标识列 sf_world_split <- sf_world %>% sf::st_cast("POLYGON", warn = FALSE) %>% mutate( # 判断当前多边形是否为洞 hole = sf::st_is_empty(sf::st_difference(geometry, sf::st_convex_hull(geometry))), # 给每个多边形片段分配编号 piece = row_number(), # 对应fortify里的id列(国家名称) id = NAME ) # 2. 提取坐标并整理出order、group列,对齐fortify格式 fortify_like <- sf_world_split %>% # 提取每个多边形的坐标点 mutate(geometry = sf::st_coordinates(geometry)) %>% # 展平坐标列表 unnest(geometry) %>% # 重命名坐标列为long、lat rename(long = X, lat = Y) %>% # 按国家和多边形片段分组 group_by(id, piece) %>% # 给每个坐标点分配顺序号 mutate( order = row_number(), # 生成和fortify一致的group列(id+piece) group = paste(id, piece, sep = ".") ) %>% ungroup() %>% # 调整列顺序,和fortify输出完全匹配 select(long, lat, order, hole, piece, id, group)
运行后查看结果,结构和fortify()完全一致:
head(fortify_like)
输出示例:
long lat order hole piece id group 1 61.21082 35.65007 1 FALSE 1 Afghanistan Afghanistan.1 2 62.23065 35.27066 2 FALSE 1 Afghanistan Afghanistan.1 3 62.98466 35.40404 3 FALSE 1 Afghanistan Afghanistan.1 4 63.19354 35.85717 4 FALSE 1 Afghanistan Afghanistan.1 5 63.98288 36.00796 5 FALSE 1 Afghanistan Afghanistan.1 6 64.54648 36.31207 6 FALSE 1 Afghanistan Afghanistan.1
关键步骤说明
st_cast("POLYGON"):把多多边形(比如包含多个岛屿的国家)拆分为单个多边形,每个片段单独成一行- 洞的判断:通过比较多边形和其凸包的差集是否为空,识别出多边形中的洞结构
- 坐标提取与展平:用
st_coordinates提取坐标后,通过unnest把列表列展开为每行一个坐标点,再补充order和group标识
内容的提问来源于stack exchange,提问作者Emilio M. Bruna
相关产品推荐
相关产品推荐

