Wie kann ich mit R CMD-Überprüfungsnotizen „Keine sichtbare Bindung für globale Variable“ umgehen, wenn meine ggplot2-Syntax sinnvoll ist?

180

EDIT: Hadley Wickham weist darauf hin, dass ich falsch geschrieben habe. R CMD-Prüfung löst NOTES aus, keine Warnungen. Die Verwirrung tut mir schrecklich leid. Es war mein Versehen.

Die Kurzversion

R CMD checkWirft diese Notiz jedes Mal, wenn ich in ggplot2 eine sinnvolle Syntax zur Erstellung von Plots verwende:

no visible binding for global variable [variable name]

Ich verstehe, warum R CMD Check das tut, aber es scheint eine ganze Ader ansonsten vernünftiger Syntax zu kriminalisieren. Ich bin mir nicht sicher, welche Schritte ich unternehmen muss, um mein Paket zu bestehen R CMD checkund zu CRAN zugelassen zu werden.

Der Hintergrund

Sascha Epskamp hat zuvor im Wesentlichen das gleiche Thema gepostet . Ich denke, der Unterschied besteht darin, dass subset()die Manpage besagt, dass sie für den interaktiven Gebrauch konzipiert ist .

In meinem Fall ist das Problem nicht vorbei, subset()sondern über ein Kernmerkmal von ggplot2: dem data =Argument.

Ein Beispiel für Code, den ich schreibe und der diese Notizen generiert

Hier ist eine Unterfunktion in meinem Paket , die einem Plot Punkte hinzufügt:

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 checkwird beim Parsen dieses Codes sagen

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

Warum R CMD-Prüfung richtig ist

Die Prüfung ist technisch korrekt. x.valuesundy.values

  • Sind in der Funktion nicht lokal definiert JitteredResponsesByContrast()
  • Sind x.values <- [something]weder global noch im Aufrufer im Formular vordefiniert .

Stattdessen handelt es sich um Variablen innerhalb eines Datenrahmens, die früher definiert und an die Funktion übergeben werden JitteredResponsesByContrast().

Warum ggplot2 es schwierig macht, die R CMD-Prüfung zu beschwichtigen

ggplot2 scheint die Verwendung eines dataArguments zu fördern . Das Datenargument ist vermutlich der Grund, warum dieser Code ausgeführt wird

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

aber dieser Code wird ein Objekt nicht gefunden - Fehler erzeugen:

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

Zwei Workarounds, und warum ich mit keinem zufrieden bin

Die NULLing-Out-Strategie

Matthew Dowle empfiehlt , die problematischen Variablen zuerst auf NULL zu setzen, was in meinem Fall folgendermaßen aussehen würde:

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

Ich schätze diese Lösung, aber ich mag sie aus drei Gründen nicht.

  1. es dient keinem zusätzlichen Zweck als dem Beschwichtigen R CMD check.
  2. es spiegelt nicht die Absicht wider. Es erhöht die Erwartung, dass der aes()Aufruf unsere now-NULL-Variablen sieht (dies wird nicht der Fall sein), während der eigentliche Zweck verdeckt wird (wodurch die R CMD-Prüfung auf Variablen aufmerksam wird, von denen sie anscheinend sonst nicht wissen würde, dass sie gebunden sind).
  3. Die Probleme von 1 und 2 multiplizieren sich, da Sie jedes Mal, wenn Sie eine Funktion schreiben, die ein Plotelement zurückgibt, eine verwirrende NULL-Anweisung hinzufügen müssen

Die with () Strategie

Sie können with()damit explizit signalisieren, dass sich die betreffenden Variablen in einer größeren Umgebung befinden. In meinem Fall with()sieht die Verwendung folgendermaßen aus:

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

Diese Lösung funktioniert. Aber ich mag diese Lösung nicht, weil sie nicht einmal so funktioniert, wie ich es erwarten würde. Wenn with()ich das Problem wirklich lösen würde, den Interpreter darauf zu richten, wo sich die Variablen befinden, sollte ich das Argument nicht einmal brauchendata = . Funktioniert aber with()nicht so:

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

Ich denke also, diese Lösung weist ähnliche Mängel auf wie die NULL-Strategie:

  1. Ich muss immer noch jede Plotelementfunktion durchgehen und die Logik in einen with()Aufruf einschließen
  2. Der with()Anruf ist irreführend. Ich muss noch ein data =Argument liefern ; alles with()was tut ist zu beschwichtigen R CMD check.

Fazit

So wie ich das sehe, gibt es drei Möglichkeiten, die ich wählen könnte:

  1. Setzen Sie sich für CRAN ein, um die Notizen zu ignorieren, indem Sie argumentieren, dass sie "falsch" sind (gemäß der CRAN-Richtlinie ), und tun Sie dies jedes Mal, wenn ich ein Paket einreiche
  2. Korrigiere meinen Code mit einer von zwei unerwünschten Strategien (NULL oder with()Blöcke)
  3. Summen Sie sehr laut und hoffen Sie, dass das Problem verschwindet

Keiner der drei macht mich glücklich und ich frage mich, was die Leute (und andere Paketentwickler, die auf ggplot2 zugreifen möchten) vorschlagen sollten. Vielen Dank an alle im Voraus. Ich freue mich sehr, dass Sie dies überhaupt durchgelesen haben :-)

