Як я можу обробляти примітки R CMD, щоб перевірити "відсутні видимі прив'язки для глобальної змінної", коли мій синтаксис ggplot2 чутливий?


180

EDIT: Хедлі Вікхем вказує, що я помиляюсь. R CMD перевірка кидає ПРИМІТКИ, а не попередження. Мені страшенно шкода плутанини. Це був мій нагляд.

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

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'

Чому перевірка CM CMD правильна

Чек технічно правильний. x.valuesіy.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()

але цей код призведе до помилки, що не знайдена:

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

Дві роботи, і чому я задоволений жодним із них

Стратегія NULLing out

Меттью Даул рекомендує спочатку встановити проблемні змінні значення 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()виглядає так:

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). Дякуємо всім заздалегідь. Я дуже вдячний, що ви навіть прочитали це :-)


20
Мені подобаються №1 і №3.
Бен Болкер

8
@BenBolker це теж мої методи переходу.
хадлі

6
Існує 4-й варіант: змінити "R CMD check" та надіслати виправлення до r-devel для розгляду. Я підозрюю, що вам буде складно (а можливо неможливо) виявити, які є хибними, а які - ні. Якщо хтось придумав це зробити, то ...
Метт Даул

6
Інша стратегія полягає у використанніaes_string
hadley

2
Це, здається, є проблемою transformі subsetзанадто (не на 100% впевнений, але це має сенс).
BrodieG

Відповіді:


45

Ви намагалися aes_stringзамість цього aes? Це має спрацювати, хоча я цього не пробував:

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

4
просто попередження: aesробить поки aes_stringне визначає позиційні параметри xта y.
топчеф

6
Просто ще одне попередження. aes_string не дозволяє використовувати функції для маніпулювання значеннями x та y. Скажіть, що ви хочете записати перетворення y, в цьому випадку aes_string (x = 'x.values', y = 'log (y.values)'), звичайно, не працює. Я дуже часто використовую такі перетворення, тому aes_string не завжди є для мене варіантом.
Доктор Майк

Можливо, цю відповідь (і ту, що має найбільшу кількість голосів) слід оновити, оскільки в документації aes_stringсказано: "Усі ці функції злегка застаріли. Будь ласка, використовуйте замість них чіткі ідіоми оцінювання (див. Розділ квазівітування в документації aes ())." (ggplot2 версія 3.2.1). Це, мабуть, змушує rlang::.dataнайкращого кандидата замовчувати ці замітки.
Ванденман

86

У вас є два рішення:

  • Перепишіть свій код, щоб уникнути нестандартного оцінювання. Для ggplot2 це означає використовувати aes_string()замість aes()(як описано Харланом)

  • Додайте дзвінок globalVariables(c("x.values", "y.values"))десь із найвищого рівня свого пакету.

Ви повинні прагнути до 0 ПРИМІТКИ у вашому пакеті під час подання в CRAN, навіть якщо вам доведеться зробити щось злегка вибагливе. Це полегшує життя CRAN та полегшує вам.

(Оновлено 2014-12-31, щоб відобразити мої останні думки з цього приводу)


26
globalVariablesце жахливий хак, і я його ніколи не буду використовувати.
хадлі

10
Щодо того, моє подання пакету було відхилено через ці примітки, і йому сказали використовувати функцію utils :: globalVariables. Оскільки я не в змозі сперечатися, саме це я і зробив.
jbryer

9
Я згоден , що було б краще , щоб їх ігнорувати, але мій код використовує багато ggplotі data.table, і , отже , має тонн цих попереджень, які утримували мене помічати інші більш важливі попередження , які дійсно були проблеми , які я повинен виправити.
Кен Вільямс

108
@hadley, ти не повинен говорити, що ти ніколи не будеш користуватися речами, коли лише через два роки ти вважатимеш це нормально
hadley

10
новорічна резолюція? Я буду тримати очі відкритими ggplot::scale_dualAxis.sqrtта 3D-пироги з візерунками наповнення.
баптист

29

На це запитання було задано і відповіли деякий час тому, але лише для вашої інформації, оскільки у версії 2.1.0 є ще один спосіб обійти нотатки:aes_(x=~x.values,y=~y.values).


12

Якщо

getRversion() >= "3.1.0"

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

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

від:

help("suppressForeignCheck")

3
Це справедливе рішення. Дякую! Я вважав це, але проблема полягає в тому, що у мене дуже багато змінних, таких як x.valuesі y.values, тому мені доведеться зареєструвати ВСІ з них.
бріандк

4
Це не те, що suppressForeignCheckвикористовується для
hadley

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, щоб він ставився x.valuesі y.valuesяк стовпці в 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("."))

Приклад тут

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.