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

使用ggplot绘制带数值网格的地图:Lambert投影适配失败求助

实现带Lambert投影的数值网格地图

问题背景

现有一段R语言代码,用于绘制覆盖西经20°至东经40°、北纬30°至70°的50×50数值网格地图,默认投影下运行正常,但切换为Lambert投影时完全失效,需要调整代码以支持Lambert投影。

原默认投影代码:

# Install and load necessary packages. Are already installed
#install.packages(c("ggplot2", "sf", "rnaturalearth", "rnaturalearthdata"))
library(ggplot2)
library(sf)
library(rnaturalearth)
library(rnaturalearthdata)

# Define the grid parameters
x_range <- seq(-20, 40, length.out = 50)
y_range <- seq(30, 70, length.out = 50)

# Create a data frame with grid coordinates
df <- expand.grid(lon = x_range, lat = y_range)
df$value <- runif(nrow(df), min = 0, max = 100)  # Assign random values to each grid cell

# Prepare the world map data
world <- ne_countries(scale = "medium", returnclass = "sf")

# Plot the data
plot <- ggplot() +
   geom_tile(data = df, aes(x = lon, y = lat, fill = value), alpha = 0.4) +    
scale_fill_gradient2(low = "blue", mid = "white", high = "red", midpoint = 50, 
                   name = "Value", guide = guide_colorbar(barwidth = 10, barheight = 0.5)) +
  geom_sf(data = world, fill = NA, color = "black") +  # Add country boundaries
  coord_sf(xlim = c(-20, 40), ylim = c(30, 70), expand = FALSE) +
  theme_minimal(base_family = "sans") +
  theme(
    plot.background = element_rect(fill = "white"),
    text = element_text(color = "black"),
    axis.title = element_blank(),  # Remove axis titles
    axis.text = element_text(color = "black"),
    legend.position = "bottom"  # Position the legend at the bottom
  ) +
  labs(title = "Geographical Map with Grid Cell Values")

 # Save the plot as a PNG file with custom width and height
 ggsave("map_plot.png", plot = plot, width = 10, height = 8, dpi = 300)

失效原因

原代码中geom_tile使用的是普通数据框(df),coord_sf的投影设置仅对sf格式的空间对象生效,普通数据框的经纬度坐标不会被投影转换,导致网格图层与投影后的地图边界错位,最终显示异常。

修正后的代码(支持Lambert投影)

将网格数据转换为sf对象,并统一设置目标Lambert投影(这里选用适合欧洲区域的Lambert Azimuthal Equal Area投影,EPSG:3035):

library(ggplot2)
library(sf)
library(rnaturalearth)
library(rnaturalearthdata)

# 定义网格参数
x_range <- seq(-20, 40, length.out = 50)
y_range <- seq(30, 70, length.out = 50)

# 创建网格数据框并转换为sf对象(指定原始坐标系为WGS84,EPSG:4326)
df <- expand.grid(lon = x_range, lat = y_range)
df$value <- runif(nrow(df), min = 0, max = 100)
grid_sf <- st_as_sf(df, coords = c("lon", "lat"), crs = 4326)

# 准备世界地图数据,默认使用WGS84坐标系
world <- ne_countries(scale = "medium", returnclass = "sf")

# 绘制带Lambert投影的地图
plot <- ggplot() +
  # 用geom_sf绘制网格(替代geom_tile确保投影生效)
  geom_sf(data = grid_sf, aes(color = value, fill = value), alpha = 0.4, size = 0.1) +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red", midpoint = 50,
                       name = "Value", guide = guide_colorbar(barwidth = 10, barheight = 0.5)) +
  scale_color_gradient2(low = "blue", mid = "white", high = "red", midpoint = 50) +
  # 添加国家边界
  geom_sf(data = world, fill = NA, color = "black", linewidth = 0.5) +
  # 设置Lambert投影(EPSG:3035)和投影后的显示范围
  coord_sf(crs = st_crs(3035), xlim = c(2500000, 6500000), ylim = c(1500000, 5500000), expand = FALSE) +
  theme_minimal(base_family = "sans") +
  theme(
    plot.background = element_rect(fill = "white"),
    text = element_text(color = "black"),
    axis.title = element_blank(),
    axis.text = element_text(color = "black"),
    legend.position = "bottom"
  ) +
  labs(title = "Geographical Map with Grid Cell Values (Lambert Projection)")

# 保存图片
ggsave("map_lambert.png", plot = plot, width = 10, height = 8, dpi = 300)

关键说明

  • 转换网格为sf对象:使用st_as_sf()将普通数据框转为空间对象,指定原始CRS为WGS84(EPSG:4326),确保坐标能被正确投影转换。
  • 替换geom_tile为geom_sf:geom_tile无法适配投影转换,改用geom_sf绘制网格点;若需要严格的面状网格单元格,可进一步用st_make_grid()生成网格多边形。
  • 设置目标投影:在coord_sf()中通过crs参数指定Lambert投影的EPSG代码,同时调整xlim和ylim为投影后的坐标范围,确保显示区域符合需求。
  • 统一图层坐标系:世界地图数据默认是WGS84,coord_sf会自动将所有sf图层转换到目标投影。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:42:34