You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言ggplot2 for循环绘图后grid.arrange调用fill着色失效问题求助

问题根源

这个问题是ggplot2的延迟求值特性导致的:aes()中定义的映射关系不会在你创建ggplot对象时立即计算,只会在实际渲染绘图时才会读取对应变量的当前值。你在循环中定义的rightans是全局环境变量,循环执行完成后rightans会停留在最后一次迭代的取值,后续不管是调用grid.arrange拼接图表,还是单独调用之前保存的ggplot对象,都会用这个最终值计算fill着色规则,因此所有图的着色逻辑都和最后一张图一致。
另外你的代码还存在一个隐藏问题:你给fill属性做了映射,但调用的是scale_colour_manual修改颜色色板,就算fill逻辑正常也无法显示预期的红绿配色,需要改成scale_fill_manual。

解决方案

有两种常用的修复方案可任选:

方案1:用非标准求值注入变量值

使用rlang的!!操作符,在创建ggplot对象时就把当前迭代的rightans值直接注入到aes表达式中,避免后续渲染时再读取变量:

plist<-list()
for (i in 1:20){
  TheTable <- answers[i] %>% count(answers[i])
  colnames(TheTable) <- c("q", "n")
  rightans <- correct_answers[i]
  perc_wrong <- prop.table(table(right_wrong[i]))[1]*100
  p<-ggplot(TheTable)+
    # 用!!注入当前rightans的取值
    geom_bar(stat="identity", aes(x=q, y=n, fill = q == !!rightans)) +
    # 把colour改成fill
    scale_fill_manual(name = 'Right', values = setNames(c('green','red'), c(T, F)))+
    theme_classic()+
    theme(legend.position='none')+
    xlab("")+
    ylab("")+
    labs(title= paste0("Question ", i, " (", rightans, ") "),
         subtitle=paste0(round(perc_wrong, 0), "% was wrong"))
  print(p)
  plist[[i]]<-p
  assign(paste0("Q", i, "_plot"), p)
}
do.call(grid.arrange,plist)

方案2:封装绘图逻辑为独立函数

将单张图表的生成逻辑封装为独立函数,利用函数的局部作用域锁定每次迭代的参数值,不会被后续循环的变量覆盖:

# 定义绘图函数
make_single_plot <- function(i, answers, correct_answers, right_wrong) {
  TheTable <- answers[i] %>% count(answers[i])
  colnames(TheTable) <- c("q", "n")
  rightans <- correct_answers[i]
  perc_wrong <- prop.table(table(right_wrong[i]))[1]*100
  p<-ggplot(TheTable)+
    geom_bar(stat="identity", aes(x=q, y=n, fill = q == rightans)) +
    scale_fill_manual(name = 'Right', values = setNames(c('green','red'), c(T, F)))+
    theme_classic()+
    theme(legend.position='none')+
    xlab("")+
    ylab("")+
    labs(title= paste0("Question ", i, " (", rightans, ") "),
         subtitle=paste0(round(perc_wrong, 0), "% was wrong"))
  return(p)
}

# 循环调用函数生成图表
plist<-list()
for (i in 1:20) {
  p <- make_single_plot(i, answers, correct_answers, right_wrong)
  print(p)
  plist[[i]] <- p
  assign(paste0("Q", i, "_plot"), p)
}
do.call(grid.arrange,plist)

内容的提问来源于stack exchange,提问作者Thomas Frissen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 05:24:05