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

bri*_*ndk 169 r ggplot2

编辑:哈德利威克姆指出我错过了.R CMD检查是投掷NOTES,而不是警告.我非常抱歉这种混乱.这是我的疏忽.

简短的版本

R CMD check每次我在ggplot2中使用合理的绘图创建语法时都会抛出此注释:

no visible binding for global variable [variable name]
Run Code Online (Sandbox Code Playgroud)

我理解为什么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))
    )
  )
}
Run Code Online (Sandbox Code Playgroud)

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'
Run Code Online (Sandbox Code Playgroud)

为什么R CMD检查是正确的

检查在技术上是正确的.x.valuesy.values

  • 未在函数中本地定义 JitteredResponsesByContrast()
  • 不是x.values <- [something]全局或调用者在表单中预定义的.

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

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

ggplot2似乎鼓励使用data参数.据推测,数据参数是此代码执行的原因

library(ggplot2)
p <- ggplot(aes(x = hwy, y = cty), data = mpg)
p + geom_point()
Run Code Online (Sandbox Code Playgroud)

但是这段代码会产生一个对象未​​找到的错误:

library(ggplot2)
hwy # a variable in the mpg dataset
Run Code Online (Sandbox Code Playgroud)

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

NULLing out策略

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))
    )
  )
}
Run Code Online (Sandbox Code Playgroud)

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

  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))
      )
    }
  )
}
Run Code Online (Sandbox Code Playgroud)

此解决方案有效.但是,我不喜欢这种解决方案,因为它甚至没有像我期望的那样工作.如果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
Run Code Online (Sandbox Code Playgroud)

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

  1. 我仍然需要遍历每个plot元素函数并在with()调用中包装逻辑
  2. 这个with()电话有误导性.我仍然需要提供一个data =论点; 一切with()都在安抚R CMD check.

结论

我看到它的方式,我可以采取三种选择:

  1. 大堂CRAN忽略了这些笔记,认为它们是"虚假的"(根据CRAN政策),每次提交包裹时都这样做
  2. 使用两种不合需要的策略之一修复我的代码(NULLing或with()块)
  3. 哼声非常大声,希望问题消失

三者都不让我高兴,我想知道人们建议我(以及其他想要利用ggplot2的软件包开发者)应该做些什么.感谢所有提前.我非常感谢你甚至通过这个阅读:-)

had*_*ley 82

你有两个解决方案:

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

  • 将呼叫添加到globalVariables(c("x.values", "y.values"))程序包顶级的某个位置.

在提交给CRAN时,你应该在你的包中争取0注意,即使你必须做一些有点hacky的事情.这使CRAN的生活更轻松,也更容易.

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

  • @hadley你不应该说你永远不会在两年后再使用东西你觉得它没问题 (104认同)
  • `globalVariables`是一个可怕的黑客,我永远不会使用它. (26认同)
  • 值得一提的是,由于这些注释,我的包提交被拒绝,并被告知使用utils :: globalVariables函数.由于我无法辩论,这就是我所做的. (10认同)
  • 新的一年的决议?我将睁大眼睛看看`ggplot :: scale_dualAxis.sqrt`和带有填充图案的3D饼图. (10认同)
  • 我同意最好忽略它们,但是我的代码使用了很多`ggplot`和`data.table`,因此有*吨*的这些警告,这使我无法注意到其他更重要的警告.我需要解决的问题. (9认同)
  • @Mike博士,它仍然是一个可怕的黑客,但如果你想要你的CRAN包你只需要搞砸 (7认同)
  • 现在有`utils :: globalVariables`来阻止这些注释(但不要忘记`if(getRversion()> ="2.15.1")`或者包真的会失败) (5认同)
  • 我的包裹也被这个论点拒绝了.我们真的需要让CRAN的守门人过来取消这个限制.它浪费了每个人的时间. (4认同)
  • @hadley为了记录,我同意2012年你比现在更多.我不知道是什么让你改变了主意,但对我来说,globalVariables确实感觉像是一个"可怕的黑客"...... (3认同)

Har*_*lan 42

你尝试过aes_string而不是aes吗?这应该工作,虽然我没有尝试过:

aes_string(x = 'x.values', y = 'y.values')
Run Code Online (Sandbox Code Playgroud)

  • 只是另一个警告.aes_string不允许您使用函数来操纵x和y值.假设您想要记录变换y,在这种情况下,aes_string(x ='x.values',y ='log(y.values)')当然不起作用.我自己经常使用这些转换,所以aes_string对我来说并不总是一个选项. (6认同)
  • 只是一个警告:`aes`确实,而`aes_string`没有定义位置参数`x`和`y`. (3认同)
  • 也许这个答案(以及得票最多的答案)应该更新,因为 `aes_string` 的文档说:“所有这些函数都已软弃用。请改用整洁的评估习惯用法(请参阅 aes() 文档中的准引用部分) ”。(ggplot2 版本 3.2.1)。这可能使“rlang::.data”成为沉默这些注释的最佳候选者。 (3认同)
  • 只是在这里要注意,自 ggplot2 v3.0 以来,`aes_string` 已被弃用 (3认同)

小智 28

这个问题前一段时间已经被提出并得到了回答,但仅仅是因为版本2.1.0,还有另一种解决方法的方法:aes_(x=~x.values,y=~y.values).


Pau*_*ain 15

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

注意:如果您知道数据输入中存在预定义的列名称,则此方法效果最佳

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

  • 请注意,“.data”是从“ggplot2”导出的,因此您不需要添加“rlang”作为单独的依赖项。 (3认同)

Bas*_*ast 12

如果

getRversion() >= "3.1.0"
Run Code Online (Sandbox Code Playgroud)

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

utils::suppressForeignCheck(c("x.values", "y.values"))
Run Code Online (Sandbox Code Playgroud)

从:

help("suppressForeignCheck")
Run Code Online (Sandbox Code Playgroud)

  • 实际上**顶级**在哪里?我在哪个文件中添加此命令? (10认同)
  • 通过自定义,它被放在`./ R /`中的`zzz.R`文件中.例如,https://github.com/HughParsonage/grattan/blob/master/R/zzz.R (9认同)
  • @hadley,它用于什么?help("suppressForeignCheck")似乎意味着它是一个"运行时计算的原生符号",但那到底是什么? (6认同)
  • 那不是'suppressForeignCheck`用的 (4认同)
  • 这是一个公平的解决方案.谢谢!我考虑过这个,但问题是我有很多变量,如`x.values`和`y.values`,所以我必须注册所有这些变量. (3认同)

use*_*745 7

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

if(getRversion() >= "2.15.1")  utils::globalVariables(c("."))
Run Code Online (Sandbox Code Playgroud)

示例在这里