Come posso gestire le note di controllo “Nessun legame visibile per variabile globale” R CMD quando la mia sintassi ggplot2 è ragionevole?


180

EDIT: Hadley Wickham sottolinea che ho sbagliato a parlare. R Il controllo CMD sta generando NOTE, non Avvertenze. Mi dispiace terribilmente per la confusione. È stata la mia svista.

La versione corta

R CMD checkgenera questa nota ogni volta che utilizzo una sintassi di creazione di grafici sensata in ggplot2:

no visible binding for global variable [variable name]

Capisco il motivo per cui il controllo R CMD lo fa, ma sembra criminalizzare un'intera vena di sintassi altrimenti sensata. Non sono sicuro di quali passi adottare per far passare il mio pacchetto R CMD checke essere ammesso al CRAN.

Lo sfondo

Sascha Epskamp in precedenza aveva pubblicato essenzialmente lo stesso problema . La differenza, penso, è che subset()la manpage dice che è progettata per un uso interattivo .

Nel mio caso, il problema non è risolto subset()ma riguarda una caratteristica fondamentale di ggplot2: l' data =argomento.

Un esempio di codice che scrivo che genera queste note

Ecco una sotto-funzione nel mio pacchetto che aggiunge punti a un grafico:

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, analizzando questo codice, dirà

granovagg.contr : JitteredResponsesByContrast: no visible binding for
  global variable 'x.values'
granovagg.contr : JitteredResponsesByContrast: no visible binding for
  global variable 'y.values'

Perché il controllo R CMD è corretto

Il controllo è tecnicamente corretto. x.valuesey.values

  • Non sono definiti localmente nella funzione JitteredResponsesByContrast()
  • Non sono predefiniti nel modulo x.values <- [something]né a livello globale né nel chiamante.

Al contrario, sono variabili all'interno di un frame di dati che viene definito in precedenza e passato alla funzione JitteredResponsesByContrast().

Perché ggplot2 rende difficile placare il controllo R CMD

ggplot2 sembra incoraggiare l'uso di un dataargomento. L'argomento dei dati, presumibilmente, è il motivo per cui questo codice verrà eseguito

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

ma questo codice produrrà un errore oggetto non trovato:

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

Due soluzioni alternative e perché non sono contento di nessuno dei due

La strategia di NULLing out

Matthew Dowle consiglia di impostare prima le variabili problematiche su NULL, che nel mio caso sarebbe simile al seguente:

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))
    )
  )
}

Apprezzo questa soluzione, ma non mi piace per tre motivi.

  1. non ha alcuno scopo aggiuntivo oltre a placare R CMD check.
  2. non riflette l'intento. Aumenta l'aspettativa che la aes()chiamata vedrà le nostre variabili ora-NULL (non lo farà), mentre oscura lo scopo reale (facendo in modo che R CMD verifichi le variabili che apparentemente non saprebbero altrimenti che erano legate)
  3. I problemi di 1 e 2 si moltiplicano perché ogni volta che si scrive una funzione che restituisce un elemento grafico, è necessario aggiungere un'istruzione NULLing confusa

La strategia with ()

Puoi usare with()per segnalare esplicitamente che le variabili in questione possono essere trovate all'interno di un ambiente più grande. Nel mio caso, l'utilizzo with()è simile al seguente:

JitteredResponsesByContrast <- function (data) {
  with(data, {
      geom_point(
               aes(
                 x = x.values, 
                 y = y.values
               ),
               data     = data,
               position = position_jitter(height = 0, width = GetDegreeOfJitter(jj))
      )
    }
  )
}

Questa soluzione funziona. Ma questa soluzione non mi piace perché non funziona nemmeno come mi aspetterei. Se with()sono stati davvero risolvere il problema di indicare l'interprete al punto in cui le variabili sono, allora dovrei nemmeno bisogno della data =discussione. Ma with()non funziona in questo modo:

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

Quindi, ancora una volta, penso che questa soluzione abbia difetti simili alla strategia NULLing:

  1. Devo ancora passare attraverso ogni funzione dell'elemento trama e avvolgere la logica in una with()chiamata
  2. La with()chiamata è fuorviante. Devo ancora fornire un data =argomento; tutto with()ciò che sta facendo è appagante R CMD check.

Conclusione

A mio modo di vedere, ci sono tre opzioni che potrei prendere:

  1. Fai pressioni su CRAN per ignorare le note sostenendo che sono "spurie" (ai sensi della politica CRAN ) e fallo ogni volta che invio un pacchetto
  2. Correggi il mio codice con una delle due strategie indesiderate (NULLing o with()blocchi)
  3. Ronza molto forte e spero che il problema scompaia

Nessuno dei tre mi rende felice, e mi chiedo cosa dovrebbe suggerire la gente (e altri sviluppatori di pacchetti che vogliono attingere a ggplot2). Grazie a tutti in anticipo. Apprezzo molto la tua lettura anche attraverso questo :-)


