如何在for循环中使用ggplot2?循环绘图报错排查
问题排查与修复方案
核心错误原因
报错Error: Discrete value supplied to continuous scale是因为给连续尺度参数传入了离散值,具体出在两处:
1. 栅格图层填充映射错误
geom_raster的aes(fill=paste0(variable, "_",scenario,"_",time_period,"_diff"))中,paste0生成的是字符串文本(例如"Bio4_ssp126_2041_2070_diff"),而非rona_df中对应的数值列。连续尺度的scale_fill_gradient无法处理离散字符串,引发冲突。
2. 散点大小映射错误
geom_point的aes(size = variable)中,variable是循环内的字符串(例如"Bio4"),属于离散值,但scale_size_continuous是连续尺度,两者不兼容。实际应该映射的是rona_data中对应variable的数值列,而非变量名本身。
修复后的代码
library(raster) library(ggplot2) library(rgdal) library(sf) library(broom) #### 提前读取静态数据(放到循环外提升效率) ammo_country <- readOGR("/data/personal2/sun/ammo/gf/chelsa2_crop_selected/current/ammo_extent_country.shp") ammo_country_df <- broom::tidy(ammo_country, region="NAME_1") cnames <- aggregate(cbind(long,lat)~id, data=ammo_country_df, FUN=mean) range <- st_read("/data/personal2/sun/ammo/gf/ammo_binary.shp") setwd("/data/personal2/sun/ammo/rona/") variables <- c("Bio4", "Bio5", "Bio6", "Bio15", "Bio17") scenarios <- c("ssp126", "ssp585") time_periods <- c("2041_2070", "2071_2100") for (variable in variables) { for (scenario in scenarios) { for (time_period in time_periods) { # 读取数据 rona_data <- read.csv(paste0(scenario,"_",time_period,"_rona_xy.csv"), header=T, row.names=1) rona_layer <- raster(paste0(variable, "_",scenario,"_",time_period,"_diff.asc")) # 裁剪掩膜 crop_layer2 <- crop(rona_layer, extent(range)) crop_layer3 <- mask(crop_layer2, range) rona_df <- as.data.frame(as(crop_layer3, "SpatialPixelsDataFrame")) # 给栅格列重命名为固定名称,避免字符串映射问题 colnames(rona_df)[3] <- "raster_value" # 绘图 p <- ggplot() + geom_sf(data = range, color = "black", fill = NA, size = 0.7) + # 使用重命名后的列做填充映射 geom_raster(data = rona_df, aes(x = x, y = y, fill = raster_value), alpha = 1) + # 用.data[[variable]]引用rona_data中对应的数值列 geom_point(data = rona_data, aes(x = x, y = y, size = .data[[variable]]), color = "navy", alpha = 1, shape = 21, stroke = 1) + scale_fill_gradient(low = "lightblue", high = "blue", name = variable) + scale_size_continuous(limits=c(0,0.6), breaks=c(0.1,0.2,0.3,0.4,0.5)) + theme_bw() + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) + labs(title = variable, x = "Lon", y = "Lat", size = "RONA") + # 使用tidy后的多边形数据,避免sf和sp对象混用问题 geom_polygon(data=ammo_country_df, aes(x=long,y=lat,group=group), color="black", fill=NA) + geom_text(data=cnames, aes(x=long,y=lat,label=id), size=3) ggsave(paste0(time_period, "_",scenario,"_",variable,"_RONA.pdf"), plot=p, height=5.74, width=4) } } }
额外优化点
- 将静态空间数据(
ammo_country、range)的读取放到循环外,避免重复IO操作,提升运行效率。 - 把栅格数据列重命名为固定名称(例如"raster_value"),避免动态字符串映射的麻烦。
- 使用
broom::tidy后的ammo_country_df绘制多边形,避免sp对象和sf对象在ggplot中混用可能出现的兼容问题。 - 合并重复的
labs设置,让代码更简洁。
内容的提问来源于stack exchange,提问作者Pei-Wei Sun
相关产品推荐
相关产品推荐

