如何处理R CMD检查“全局变量没有可见绑定”;注释当我的ggplot2语法是明智的?

编辑:哈德利·维克汉姆指出我说错了。R CMD检查抛出NOTES,而不是警告。非常抱歉给您造成了混乱。这是我的疏忽。

简短的版本

每次在ggplot2中使用合理的情节创建语法时,R CMD check都会抛出这个注释:

no visible binding for global variable [variable name]

我理解为什么R CMD检查这样做,但它似乎是犯罪的整个脉络,否则明智的语法。我不确定要采取什么步骤来让我的包通过R CMD check并被CRAN录取。

背景

Sascha Epskamp之前在本质上是同一个问题上发表过文章。我认为,区别在于subset()的manpage 说它是为交互使用而设计的. xml。

在我的例子中,问题不是关于subset(),而是关于ggplot2的一个核心特性:data =参数。

我编写的生成这些注释的代码示例

下面是我的包中的一子函数,它将点添加到绘图中:

JitteredResponsesByContrast <- function (data) {
return(
geom_point(
aes(
x = x.values,
y = y.values
),
data     = data,
position = position_jitter(height = 0, width = GetDegreeOfJitter(jj))
)
)
}

R CMD check在解析这段代码时会说

granovagg.contr : JitteredResponsesByContrast: no visible binding for
global variable 'x.values'
granovagg.contr : JitteredResponsesByContrast: no visible binding for
global variable 'y.values'

为什么R CMD检查是正确的

这张支票在技术上是正确的。x.valuesy.values

  • 不是在函数JitteredResponsesByContrast()中局部定义的
  • 不是在x.values <- [something]形式中预定义的,无论是全局的还是调用者的。

相反,它们是先前定义并传递给函数JitteredResponsesByContrast()的数据帧中的变量。

为什么ggplot2很难安抚R CMD检查

ggplot2似乎鼓励使用data参数。data参数大概是执行这段代码的原因

library(ggplot2)
p <- ggplot(aes(x = hwy, y = cty), data = mpg)
p + geom_point()

但是代码将产生一个object-not-found错误:

library(ggplot2)
hwy # a variable in the mpg dataset

有两个变通办法,为什么我一个都不满意

排除策略

马修·道尔推荐首先将有问题的变量设置为NULL,在我的情况下看起来像这样:

JitteredResponsesByContrast <- function (data) {
x.values <- y.values <- NULL # Setting the variables to NULL first
return(
geom_point(
aes(
x = x.values,
y = y.values
),
data     = data,
position = position_jitter(height = 0, width = GetDegreeOfJitter(jj))
)
)
}

我欣赏这个解决方案,但我不喜欢它有三个原因。

  1. 除了安抚R CMD check之外,它没有其他用途。
  2. 它没有反映出意图。它提高了aes()调用将看到我们的now-NULL变量的期望(它不会),同时模糊了真正的目的(使R CMD检查意识到它显然不知道被绑定的变量)
  3. 1和2的问题是加倍的,因为每次编写返回plot元素的函数时,都必须添加一个令人困惑的NULLing语句

with()策略

你可以使用with()显式地表示可以在更大的环境中找到相关变量。在我的例子中,使用with()看起来像这样:

JitteredResponsesByContrast <- function (data) {
with(data, {
geom_point(
aes(
x = x.values,
y = y.values
),
data     = data,
position = position_jitter(height = 0, width = GetDegreeOfJitter(jj))
)
}
)
}

这个解决方案是可行的。但是,我不喜欢这个解决方案因为它甚至不像我期望的那样工作。如果with()真的解决了将解释器指向变量所在位置的问题,那么我甚至不应该需要 data =参数。但是,with()不是这样工作的:

library(ggplot2)
p <- ggplot()
p <- p + with(mpg, geom_point(aes(x = hwy, y = cty)))
p # will generate an error saying `hwy` is not found

因此,我再次认为这个解决方案与NULLing策略有类似的缺陷:

  1. 我仍然必须遍历每个plot元素函数,并将逻辑包装在with()调用中
  2. with()调用具有误导性。我仍然需要提供一个data =参数;所有with()所做的是安抚R CMD check

结论

在我看来,我有三个选择:

  1. 游说CRAN忽略这些便条,理由是它们是“虚假的”;(根据凹口政策),并在每次提交包时这样做
  2. 用两种不受欢迎的策略之一(NULLing或with()块)修复我的代码
  3. 大声哼唱,希望问题消失

这三种方法都不能让我满意,我想知道人们建议我(以及其他想利用ggplot2的包开发人员)应该做什么。

28493 次浏览

你试过用aes_string代替aes吗?这应该可以工作,尽管我还没有尝试过:

aes_string(x = 'x.values', y = 'y.values')

你有两个解决方案:

  • 重写代码以避免非标准的计算。对于ggplot2,这意味着使用aes_string()而不是aes()(如Harlan所述)

  • 在包的顶层某处添加对globalVariables(c("x.values", "y.values"))的调用。

在提交给CRAN时,您应该在包中争取0个NOTES,即使您必须做一些略显笨拙的事情。这使CRAN和您的工作更轻松。

(更新2014年12月31日,反映我对这个问题的最新想法)

如果

getRversion() >= "3.1.0"

你可以在包的顶层添加一个调用:

utils::suppressForeignCheck(c("x.values", "y.values"))

来自:

help("suppressForeignCheck")

这个问题在一段时间前已经被问过并回答过了,但只是为了供你参考,因为版本2.1.0的有另一种方法来避开注释:aes_(x=~x.values,y=~y.values).

在2019年,解决这个问题的最佳方法是使用rlang包中的.data前缀,该前缀也会被导出到ggplot2。这告诉R将x.valuesy.values视为data.frame中的列(因此它不会抱怨未定义的变量)。

注意:如果您预先定义了您知道将存在于数据输入中的列名,那么这种方法效果最好

#' @importFrom ggplot2 .data
my_func <- function(data) {
ggplot(data, aes(x = .data$x, y = .data$y))
}

编辑:更新为根据@Noah注释从ggplot2导出.data,而不是rlang

将这行代码添加到您提供包级文档的文件中:

if(getRversion() >= "2.15.1")  utils::globalVariables(c("."))

例子在这里

使用get()怎么样?

geom_point(
aes(
x = get('x.values'),
y = get('y.values')
),
data     = data,
position = position_jitter(height = 0, width = GetDegreeOfJitter(jj))
)

因为?aes_string的手册说

所有这些函数都是轻度弃用的。请使用整齐的评价 用成语代替(参见aes()中的准引用部分) 文档)。< / p >

所以我读了那一页,想出了这个模式:

ggplot2::aes(x = !!quote(x.values),
y = !!quote(y.values))

它和IIFE一样丑陋,混合了基本表达式和整齐的bang-bang -bang。但也不需要全局变量的变通方法,并且不使用任何已弃用的东西。它似乎也适用于美学计算和派生变量,如..count..