20
Mi piacciono i numeri 1 e 3.
Ben Bolker,

8
@BenBolker anche queste sono le mie tecniche di riferimento.
Hadley,

6
C'è una quarta opzione: modifica 'R controllo CMD' e invia una patch a r-devel per considerazione. Ho il sospetto che scoprirai che è abbastanza difficile (e forse impossibile) rilevare quali sono spurie e quali no. Se qualcuno ha trovato un pezzo di codice per farlo, allora ...
Matt Dowle,

6
Un'altra strategia è quella di utilizzareaes_string
Hadley il

2
Questo sembra essere un problema con transforme subsettroppo (non sicuro al 100%, ma ha senso).
BrodieG,

Risposte:


45

Hai provato con aes_stringinvece di aes? Questo dovrebbe funzionare, anche se non l'ho provato:

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

4
solo un avvertimento: aesfa while aes_stringnon definisce parametri posizionali xe y.
topchef,

6
Solo un altro avvertimento. aes_string non consente di utilizzare le funzioni per manipolare i valori xey. Supponiamo che tu voglia registrare trasformare y nel qual caso aes_string (x = 'x.values', y = 'log (y.values)') ovviamente non funziona. Uso questo tipo di trasformazioni da solo, quindi aes_string non è sempre un'opzione per me.
Dr. Mike

Forse questa risposta (e quella con il maggior numero di voti) dovrebbe essere aggiornata poiché la documentazione di aes_stringdice: "Tutte queste funzioni sono deprecate. Si prega di usare idiomi di valutazione ordinati (vedere la sezione di quasiquotazione nella documentazione di aes ())." (ggplot2 versione 3.2.1). Questo probabilmente rende rlang::.datail miglior candidato a mettere a tacere queste note.
Vandenman,

86

Hai due soluzioni:

  • Riscrivi il tuo codice per evitare valutazioni non standard. Per ggplot2, questo significa usare aes_string()invece di aes()(come descritto da Harlan)

  • Aggiungi una chiamata da globalVariables(c("x.values", "y.values"))qualche parte nel livello superiore del tuo pacchetto.

Dovresti cercare 0 NOTE nel tuo pacchetto quando invii a CRAN, anche se devi fare qualcosa di leggermente confuso. Questo rende la vita più facile per CRAN e più facile per te.

(Aggiornato 2014-12-31 per riflettere i miei ultimi pensieri su questo)


26
globalVariablesè un trucco orribile e non lo userò mai.
Hadley,

10
Per quello che vale, l'invio del mio pacchetto è stato rifiutato a causa di queste note e mi è stato detto di usare la funzione utils :: globalVariables. Dal momento che non sono in grado di discutere, è quello che ho fatto.
jbryer,

9
Concordo sul fatto che sarebbe meglio ignorarli, ma il mio codice usa molti ggplote data.table, e quindi ha tonnellate di questi avvisi, che mi hanno impedito di notare altri avvertimenti più importanti che erano davvero problemi che dovevo risolvere.
Ken Williams,

108
@hadley non dovresti dire che non userai mai le cose quando solo due anni dopo pensi che
vada

10
propositi per l'anno nuovo? Terrò gli occhi aperti per ggplot::scale_dualAxis.sqrte grafici a torta 3D con motivi di riempimento.
Baptista,

29

Questa domanda è stata posta e ha risposto qualche tempo fa, ma solo per tua informazione, dalla versione 2.1.0 c'è un altro modo per aggirare le note:aes_(x=~x.values,y=~y.values).


12

Se

getRversion() >= "3.1.0"

È possibile aggiungere una chiamata al livello superiore del pacchetto:

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

a partire dal:

help("suppressForeignCheck")

3
Questa è una soluzione giusta. Grazie! Lo avevo considerato, ma il problema è che ho molte variabili come x.valuese y.values, quindi dovrei registrarle TUTTE.
Briandk,

4
Non è quello per cui suppressForeignCheckviene usato
Hadley,

10
Dov'è effettivamente il livello più alto ? In quale file devo aggiungere questo comando?
drmariod,

9
Per impostazione predefinita, questo viene inserito in un zzz.Rfile ./R/. Ad esempio, github.com/HughParsonage/grattan/blob/master/R/zzz.R
Hugh

6
@hadley, a cosa serve? help ("suppressForeignCheck") sembra implicare che sia per un "simbolo nativo calcolato in fase di esecuzione", ma che diamine è?
pdb,

8

Nel 2019, il modo migliore per aggirare questo è utilizzare il .dataprefisso dal rlangpacchetto. Questo dice a R di trattare x.valuese y.valuescome colonne in a data.frame(quindi non si lamenterà di variabili indefinite).

Nota: funziona meglio se hai nomi di colonne predefiniti che sai esisteranno nel tuo input di dati

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

3

Aggiungi questa riga di codice al file in cui fornisci la documentazione a livello di pacchetto:

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

Esempio qui

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.