You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用ggplot叠加地图与散点图?(附报错及代码)

问题根源分析

你遇到的object 'longitud' not found报错,本质是ggplot的全局美学映射(aes)继承问题:你的gtomap对象在初始化时设置了全局的x = longitud, y = latitud,当你叠加geom_sf(data=map)时,geom_sf会默认尝试从map数据框中读取这两个变量,但你把sf格式的地图数据转成了普通data.frame,既丢失了空间属性,也没有longitud/latitud列,因此触发报错。

另外,将sf对象转成data.frame是完全不必要的——geom_sf需要直接使用sf类型的数据才能正确渲染地图。


解决方案:两种可行的修正方式

方法1:统一使用SF格式处理空间数据(推荐)

将学校的经纬度数据转为sf对象,和地图数据统一用geom_sf绘制,这样能保证坐标系完全匹配,避免错位问题:

# 加载所需包(新增sf包处理空间数据)
library(foreach)
library(forcats)
library(ggplot2)
library(dplyr)
library(stringr)
library(raster)
library(readr)
library(reshape2)
library(sf)

# 读取学校数据并处理教育水平分类
gto <- read_csv("http://fs.planeacion.sep.gob.mx/cct/cct11.csv")
nivel_ed <- c("Primaria", "Secundaria", "Bachillerato", "Superior")

schools_sf <- subset(gto, select = c(longitud, latitud, nnivel)) %>%
  filter(nnivel %in% c("PRIMARIA", "SECUNDARIA", "BACHILLERATO", 
                       "PEDAGOGICA, UNIVERSITARIA O TECNOLOGICA", "PROFESIONAL")) %>%
  mutate(nnivel = case_when(
    nnivel == "PEDAGOGICA, UNIVERSITARIA O TECNOLOGICA" ~ "Superior",
    nnivel == "PROFESIONAL" ~ "Superior",
    nnivel == "SECUNDARIA" ~ "Secundaria",
    nnivel == "PRIMARIA" ~ "Primaria",
    nnivel == "BACHILLERATO" ~ "Bachillerato"
  )) %>%
  mutate(nnivel = factor(nnivel, levels = nivel_ed)) %>%
  # 将经纬度转为SF对象,指定坐标系为WGS84(EPSG:4326,全球通用地理坐标系)
  st_as_sf(coords = c("longitud", "latitud"), crs = 4326)

# 读取地图数据(保留SF格式,不要转成data.frame)
mapgto <- sf::read_sf("http://geoinfo.iplaneg.net/geoserver/wms/kml?layers=geonode%3Amgm_gto2010&mode=download", quiet = T)

# 绘制叠加图:先画地图底图,再画学校散点
ggplot() +
  geom_sf(data = mapgto, fill = "lightgray", color = "white") +
  geom_sf(data = schools_sf, aes(color = nnivel), size = 0.8) +
  theme_minimal() +
  theme(legend.title = element_blank()) +
  labs(x = "", y = "")

方法2:保留原有散点图,关闭美学映射继承

如果你不想修改原有散点图的代码,可以在geom_sf中设置inherit.aes = FALSE,避免它继承全局的x/y映射,同时保留sf格式的地图数据:

# 保留你原来的gtomap代码
library(foreach)
library(forcats)
library(ggplot2)
library(dplyr)
library(stringr)
library(raster)
library(readr)
library(reshape2)
library(sf)

gto <- read_csv("http://fs.planeacion.sep.gob.mx/cct/cct11.csv")
nivel_ed <- c("Primaria", "Secundaria", "Bachillerato", "Superior")

gtomap <- subset(gto, select = c(longitud, latitud, nnivel)) %>% 
  filter(nnivel %in% c("PRIMARIA", "SECUNDARIA", "BACHILLERATO", 
                       "PEDAGOGICA, UNIVERSITARIA O TECNOLOGICA", "PROFESIONAL")) %>% 
  mutate(nnivel = case_when(
    nnivel == "PEDAGOGICA, UNIVERSITARIA O TECNOLOGICA" ~ "Superior",
    nnivel == "PROFESIONAL" ~ "Superior",
    nnivel == "SECUNDARIA" ~ "Secundaria",
    nnivel == "PRIMARIA" ~ "Primaria",
    nnivel == "BACHILLERATO" ~ "Bachillerato"
  )) %>% 
  mutate(nnivel = factor(nnivel, levels = nivel_ed)) %>% 
  melt(id = c("longitud", "latitud")) %>% 
  mutate(value = factor(value, levels = nivel_ed)) %>% 
  ggplot(aes(x = longitud, y = latitud, col = value)) + 
  geom_point() + 
  theme(legend.title = element_blank()) + 
  labs(x = "", y = "")

# 读取地图数据(保留SF格式)
mapgto <- sf::read_sf("http://geoinfo.iplaneg.net/geoserver/wms/kml?layers=geonode%3Amgm_gto2010&mode=download", quiet = T)

# 叠加地图:关闭继承,添加coord_sf确保坐标系匹配
gtomap + 
  geom_sf(data = mapgto, inherit.aes = FALSE, fill = "lightgray", color = "white") +
  coord_sf()

关键注意事项

  1. 永远不要把sf对象转成普通data.frame——sf对象包含空间坐标系信息,转成data.frame会丢失这些关键数据,导致geom_sf无法识别。
  2. 方法1是更规范的空间数据可视化方式,统一用sf处理能避免坐标系不匹配、图层错位等潜在问题。

内容的提问来源于stack exchange,提问作者Alejandro Carrera

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:28:55