web-dev-qa-db-fra.com

Comment puis-je gérer les notes de la vérification R CMD «aucune liaison visible pour la variable globale» lorsque ma syntaxe ggplot2 est raisonnable?

EDIT: Hadley Wickham souligne que j'ai mal parlé. R La vérification CMD lance des NOTES, pas des avertissements. Je suis vraiment désolé pour la confusion. C'était ma surveillance.

La version courte

R CMD check Lance cette note à chaque fois que j'utilise syntaxe de création de tracé sensée dans ggplot2:

no visible binding for global variable [variable name]

Je comprends pourquoi R CMD check fait cela, mais cela semble criminaliser toute une veine de syntaxe autrement sensée. Je ne sais pas quelles mesures prendre pour que mon colis passe R CMD check Et soit admis au CRAN.

L'arrière-plan

Sascha Epskamp a précédemment posté sur essentiellement le même problème . La différence, je pense, est que la page de manuel de subset()dit qu'elle est conçue pour une utilisation interactive .

Dans mon cas, le problème n'est pas sur subset() mais sur une fonctionnalité centrale de ggplot2: L'argument data =.

Un exemple de code que j'écris qui génère ces notes

Voici ne sous-fonction dans mon package qui ajoute des points à un tracé:

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, En analysant ce code, dira

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

Pourquoi le contrôle R CMD est bon

La vérification est techniquement correcte. x.values Et y.values

  • Ne sont pas définis localement dans la fonction JitteredResponsesByContrast()
  • Ne sont pas prédéfinis sous la forme x.values <- [something], Globalement ou dans l'appelant.

Au lieu de cela, ce sont des variables dans une trame de données qui sont définies plus tôt et transmises à la fonction JitteredResponsesByContrast().

Pourquoi ggplot2 rend difficile l'apaisement du contrôle R CMD

ggplot2 semble encourager l'utilisation d'un argument data. L'argument data, probablement, est la raison pour laquelle ce code s'exécutera

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

mais ce code produira une erreur d'objet introuvable:

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

Deux solutions, et pourquoi je ne suis satisfait ni

La stratégie NULLing out

Matthew Dowle recommande régler d'abord les variables problématiques sur NULL, ce qui dans mon cas ressemblerait à ceci:

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

J'apprécie cette solution, mais je ne l'aime pas pour trois raisons.

  1. il ne sert à rien d'autre que d'apaiser R CMD check.
  2. cela ne reflète pas l'intention. Cela soulève l'espoir que l'appel aes() verra nos variables maintenant NULL (ce ne sera pas le cas), tout en obscurcissant le véritable objectif (en rendant R CMD check conscient des variables qu'il ne connaîtrait pas autrement étaient liées) )
  3. Les problèmes de 1 et 2 se multiplient car chaque fois que vous écrivez une fonction qui retourne un élément de tracé, vous devez ajouter une instruction NULL déroutante

La stratégie with ()

Vous pouvez utiliser with() pour signaler explicitement que les variables en question peuvent être trouvées dans un environnement plus vaste. Dans mon cas, l'utilisation de with() ressemble à ceci:

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

Cette solution fonctionne. Mais, je n'aime pas cette solution car elle ne fonctionne même pas comme je m'y attendais. Si with() résolvait vraiment le problème du pointage de l'interpréteur vers où se trouvent les variables, alors je ne devrais même pas need l'argument data =. Mais, with() ne fonctionne pas de cette façon:

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

Donc, encore une fois, je pense que cette solution a des défauts similaires à la stratégie NULLing:

  1. Je dois encore parcourir toutes les fonctions des éléments de tracé et encapsuler la logique dans un appel à with()
  2. L'appel with() est trompeur. J'ai encore besoin de fournir un argument data =; tout ce que with() fait est d'apaiser R CMD check.

Conclusion

À mon avis, je pourrais choisir trois options:

  1. Faire pression sur le CRAN pour qu'il ignore les notes en faisant valoir qu'elles sont "fausses" (conformément à politique du CRAN ), et le faire chaque fois que je soumets un paquet
  2. Correction de mon code avec l'une des deux stratégies indésirables (blocs NULL ou with())
  3. Hum vraiment fort et j'espère que le problème disparaîtra

Aucun des trois ne me rend heureux et je me demande ce que les gens suggèrent que je (et les autres développeurs de packages souhaitant puiser dans ggplot2) devraient faire. Merci à tous d'avance. J'apprécie vraiment que vous ayez lu ceci :-)

164
briandk

Avez-vous essayé avec aes_string au lieu de aes? Cela devrait fonctionner, même si je ne l'ai pas essayé:

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

Vous avez deux solutions:

  • Réécrivez votre code pour éviter une évaluation non standard. Pour ggplot2, cela signifie utiliser aes_string() au lieu de aes() (comme décrit par Harlan)

  • Ajoutez un appel à globalVariables(c("x.values", "y.values")) quelque part dans le niveau supérieur de votre package.

Vous devez vous efforcer d'obtenir 0 NOTES dans votre colis lors de la soumission à CRAN, même si vous devez faire quelque chose de légèrement hacky. Cela rend la vie plus facile pour CRAN, et plus facile pour vous.

(Mis à jour le 2014-12-31 pour refléter mes dernières réflexions à ce sujet)

81
hadley

Cette question a été posée et répondue il y a un certain temps mais juste pour votre information, puisque version 2.1. il existe un autre moyen de contourner les notes: aes_(x=~x.values,y=~y.values).

26
stefan.schroedl

Si

getRversion() >= "3.1.0"

Vous pouvez ajouter un appel au niveau supérieur du package:

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

de:

help("suppressForeignCheck")
11
Bastiaan Quast

En 2019, la meilleure façon de contourner cela est d'utiliser le .data préfixe du package rlang. Cela indique à R de traiter x.values et y.values sous forme de colonnes dans un data.frame (donc il ne se plaindra pas des variables non définies).

Remarque: Cela fonctionne mieux si vous avez des noms de colonnes prédéfinis dont vous savez qu'ils existeront dans votre entrée de données

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