ggplot多图合并后图表重复问题求助(附R代码示例)
循环生成ggplot图表全部相同的问题解决
问题根源
ggplot采用延迟求值机制:循环中创建的ggplot对象不会立即解析aes()内的表达式,直到最终调用grid.arrange()渲染时才会执行。此时循环变量variable已经指向最后一次循环的取值,导致所有图表都使用同一个变量生成。
解决方案1:使用tidyeval强制提前求值
利用!!sym()语法将字符串变量名转换为符号并强制提前解析,确保每次循环绑定当前的变量值:
library(tidyverse) library(gridExtra) url <- paste("https://raw.githubusercontent.com/fivethirtyeight/", "data/master/college-majors/recent-grads.csv", sep = "" ) df <- read_csv(url) cols_to_factor <- c("Major", "Major_code", "Major_category") df <- df %>% mutate_at(cols_to_factor, factor) df_clean <- df %>% drop_na() plot_list <- list() i <- 0 for (variable in colnames(select_if(df_clean, is.numeric))) { i <- i + 1 g <- ggplot(df_clean) + geom_histogram(aes(x = !!sym(variable)), bins = 20, fill = "royalblue", color = "gray" ) + ggtitle(paste("Histogram of", variable)) + labs(x = variable) plot_list[[i]] <- g } grid.arrange(grobs = plot_list, ncol = 5)
sym(variable):将字符串格式的变量名转换为tidyverse可识别的符号!!(双感叹号):强制提前求值该符号,绑定当前循环的variable值,避免延迟到最后统一解析
解决方案2:用local()创建局部环境
通过local()为每次循环创建独立的局部环境,保存当前循环的变量值,防止被后续循环覆盖:
library(tidyverse) library(gridExtra) url <- paste("https://raw.githubusercontent.com/fivethirtyeight/", "data/master/college-majors/recent-grads.csv", sep = "" ) df <- read_csv(url) cols_to_factor <- c("Major", "Major_code", "Major_category") df <- df %>% mutate_at(cols_to_factor, factor) df_clean <- df %>% drop_na() plot_list <- list() i <- 0 for (variable in colnames(select_if(df_clean, is.numeric))) { i <- i + 1 g <- local({ var <- variable ggplot(df_clean) + geom_histogram(aes(x = unlist(df_clean[, var])), bins = 20, fill = "royalblue", color = "gray" ) + ggtitle(paste("Histogram of", var)) + labs(x = var) }) plot_list[[i]] <- g } grid.arrange(grobs = plot_list, ncol = 5)
补充说明
循环中调用plot(g)能正确显示的原因:调用plot()时会立即渲染图表,此时variable仍为当前循环的取值,因此能生成对应图表;但保存到列表的ggplot对象依然是延迟求值状态,最终批量渲染时会使用循环结束后的variable值,导致所有图表相同。
内容的提问来源于stack exchange,提问作者Coeus Wang
相关产品推荐
相关产品推荐

