ggplot2中循环生成多图时两幅图显示一致的原因咨询
问题原因:ggplot2的延迟求值特性
你遇到的问题核心在于ggplot2的延迟求值机制——它不会在你创建图形对象的时候就计算aes()里的表达式,而是等到实际要渲染图形(比如打印、保存)的时候才会去解析这些表达式。
在你的for循环里,aes(x = points[i, 1], y = points[i, 2])中的i并没有在循环的每一步被立即计算。当循环结束后,i的最终值是2(因为你的dataframe有2行),所以当你最后查看point_plots_list里的两个图形时,它们都会使用i=2对应的点坐标,自然看起来完全一致。
解决方案:3种可行的修复方式
方法1:为每个迭代创建独立的临时数据框
最稳妥的方式是每次循环只取当前点的数据,让ggplot基于这个小数据框绘图,避免依赖循环变量:
library(ggplot2) point1 <- c(1,2) point2 <- c(2,2) points <- as.data.frame(rbind(point1,point2)) point_plots_list <- list() for (i in 1:nrow(points)) { # 提取当前点的单独数据框 current_point <- points[i, , drop = FALSE] p <- ggplot(data = current_point, mapping = aes(x = V1, y = V2)) + geom_point() + xlim(-3, 3) + ylim(-3, 3) + theme_bw() point_plots_list[[i]] <- p } # 查看结果 point_plots_list
方法2:使用!!强制立即求值循环变量
如果你不想修改数据框,可以用rlang包的!!运算符(bang-bang)强制ggplot立即计算i对应的坐标值:
library(ggplot2) point1 <- c(1,2) point2 <- c(2,2) points <- as.data.frame(rbind(point1,point2)) point_plots_list <- list() for (i in 1:nrow(points)) { # 用!!强制解析当前i对应的坐标 p <- ggplot(data = points, mapping = aes(x = points[, 1], y = points[, 2])) + geom_point(aes(x = !!points[i, 1], y = !!points[i, 2])) + xlim(-3, 3) + ylim(-3, 3) + theme_bw() point_plots_list[[i]] <- p } point_plots_list
方法3:用lapply替代for循环
lapply的每个迭代都有独立的环境,不会出现循环变量延迟求值的问题,代码更简洁:
library(ggplot2) point1 <- c(1,2) point2 <- c(2,2) points <- as.data.frame(rbind(point1,point2)) point_plots_list <- lapply(1:nrow(points), function(i) { ggplot(data = points, mapping = aes(x = points[, 1], y = points[, 2])) + geom_point(aes(x = points[i, 1], y = points[i, 2])) + xlim(-3, 3) + ylim(-3, 3) + theme_bw() }) point_plots_list
内容的提问来源于stack exchange,提问作者Emy
相关产品推荐
相关产品推荐

