如何在ggplot2循环绘图中添加IF语句处理全NA的ETS列
解决循环中遇到全NA列时的程序终止问题
我来帮你搞定这个问题!你的循环之所以会终止,核心原因是当某个国家的ETS列全为NA时,执行线性回归lm(y~x)会直接抛出错误——毕竟y全是缺失值,模型根本无法拟合。下面给你两种完全符合需求的解决方案:
方案一:跳过无ETS数据的国家
如果不想给这类国家绘图,直接跳过即可。只需要在循环开头加入一个判断逻辑,检测当前国家的ETS列是否全为NA,若是就直接进入下一轮循环:
ctry <- unique(energy$country) # Color settings: colorblind-friendly palette cols <- c("#999999", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") for(i in (1:length(ctry))) { plot.df <- energy[energy$country==ctry[i],] # 新增:检查当前国家的ETS列是否全为NA,若是则跳过 if(all(is.na(plot.df$ETS))){ next } ets.initial <- min(plot.df$year) x <- plot.df$UN[plot.df$year >= ets.initial & plot.df$year < 2017] y <- plot.df$ETS[plot.df$year >= ets.initial & plot.df$year < 2017] m1 <- round(summary(lm(y~x))$r.squared, 3) m2 <- round(lm(y~x-1)$coef, 3) p <- ggplot() + geom_line(data=plot.df,aes(x=year, y=UN, color='UN 1.A.1'), na.rm=TRUE) + geom_line(data=plot.df, aes(x=year, y=ETS, color='ETS 20')) + annotate(geom='text', label=paste0("R^2==", m1), x=2014, y=Inf, vjust=2, hjust=0, parse=TRUE, cex=3) + annotate(geom='text', label=paste0("beta==", m2), x=2014, y=Inf, vjust=4, hjust=-0.15, parse=TRUE, cex=3) + labs(x="Year", y="CO2 Emissions (metric tons)", title=paste("Energy sector emissions for", ctry[i])) + theme(plot.margin=unit(c(.5, .5, .5, .5), "cm")) + scale_color_manual(values = cols) + scale_y_continuous(labels = scales::comma) + scale_x_continuous(breaks = seq(2000, 2017, by=5)) + labs(color="Datasets") ggsave(p, filename=paste("H:/figures_energy/", ctry[i], ".png", sep=""), width=6.5, height=6) }
方案二:为无ETS数据的国家单独绘制仅含UN列的图
如果想保留这类国家的可视化结果,只需要分情况构建ggplot对象:有ETS数据时正常绘制双线条+回归标注;无ETS数据时仅绘制UN线条,并调整标题和配色:
ctry <- unique(energy$country) # Color settings: colorblind-friendly palette cols <- c("#999999", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") for(i in (1:length(ctry))) { plot.df <- energy[energy$country==ctry[i],] # 检测当前国家是否有有效ETS数据 has_ets_data <- any(!is.na(plot.df$ETS)) if(has_ets_data){ # 有ETS数据的情况:正常执行回归+绘图 ets.initial <- min(plot.df$year) x <- plot.df$UN[plot.df$year >= ets.initial & plot.df$year < 2017] y <- plot.df$ETS[plot.df$year >= ets.initial & plot.df$year < 2017] m1 <- round(summary(lm(y~x))$r.squared, 3) m2 <- round(lm(y~x-1)$coef, 3) p <- ggplot() + geom_line(data=plot.df,aes(x=year, y=UN, color='UN 1.A.1'), na.rm=TRUE) + geom_line(data=plot.df, aes(x=year, y=ETS, color='ETS 20')) + annotate(geom='text', label=paste0("R^2==", m1), x=2014, y=Inf, vjust=2, hjust=0, parse=TRUE, cex=3) + annotate(geom='text', label=paste0("beta==", m2), x=2014, y=Inf, vjust=4, hjust=-0.15, parse=TRUE, cex=3) + labs(x="Year", y="CO2 Emissions (metric tons)", title=paste("Energy sector emissions for", ctry[i])) + theme(plot.margin=unit(c(.5, .5, .5, .5), "cm")) + scale_color_manual(values = cols) + scale_y_continuous(labels = scales::comma) + scale_x_continuous(breaks = seq(2000, 2017, by=5)) + labs(color="Datasets") }else{ # 无ETS数据的情况:仅绘制UN列,调整标题和配色 p <- ggplot() + geom_line(data=plot.df,aes(x=year, y=UN, color='UN 1.A.1'), na.rm=TRUE) + labs(x="Year", y="CO2 Emissions (metric tons)", title=paste("Energy sector emissions for", ctry[i], "(No ETS data)")) + theme(plot.margin=unit(c(.5, .5, .5, .5), "cm")) + scale_color_manual(values = cols[1]) + # 仅使用第一个配色 scale_y_continuous(labels = scales::comma) + scale_x_continuous(breaks = seq(2000, 2017, by=5)) + labs(color="Datasets") } ggsave(p, filename=paste("H:/figures_energy/", ctry[i], ".png", sep=""), width=6.5, height=6) }
另外注意:我把原代码里aes(x=plot.df$year)这类写法改成了直接用列名x=year,这是ggplot的规范写法,避免不必要的潜在问题。
内容的提问来源于stack exchange,提问作者Constantin
相关产品推荐
相关产品推荐

