如何用R函数批量生成x1-y1等4组变量的散点图?
解决ggplot函数封装的变量找不到问题 + 批量绘图实现
问题根源
你遇到的错误是因为ggplot的非标准求值特性:当你在aes(x=m, y=n)里直接写参数名时,ggplot会尝试在数据框minidata中寻找名为m和n的列,而不是你传入的y1、x1这些实际变量名。要让函数正确识别你传入的变量,需要用tidyverse的准引用语法来告诉ggplot“这是我传入的变量,不是字面量”。
修正单个绘图函数
这里推荐两种常用的方法:
方法1:使用{{ }}(Embrace语法,tidyverse推荐)
这种方法最直观,直接把参数用双大括号包裹,告诉ggplot要引用传入的变量:
library(tidyverse) graph <- function(m, n) { minidata <- select(alldata, {{m}}, {{n}}) ggplot(minidata, aes(x = {{m}}, y = {{n}})) + geom_point() + ggtitle(glue::glue("{deparse(substitute(m))} VS {deparse(substitute(n))}")) } # 测试调用 graph(x1, y1)
注意这里用glue包来动态生成标题(如果没装的话先install.packages("glue")),这样标题会自动显示实际的变量名,而不是固定的"m VS n"。
方法2:使用.data代词
如果你习惯用字符串传参,或者需要更灵活的字符串处理,可以用.data[[变量名]]的方式:
graph <- function(m, n) { # 把参数转为字符串 m_str <- as.character(substitute(m)) n_str <- as.character(substitute(n)) minidata <- select(alldata, all_of(c(m_str, n_str))) ggplot(minidata, aes(x = .data[[m_str]], y = .data[[n_str]])) + geom_point() + ggtitle(glue::glue("{m_str} VS {n_str}")) } # 调用方式一样 graph(x1, y1)
批量生成4幅图的实现
现在我们可以把需要配对的变量列出来,用循环或者purrr的批量函数来自动生成所有图:
方法1:用purrr::map2批量处理
先定义变量对的列表,然后用map2遍历每一对变量:
# 定义需要配对的变量名(注意这里是符号形式) x_vars <- list(x1, x2, x3, x4) y_vars <- list(y1, y2, y3, y4) # 批量生成所有图,结果是一个ggplot对象的列表 plot_list <- purrr::map2(x_vars, y_vars, ~graph(.x, .y)) # 如果你想把所有图拼在一起,可以用patchwork包 # install.packages("patchwork") library(patchwork) wrap_plots(plot_list) + plot_annotation(title = "All Scatter Plots")
方法2:用for循环生成并保存(如果需要单独保存每幅图)
# 定义变量对的字符串向量 var_pairs <- list( c("x1", "y1"), c("x2", "y2"), c("x3", "y3"), c("x4", "y4") ) for (pair in var_pairs) { x_var <- sym(pair[1]) y_var <- sym(pair[2]) p <- graph(!!x_var, !!y_var) # 保存每幅图到本地 ggsave(glue::glue("{pair[1]}_vs_{pair[2]}.png"), p, width = 6, height = 4) # 也可以直接打印显示 print(p) }
这里用sym()把字符串转为符号,再用!!(unquote)传入函数,和之前的embrace语法效果一致。
额外提示
- 确保你的
alldata是在函数能访问的环境里(比如全局环境),如果是在其他环境,最好把alldata也作为参数传入函数,让函数更健壮:
graph <- function(data, m, n) { minidata <- select(data, {{m}}, {{n}}) ggplot(minidata, aes(x = {{m}}, y = {{n}})) + geom_point() + ggtitle(glue::glue("{deparse(substitute(m))} VS {deparse(substitute(n))}")) } # 调用时传入alldata graph(alldata, x1, y1)
内容的提问来源于stack exchange,提问作者fran
相关产品推荐
相关产品推荐

