Как я могу обработать примечания проверки CMD "нет видимой привязки для глобальной переменной", когда мой синтаксис ggplot2 является разумным?

РЕДАКТИРОВАТЬ: Хэдли Уикхэм указывает, что я оговорился. R CMD проверяет выбрасывание NOTES, а не предупреждений. Мне ужасно жаль за путаницу. Это был мой недосмотр.

Короткая версия

R CMD check выдает эту заметку каждый раз, когда я использую разумный синтаксис создания графика в ggplot2:

no visible binding for global variable [variable name]

Я понимаю, почему проверка R CMD делает это, но, похоже, криминализирует всю вину разумного синтаксиса. Я не уверен, какие шаги нужно предпринять, чтобы передать мой пакет R CMD check и получить доступ к CRAN.

Фон

Саша Эпскамп ранее публиковал по сути ту же проблему. Разница, я думаю, в том, что 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.values а также y.values

  • Не определены локально в функции JitteredResponsesByContrast()
  • Не определены заранее в форме x.values <- [something] или глобально, или в вызывающем абоненте.

Вместо этого они являются переменными внутри фрейма данных, который был определен ранее и передан в функцию. JitteredResponsesByContrast(),

Почему ggplot2 мешает успокоить проверку 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

Два обходных пути, и почему я счастлив ни тем, ни другим

Стратегия обнуления

Мэтью Доул рекомендует сначала установить для проблемных переменных значение 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 (не будет), скрывая при этом реальную цель (делая проверку CMD R осведомленной о переменных, которые, по-видимому, иначе бы не знали, были связаны)
  3. Проблемы 1 и 2 умножаются, потому что каждый раз, когда вы пишете функцию, которая возвращает элемент сюжета, вы должны добавить непонятный оператор NULLing

Стратегия с ()

Ты можешь использовать 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. Я все еще должен пройти через каждую функцию элемента сюжета и обернуть логику в with() вызов
  2. with() звонок вводит в заблуждение. Мне все еще нужно предоставить data = аргумент; все with() делает успокаивает R CMD check,

Заключение

На мой взгляд, есть три варианта:

  1. Побуждайте CRAN игнорировать заметки, утверждая, что они "ложные" (согласно политике CRAN), и делайте это каждый раз, когда я отправляю пакет
  2. Исправьте мой код с помощью одной из двух нежелательных стратегий (NULLing или with() блоки)
  3. Гул очень громко и надеюсь, что проблема уходит

Ни один из трех не делает меня счастливым, и мне интересно, что люди предлагают мне (и другим разработчикам пакетов, желающим подключиться к ggplot2). Спасибо всем заранее. Я действительно ценю, что вы даже читаете это:-)

8 ответов

Решение

Вы пробовали с aes_string вместо aes? Это должно работать, хотя я не пробовал:

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

У вас есть два решения:

  • Перепишите свой код, чтобы избежать нестандартной оценки. Для ggplot2 это означает использование aes_string() вместо aes() (как описано Харланом)

  • Добавить звонок в globalVariables(c("x.values", "y.values")) где-то на верхнем уровне вашего пакета.

Вы должны стремиться к 0 NOTES в вашем пакете при отправке в CRAN, даже если вам нужно сделать что-то немного хакерское. Это делает жизнь проще для CRAN и проще для вас.

(Обновлено 2014-12-31, чтобы отразить мои последние мысли по этому поводу)

В 2019 году лучший способ обойти это - использовать .data префикс из rlangпакет. Это говорит R лечитьx.values а также y.values как столбцы в data.frame (поэтому он не будет жаловаться на неопределенные переменные).

Примечание: это работает лучше всего, если у вас есть предопределенные имена столбцов, которые, как вы знаете, будут существовать во вводимых вами данных.

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

Этот вопрос был задан и получен ответ некоторое время назад, но только к сведению, начиная с версии 2.1.0, есть еще один способ обойти заметки: aes_(x=~x.values,y=~y.values).

Если

getRversion() >= "3.1.0"

Вы можете добавить звонок на верхнем уровне пакета:

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

от:

help("suppressForeignCheck")

Добавьте эту строку кода в файл, в котором вы предоставляете документацию на уровне пакета:

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

Пример здесь

Потому что в руководстве для ?aes_string сказано

Все эти функции устарели. Вместо этого используйте аккуратные оценочные идиомы (см. раздел квазицитирования в документации по aes()).

Итак, я прочитал эту страницу и придумал этот шаблон:

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

Это примерно так же уродливо, как IIFE, и смешивает базовые выражения с аккуратными ударами. Но также не требует обходного пути глобальных переменных и не использует ничего, что устарело. Похоже, он также работает с расчетами в эстетике и производными переменными, такими как ..count..

как насчет использования get()?

      geom_point(
         aes(
           x = get('x.values'), 
           y = get('y.values')
         ),
         data     = data,
         position = position_jitter(height = 0, width = GetDegreeOfJitter(jj))
)
Другие вопросы по тегам