Как я могу обработать примечания проверки 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))
)
)
}
Я ценю это решение, но мне не нравится его по трем причинам.
- это не служит никакой дополнительной цели, кроме умиротворения
R CMD check
, - это не отражает намерения. Это повышает ожидание того, что
aes()
Вызов увидит наши переменные now-NULL (не будет), скрывая при этом реальную цель (делая проверку CMD R осведомленной о переменных, которые, по-видимому, иначе бы не знали, были связаны) - Проблемы 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:
- Я все еще должен пройти через каждую функцию элемента сюжета и обернуть логику в
with()
вызов -
with()
звонок вводит в заблуждение. Мне все еще нужно предоставитьdata =
аргумент; всеwith()
делает успокаиваетR CMD check
,
Заключение
На мой взгляд, есть три варианта:
- Побуждайте CRAN игнорировать заметки, утверждая, что они "ложные" (согласно политике CRAN), и делайте это каждый раз, когда я отправляю пакет
- Исправьте мой код с помощью одной из двух нежелательных стратегий (NULLing или
with()
блоки) - Гул очень громко и надеюсь, что проблема уходит
Ни один из трех не делает меня счастливым, и мне интересно, что люди предлагают мне (и другим разработчикам пакетов, желающим подключиться к 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))
)