当我的ggplot2语法合理时,如何处理R CMD检查“对全局变量无可见绑定”注释?


180

编辑:Hadley Wickham指出我误会了。R CMD检查正在抛出注释,而不是警告。对此我感到非常抱歉。这是我的疏忽。

短版

R CMD check每当我在ggplot2中使用明智的绘图创建语法时,都会抛出此注释:

no visible binding for global variable [variable name]

我理解为什么R CMD检查可以做到这一点,但是它似乎将其他本来可以理解的语法定为犯罪。我不确定要采取什么步骤使我的包裹通过R CMD check并被CRAN录取。

背景

Sascha Epskamp此前曾发表过关于同一问题的报道。我认为,区别在于手册subset()页上说它是为交互使用而设计的

就我而言,这个问题还没有结束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]全局中也未在调用方中预先定义。

相反,它们是数据帧中的变量,该变量早先定义并传递到function中JitteredResponsesByContrast()

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

ggplot2似乎鼓励使用data参数。大概是data参数,这就是为什么要执行此代码的原因

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

但是代码将产生一个找不到对象的错误:

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

两种解决方法,以及为什么我都不满意

归零策略

Matthew Dowle建议首先将有问题的变量设置为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()调用将看到我们现在为NULL的变量(不会),同时掩盖了真实的目的(使R CMD检查显然不是绑定的变量)
  3. 1和2的问题成倍增加,因为每次编写返回图元素的函数时,都必须添加一个令人困惑的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忽略这些注释,认为它们是“虚假的”(根据CRAN政策),并且每次我提交包裹时都要这样做
  2. 使用两种不良策略之一(NULL或with()块)修复我的代码
  3. 嗡嗡声真的很大,希望问题解决

这三个都不能让我感到高兴,我想知道人们建议我(以及希望利用ggplot2的其他软件包开发人员)应该做什么。在此先感谢所有。我真的很感谢您阅读本文章:-)


20
我喜欢#1和#3。
Ben Bolker

8
@BenBolker这些也是我的首选技术。
哈德利2012年

6
第四个选项是:修改“ R CMD检查”,然后将补丁提交给r-devel进行考虑。我怀疑您会发现很难检测(并且可能无法检测)哪些是伪造的,哪些不是。如果有人想出了一段代码来做到这一点,那么……
Matt Dowle

6
另一种策略是使用aes_string
hadley

2
这似乎是一个问题transformsubset太(肯定不是100%,但它是有道理的)。
BrodieG 2014年

Answers:


44

您是否尝试过使用aes_string而不是aes?虽然我没有尝试过,但这应该可以工作:

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

4
只是一个警告:aes而while aes_string并没有定义位置参数xy
topchef

6
只是另一个警告。aes_string不允许您使用函数来操纵x和y值。假设您想对变换y进行对数,则在这种情况下aes_string(x ='x.values',y ='log(y.values)')当然不起作用。我本人经常使用这类转换,因此aes_string并非总是我的选择。
迈克博士

也许应该更新此答案(以及得票最多的答案),因为的文档aes_string说:“所有这些功能都已被软弃用。请改用整洁的评估习惯用法(请参阅aes()文档中的quasiquotation部分)。” (ggplot2版本3.2.1)。这可能是使rlang::.data这些音符保持沉默的最佳人选。
Vandenman

85

您有两种解决方案:

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

  • 将呼叫添加到globalVariables(c("x.values", "y.values"))软件包顶层的某个位置。

提交给CRAN时,即使您必须做些小巧的事情,也应该在包中争取0 NOTES。这使CRAN的生活更加轻松,也使您的生活更加轻松。

(已更新2014-12-31以反映我对此的最新想法)


26
globalVariables是骇人听闻的骇客,我绝不会使用。
哈德利2012年

10
出于价值考虑,我的软件包提交由于这些说明而被拒绝,并被告知使用utils :: globalVariables函数。由于我无权争论,所以我做到了。
jbryer

9
我同意最好忽略它们,但是我的代码使用了许多ggplotdata.table,因此包含大量警告,这使我无法注意到其他更重要的警告,而这些警告实际上是我需要解决的问题。
肯·威廉姆斯

108
@hadley,你不应该说只有两年后,你才认为永远都不会使用东西
hadley 2014年

10
新的一年的决议?我会睁大眼睛看着ggplot::scale_dualAxis.sqrt带有填充图案的3D饼图。
浸信会


12

如果

getRversion() >= "3.1.0"

您可以在包的顶层添加呼叫:

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

从:

help("suppressForeignCheck")

3
这是一个公平的解决方案。谢谢!我曾考虑过这个问题,但问题是我有很多像x.valuesand 一样的变量y.values,因此我必须注册所有这些变量。
briandk

4
那不是suppressForeignCheck用来做的事
哈德利(Hadley)2015年

10
最高层实际上在哪里?我要在哪个文件中添加此命令?
drmariod

9
根据惯例,此zzz.R文件放置在中的文件中./R/。例如,github.com/HughParsonage/grattan/blob/master/R/zzz.R

6
@hadley,它是做什么用的?help(“ suppressForeignCheck”)似乎暗示它是针对“运行时计算的本机符号”的,但这到底是什么呢?
pdb

8

在2019年,解决此问题的最佳方法是使用程序包中的.data前缀rlang。这告诉R将a视为x.values并且y.values作为a中的列data.frame(因此它不会抱怨未定义的变量)。

注意:如果您有预定义的列名,并且知道这些列名将存在于数据输入中,则此方法最有效

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

3

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

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

这里的例子

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.