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

使用ggplot绘制栅格地图:栅格单元横竖畸变的原因及解决方法

问题描述

我正在绘制多个已投影的栅格对象(SpatRaster或栅格栈,采用等面积投影EPSG:3035),所有对象范围一致,但绘制出的栅格单元出现水平或垂直畸变(非正方形),或显示尺寸过大。

出现畸变的示例代码:

# 垂直畸变  
ggplot2::ggplot() +
    tidyterra::geom_spatraster(data = terra::rast(ExampleMap[[1]])) +
    paletteer::scale_fill_paletteer_c(na.value = NA, "viridis::plasma")

【对应截图】

# 水平畸变  
ggplot2::ggplot() +
    tidyterra::geom_spatraster(data = terra::rast(ExampleMap[[2]])) +
    paletteer::scale_fill_paletteer_c(na.value = NA, "viridis::plasma")

【对应截图】


为排查问题,我用不同geom绘制单个图层的完整脚本如下:

require(raster)
require(stara)
require(ggplot2)

ExampleMap2 <- ExampleMap[[1]] %>% trim()

使用geom_stars:

ggplot2::ggplot() +
  stars::geom_stars(data = stars::st_as_stars(ExampleMap2)) + 
  ggplot2::coord_equal() +
  ggplot2::theme_void() +
  ggplot2::scale_fill_continuous(na.value = NA) + 
  guides(fill = guide_legend(NULL)) +
  theme(aspect.ratio = 1) + 
  labs(title = "stars::geom_stars")

【对应截图】

使用tidyterra::geom_spatraster:

ggplot2::ggplot() +
  tidyterra::geom_spatraster(data = terra::rast(ExampleMap2)) + 
  ggplot2::theme_void() + 
  ggplot2::scale_fill_continuous(na.value = NA) + 
  guides(fill = guide_legend(NULL)) +
  theme(aspect.ratio = 1) + 
  labs(title = "tidyterra::geom_spatraster")

【对应截图】

使用ggplot2::geom_raster:

DT <- as.data.frame(ExampleMap2, xy = TRUE)

ggplot2::ggplot() + 
  ggplot2::geom_raster(aes(x = x, y = y, fill = as.numeric(as.character(ExampleMap1))), data = DT) + 
  ggplot2::theme_void() +
  ggplot2::scale_fill_continuous(na.value = NA) + 
  guides(fill = guide_legend(NULL)) + 
  coord_equal() +
  theme(aspect.ratio = 1) + 
  labs(title = "ggplot2::geom_raster")

【对应截图】

使用ggplot2::geom_tile(此方法绘图符合预期):

ggplot2::ggplot() + 
  ggplot2::geom_tile(aes(x = x, y = y, fill = as.numeric(as.character(ExampleMap1))), data = DT) + 
  ggplot2::theme_void() +
  ggplot2::scale_fill_continuous(na.value = NA) + 
  guides(fill = guide_legend(NULL)) + 
  coord_equal() + 
  labs(title = "ggplot2::geom_tile")

【对应截图】

请问出现这种畸变的原因是什么?如何在使用tidyterra::geom_spatraster或ggplot2::geom_raster时避免该问题?


问题原因与解决方法

原因分析

  • geom_raster和tidyterra::geom_spatraster默认会自动拉伸栅格单元以填满绘图区域,不会严格遵循栅格原始的宽高比。哪怕设置了theme(aspect.ratio = 1)也没用——这个参数只控制绘图区域的整体宽高比,管不了单个栅格单元的形状。
  • geom_tile则是严格按照数据中x、y对应的栅格单元尺寸绘制,配合coord_equal()强制x、y轴单位长度一致,所以能保证单元是正方形。

解决方法

修复ggplot2::geom_raster的畸变

调用geom_raster时,显式指定hjust和vjust为0.5,同时用栅格的实际分辨率设置width和height参数,再配合coord_equal():

DT <- as.data.frame(ExampleMap2, xy = TRUE)
# 获取栅格的分辨率
res <- terra::res(ExampleMap2)

ggplot2::ggplot() + 
  ggplot2::geom_raster(
    aes(x = x, y = y, fill = as.numeric(as.character(ExampleMap2))), 
    data = DT,
    hjust = 0.5, vjust = 0.5,
    width = res[1], height = res[2]
  ) + 
  ggplot2::theme_void() +
  ggplot2::scale_fill_continuous(na.value = NA) + 
  guides(fill = guide_legend(NULL)) + 
  ggplot2::coord_equal() +
  labs(title = "ggplot2::geom_raster(修正后)")

修复tidyterra::geom_spatraster的畸变

直接使用tidyterra::coord_terra(),它会自动适配SpatRaster的投影和分辨率,保证栅格单元形状正确:

ggplot2::ggplot() +
  tidyterra::geom_spatraster(data = terra::rast(ExampleMap2)) + 
  tidyterra::coord_terra() +
  ggplot2::theme_void() + 
  ggplot2::scale_fill_continuous(na.value = NA) + 
  guides(fill = guide_legend(NULL)) +
  labs(title = "tidyterra::geom_spatraster(修正后)")

也可以用coord_sf配合投影参数:

ggplot2::ggplot() +
  tidyterra::geom_spatraster(data = terra::rast(ExampleMap2)) + 
  ggplot2::coord_sf(datum = sf::st_crs(3035)) +
  ggplot2::coord_equal() +
  ggplot2::theme_void() + 
  ggplot2::scale_fill_continuous(na.value = NA) + 
  guides(fill = guide_legend(NULL)) +
  labs(title = "tidyterra::geom_spatraster(修正后)")

注意:theme(aspect.ratio = 1)可以移除,因为coord_equal()或coord_terra()已经会强制坐标轴单位长度一致,确保栅格单元为正方形。


内容的提问来源于stack exchange,提问作者Ahmed El-Gabbas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 09:15:24