数据框经纬度投影至Mollweide时全部点聚集于原点的问题排查
解决Mollweide投影下数据点聚集于原点的问题
问题概况
- 需求:将古颚类(Palaeognathae)的occurrence数据坐标转换到Mollweide投影下绘图
- 现象:
- 单独绘制无数据点的Mollweide投影地图显示正常
- 未设置投影时,数据点能正常显示在对应地理位置
- 添加数据后,所有点聚集在地图原点(0,0)附近
- 尝试过的操作:使用
coord_sf(crs = "+proj=moll")但未解决问题
核心原因
地图与数据的坐标参考系统(CRS)不匹配:
- 若提前用
st_transform将地图转换为Mollweide投影,地图的坐标已变为该投影下的平面坐标 - 但原始数据还是普通数据框中的WGS84经纬度(EPSG:4326),直接用
geom_point添加时,ggplot会把经纬度值当成Mollweide投影的坐标值,由于两种坐标的范围完全不同,所有点会被错误映射到原点附近
解决方案
方法一:将数据转换为sf对象并统一投影
把原始数据框转为sf空间对象,先设置正确的原始CRS,再转换到Mollweide投影,最后用geom_sf绘制点:
library(tidyverse) library(sf) library(rnaturalearth) library(rnaturalearthdata) library(ggthemes) # 加载地图数据 world <- ne_countries(scale = "medium", returnclass = "sf") # 加载并处理古颚类数据 ratites <- read_csv("Palaeognathae_Occurance_dataRevised.csv") # 替换为你的数据文件路径 Ratite_C <- ratites %>% select(accepted_name, Longitude, latitude, early_interval, cc) %>% # 转换为sf对象,设置原始CRS为WGS84 st_as_sf(coords = c("Longitude", "latitude"), crs = 4326) %>% # 统一转换到Mollweide投影 st_transform(crs = "+proj=moll") # 按时间区间拆分数据 Cret <- Ratite_C %>% filter(early_interval == "Cretaceous") Paleo <- Ratite_C %>% filter(early_interval == "Paleocene") Eoc <- Ratite_C %>% filter(early_interval == "Eocene") Oligo <- Ratite_C %>% filter(early_interval == "Oligocene") Mioc <- Ratite_C %>% filter(early_interval == "Miocene") Plio <- Ratite_C %>% filter(early_interval == "Pliocene") Pleis.Holo <- Ratite_C %>% filter(early_interval %in% c("Pleistocene", "Holocene")) # 转换地图到Mollweide投影 world_moll <- world %>% st_transform(crs = "+proj=moll") # 绘图 R.Smap <- ggplot() + geom_sf(data = world_moll, color = "black", fill = "white") + geom_sf(data = Cret, size = 3, shape = 23, fill = "orange") + geom_sf(data = Paleo, size = 3, shape = 21, fill = "lightblue") + geom_sf(data = Eoc, size = 3, shape = 21, fill = "goldenrod4") + geom_sf(data = Oligo, size = 3, shape = 21, fill = "yellow") + geom_sf(data = Mioc, size = 3, shape = 21, fill = "purple") + geom_sf(data = Plio, size = 3, shape = 21, fill = "green") + geom_sf(data = Pleis.Holo, size = 2, shape = 21, fill = "cyan") + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.background = element_rect(fill = 'azure2')) R.Smap
方法二:用coord_sf统一设置全局投影(更简便)
无需提前转换地图和数据的CRS,直接在ggplot中用coord_sf指定目标投影,ggplot会自动完成所有图层的投影转换:
library(tidyverse) library(sf) library(rnaturalearth) library(rnaturalearthdata) library(ggthemes) # 加载地图数据 world <- ne_countries(scale = "medium", returnclass = "sf") # 加载并处理古颚类数据 ratites <- read_csv("Palaeognathae_Occurance_dataRevised.csv") # 替换为你的数据文件路径 Ratite_C <- ratites %>% select(accepted_name, Longitude, latitude, early_interval, cc) # 按时间区间拆分数据 Cret <- Ratite_C %>% filter(early_interval == "Cretaceous") Paleo <- Ratite_C %>% filter(early_interval == "Paleocene") Eoc <- Ratite_C %>% filter(early_interval == "Eocene") Oligo <- Ratite_C %>% filter(early_interval == "Oligocene") Mioc <- Ratite_C %>% filter(early_interval == "Miocene") Plio <- Ratite_C %>% filter(early_interval == "Pliocene") Pleis.Holo <- Ratite_C %>% filter(early_interval %in% c("Pleistocene", "Holocene")) # 绘图,通过coord_sf统一设置Mollweide投影 R.Smap <- ggplot() + geom_sf(data = world, color = "black", fill = "white") + geom_point(data = Cret, aes(x = Longitude, y = latitude), size = 3, shape = 23, fill = "orange") + geom_point(data = Paleo, aes(x = Longitude, y = latitude), size = 3, shape = 21, fill = "lightblue") + geom_point(data = Eoc, aes(x = Longitude, y = latitude), size = 3, shape = 21, fill = "goldenrod4") + geom_point(data = Oligo, aes(x = Longitude, y = latitude), size = 3, shape = 21, fill = "yellow") + geom_point(data = Mioc, aes(x = Longitude, y = latitude), size = 3, shape = 21, fill = "purple") + geom_point(data = Plio, aes(x = Longitude, y = latitude), size = 3, shape = 21, fill = "green") + geom_point(data = Pleis.Holo, aes(x = Longitude, y = latitude), size = 2, shape = 21, fill = "cyan") + coord_sf(crs = "+proj=moll") + # 关键:统一设置投影 theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.background = element_rect(fill = 'azure2')) R.Smap
注意事项
- 避免使用
attach()函数,容易引发变量冲突,优先使用dplyr管道或直接引用数据框 - 确认数据中的
Longitude和latitude是标准WGS84经纬度(经度范围-180180,纬度范围-9090) - 方法二更适合快速绘图,无需手动转换每个数据集的CRS
内容的提问来源于stack exchange,提问作者Aamir
相关产品推荐
相关产品推荐

