在purrr::map中调用as.ggplot时,如何规避全局变量赋值?
问题描述
我正在使用ggplotify包中的as.ggplot函数,包装circlize包生成的弦图,以便用patchwork包进行美观排版。但由于as.ggplot接受公式或表达式作为参数,似乎要求所有标识符都处于全局作用域中。我可以通过<<-将变量赋值到全局来解决,但这种方法显得不够规范。
我是在函数内部(通过purrr::map)调用as.ggplot的,因此内部的所有变量仅存在于局部作用域中,以下是简化示例:
失败示例:局部变量无法被识别
隐式变量.x仅存在于匿名map函数的作用域内,as.ggplot的公式无法找到它:
library(ggplotify) library(purrr) plots <- map(1:10,~{ as.ggplot(~plot(seq(.x))) }) #> Error in `map()`: #> ℹ In index: 1. #> Caused by error in `seq()`: #> ! object '.x' not found plots[[10]] #> Error in eval(expr, envir, enclos): object 'plots' not found
成功但不规范的示例:使用全局变量
通过<<-将变量赋值到全局作用域,虽然能运行,但不符合编程规范:
library(ggplotify) library(purrr) plots <- map(1:10,~{ x <<- .x as.ggplot(~plot(seq(x))) }) plots[[10]]

请问有没有无需使用<<-创建全局变量的解决方法?
解决方案
可以通过绑定公式的局部环境或利用rlang构造带环境的表达式,让as.ggplot能够访问到map匿名函数内的局部变量,以下是三种可靠方法:
方法1:手动为公式绑定当前局部环境
先构造公式,再将其环境设置为当前局部作用域,这样公式就能识别.x:
library(ggplotify) library(purrr) plots <- map(1:10, ~{ p_formula <- ~plot(seq(.x)) environment(p_formula) <- environment() as.ggplot(p_formula) }) plots[[10]]
方法2:用rlang::new_formula直接创建带环境的公式
借助rlang包的new_formula函数,在创建公式时直接指定局部环境,一步完成:
library(ggplotify) library(purrr) library(rlang) plots <- map(1:10, ~{ as.ggplot(new_formula(NULL, expr(plot(seq(.x))), env = environment())) }) plots[[10]]
方法3:使用as.ggplot的env参数(版本支持时)
如果你的ggplotify版本较新,as.ggplot提供了env参数,可直接传入局部环境,无需修改公式:
library(ggplotify) library(purrr) plots <- map(1:10, ~{ as.ggplot(~plot(seq(.x)), env = environment()) }) plots[[10]]
以上方法均无需依赖全局变量,既符合编程规范,又能实现预期功能。
内容的提问来源于stack exchange,提问作者Luther Blissett
相关产品推荐
相关产品推荐

