使用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
相关产品推荐
相关产品推荐

