R语言ggplot绘图时循环与展开循环运行表现不一致问题
问题原因分析
这个差异的核心是ggplot2的美学映射函数aes()采用延迟求值机制导致的:
- 逐行展开编写代码时,
shortdf[[1]]、shortdf[[2]]是直接写死的固定取值,添加第一层geom_line时直接绑定第1列的数值,第二层绑定第2列的数值,因此两条线都能正常渲染显示。 - 写在for循环中时,
aes()不会在循环执行的当下就计算shortdf[[i]]的实际值,只会保存对变量i的引用。等到整个代码执行完毕、ggplot最终渲染绘图时,循环已经跑完,i的值已经固定为循环的最后一个取值2,因此你添加的两层geom_line实际上都绑定了shortdf[[2]]的数值,自然只能看到最后一条线。
解决方法
你可以任选以下任意一种方案修复循环绘图的问题:
- 使用tidyverse推荐的
.data代词绑定列,避免延迟求值的问题
p <- ggplot(shortdf, aes(datetime)) for (i in 1:2) { p <- p + geom_line(aes(y = as.numeric(as.character(.data[[names(shortdf)[i]]])))) }
- 在循环中添加
force()函数,强制每一轮立刻求值当前的i
p <- ggplot(shortdf, aes(datetime)) for (i in 1:2) { force(i) p <- p + geom_line(aes(y = as.numeric(as.character(shortdf[[i]])))) }
- (更符合ggplot设计逻辑的推荐方案)把宽格式的
shortdf转为长格式,不需要循环即可一次性绘制所有折线
library(tidyr) library(dplyr) # 宽转长,除了datetime列之外的列都转为值列 longdf <- shortdf %>% pivot_longer(-datetime, names_to = "group", values_to = "val") %>% mutate(val = as.numeric(as.character(val))) # 一次绘图自动生成所有折线,还可以自动按group区分颜色 p <- ggplot(longdf, aes(datetime, y = val, color = group)) + geom_line()
内容的提问来源于stack exchange,提问作者idontgetoutmuch
相关产品推荐
相关产品推荐

