ggmap中geom_polygon列名未识别及sf与底图对齐问题求助
解决方案:ggmap叠加加州郡县分级统计图的对齐与填充问题
我来帮你搞定这个空间可视化的问题,这里有两个靠谱的解决方案,你可以按需选择:
方案一:修复sf对象与ggmap的对齐问题(推荐,sf是R空间数据新标准)
你之前遇到的错位问题,核心是底图和sf对象的坐标系统不匹配:Stamen底图实际使用的是Web Mercator投影(EPSG:3857),而你把sf对象转成了WGS84(EPSG:4326),直接叠加自然会错位。用ggmap_sf()(ggmap专为sf设计的函数)配合坐标转换就能解决,步骤如下:
library(sf) library(ggmap) library(tigris) options(tigris_use_cache = TRUE) # 获取加州郡县sf数据 Counties.sf <- counties(state = "CA", cb = TRUE, resolution = "20m", year = 2016) # 生成模拟的Freq列 Counties.sf$Freq <- sample(10, size=nrow(Counties.sf), replace=TRUE) # 关键:将sf对象转换为与底图一致的Web Mercator投影(EPSG:3857) Counties.sf_3857 <- st_transform(Counties.sf, 3857) # 获取底图,bbox用原始sf的WGS84范围即可,ggmap会自动处理 bbox.sf <- unname(st_bbox(Counties.sf)) my.stamen <- get_stamenmap(bbox=bbox.sf, maptype='terrain-background', zoom=8) # 使用ggmap_sf叠加sf对象,自动对齐坐标系统 ggmap_sf(my.stamen) + geom_sf(data=Counties.sf_3857, aes(fill=factor(Freq)), color='black', inherit.aes = FALSE) + scale_fill_viridis_d(name = "Frequency") # 可选:添加好看的色阶
这样既解决了错位问题,又能正常按Freq列生成分级统计图,而且sf格式在后续的空间分析、数据操作中都更便捷。
方案二:解决SpatialPolygonsDataFrame的填充问题
如果你坚持使用sp格式,报错的原因是geom_polygon无法直接读取SpatialPolygonsDataFrame的属性列,需要先把空间对象转换为长格式数据框,并手动关联属性数据:
library(sf) library(ggmap) library(tigris) library(broom) # 需要用这个包转换sp对象为数据框 options(tigris_use_cache = TRUE) Counties.sf <- counties(state = "CA", cb = TRUE, resolution = "20m", year = 2016) Counties.sf$Freq <- sample(10, size=nrow(Counties.sf), replace=TRUE) Counties.sf <- st_transform(Counties.sf, 4326) # 转换为SpatialPolygonsDataFrame Counties.sp <- as_Spatial(Counties.sf) # 关键:用broom::tidy()把sp对象转为数据框,同时保留唯一标识符(比如GEOID) Counties.sp_df <- broom::tidy(Counties.sp, region = "GEOID") # 将原属性数据(包含Freq)合并到数据框中 Counties.sp_df <- merge(Counties.sp_df, Counties.sp@data, by.x = "id", by.y = "GEOID") # 获取底图 bbox.sf <- unname(st_bbox(Counties.sf)) my.stamen <- get_stamenmap(bbox=bbox.sf, maptype='terrain-background', zoom=8) # 现在可以正常按Freq填充了 ggmap(my.stamen) + geom_polygon(data=Counties.sp_df, aes(x=long, y=lat, group=group, fill=factor(Freq)), color='black') + scale_fill_viridis_d(name = "Frequency")
这里用broom::tidy()将sp对象拆分为长格式数据框,通过唯一的GEOID列把原属性数据(包括Freq)合并进去,这样geom_polygon就能识别到Freq列了。
内容的提问来源于stack exchange,提问作者Avalon
相关产品推荐
相关产品推荐