briandk
quelle
20
Ich mag # 1 und # 3.
Ben Bolker
8
@ BenBolker das sind auch meine Techniken.
Hadley
6
Es gibt eine vierte Option: Ändern Sie 'R CMD check' und senden Sie einen Patch zur Prüfung an r-devel. Ich vermute, Sie werden feststellen, dass es ziemlich schwierig (und möglicherweise unmöglich) ist, zu erkennen, welche falsch sind und welche nicht. Wenn jemand einen Code dafür gefunden hat, dann ...
Matt Dowle
6
Eine andere Strategie ist zu verwendenaes_string
Hadley
2
Dies scheint ein Problem mit zu sein transformund subsetzu (nicht 100% sicher, aber es macht Sinn).
BrodieG

Antworten:

44

Hast du es mit aes_stringstatt versucht aes? Dies sollte funktionieren, obwohl ich es nicht ausprobiert habe:

aes_string(x = 'x.values', y = 'y.values')
Harlan
quelle
4
nur eine Warnung: aestut , während aes_stringkeine Positionsparameter definieren xund y.
Topchef
6
Nur eine weitere Warnung. Mit aes_string können Sie keine Funktionen zum Bearbeiten der x- und y-Werte verwenden. Angenommen, Sie möchten die Transformation y protokollieren. In diesem Fall funktioniert aes_string (x = 'x.values', y = 'log (y.values)') natürlich nicht. Ich benutze diese Art von Transformationen oft selbst, daher ist aes_string für mich nicht immer eine Option.
Dr. Mike
Vielleicht sollte diese Antwort (und die mit den meisten Stimmen) aktualisiert werden, da in der Dokumentation von aes_stringsteht: "Alle diese Funktionen sind veraltet. Bitte verwenden Sie stattdessen ordentliche Bewertungssprachen (siehe Abschnitt Quasiquotation in der Dokumentation zu aes ())." (ggplot2 Version 3.2.1). Das ist wahrscheinlich rlang::.datader beste Kandidat, um diese Notizen zum Schweigen zu bringen.
Vandenman
85

Sie haben zwei Lösungen:

  • Schreiben Sie Ihren Code neu, um eine nicht standardmäßige Auswertung zu vermeiden. Für ggplot2 bedeutet dies, dass aes_string()anstelle von aes()(wie von Harlan beschrieben) verwendet wird.

  • Fügen Sie globalVariables(c("x.values", "y.values"))irgendwo in der obersten Ebene Ihres Pakets einen Anruf hinzu .

Sie sollten bei der Übermittlung an CRAN nach 0 NOTES in Ihrem Paket streben, auch wenn Sie etwas leicht Hackiges tun müssen. Dies erleichtert CRAN das Leben und Ihnen das Leben.

(Aktualisiert am 31.12.2014, um meine neuesten Gedanken dazu wiederzugeben)

Hadley
quelle
26
globalVariablesist ein schrecklicher Hack und ich werde ihn niemals benutzen.
Hadley
10
Für das, was es wert ist, wurde meine Paketübermittlung aufgrund dieser Hinweise abgelehnt und aufgefordert, die Funktion utils :: globalVariables zu verwenden. Da ich nicht in der Lage bin zu streiten, habe ich das getan.
jbryer
9
Ich bin damit einverstanden, dass es am besten ist, sie zu ignorieren, aber mein Code verwendet viele ggplotund data.tableund enthält daher Tonnen dieser Warnungen, die mich davon abgehalten haben, andere wichtigere Warnungen zu bemerken, die wirklich Probleme waren, die ich beheben musste.
Ken Williams
108
@ Hadley du solltest nicht sagen, dass du niemals Dinge benutzen wirst, wenn du nur zwei Jahre später denkst, dass es in Ordnung ist
Hadley
10
Neujahrsvorsatz? Ich werde meine Augen offen halten ggplot::scale_dualAxis.sqrtund 3D-Kreisdiagramme mit Füllmustern.
Taufe
29

Diese Frage wurde vor einiger Zeit gestellt und beantwortet, jedoch nur zu Ihrer Information. Seit Version 2.1.0 gibt es eine andere Möglichkeit, die Notizen zu umgehen :aes_(x=~x.values,y=~y.values).

stefan.schroedl
quelle
12

Wenn

getRversion() >= "3.1.0"

Sie können einen Anruf auf der obersten Ebene des Pakets hinzufügen:

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

von:

help("suppressForeignCheck")
Bastiaan Quast
quelle
3
Das ist eine faire Lösung. Vielen Dank! Ich hatte darüber nachgedacht, aber das Problem ist, dass ich sehr viele Variablen wie x.valuesund habe y.values, also müsste ich ALLE registrieren.
Briandk
4
Das ist nicht, wofür suppressForeignCheckverwendet wird
Hadley
10
Wo ist eigentlich die oberste Ebene ? In welcher Datei füge ich diesen Befehl hinzu?
Drmariod
9
Dies wird benutzerdefiniert in eine zzz.RDatei eingefügt ./R/. Zum Beispiel github.com/HughParsonage/grattan/blob/master/R/zzz.R
Hugh
6
@ Hadley, wofür wird es verwendet? help ("unterdrückenForeignCheck") scheint zu implizieren, dass es sich um ein "zur Laufzeit berechnetes natives Symbol" handelt, aber was zum Teufel ist das?
pdb
8

Im Jahr 2019 können Sie dies am besten umgehen, indem Sie das .dataPräfix aus dem rlangPaket verwenden. Dies weist R an, x.valuesund y.valuesals Spalten in a zu behandeln data.frame(damit es sich nicht über undefinierte Variablen beschwert).

Hinweis: Dies funktioniert am besten, wenn Sie vordefinierte Spaltennamen haben, von denen Sie wissen, dass sie in Ihrer Dateneingabe vorhanden sind

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

Fügen Sie diese Codezeile zu der Datei hinzu, in der Sie die Dokumentation auf Paketebene bereitstellen:

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

Beispiel hier

stevec
quelle