¿Cómo puedo manejar las notas de R CMD de verificación "sin enlace visible para la variable global" cuando mi sintaxis ggplot2 es sensible?

180

EDITAR: Hadley Wickham señala que hablo mal. R La comprobación CMD arroja NOTAS, no Advertencias. Lamento muchísimo la confusión. Fue mi descuido.

La versión corta

R CMD checklanza esta nota cada vez que uso una sintaxis sensata de creación de gráficos en ggplot2:

no visible binding for global variable [variable name]

Entiendo por qué R CMD check hace eso, pero parece estar criminalizando toda una veta de sintaxis sensible. No estoy seguro de qué pasos tomar para que mi paquete pase R CMD checky sea admitido en CRAN.

El fondo

Sascha Epskamp publicó anteriormente sobre esencialmente el mismo problema . La diferencia, creo, es que subset()la página de manual dice que está diseñada para uso interactivo .

En mi caso, el problema no ha terminado subset()sino una característica central de ggplot2: el data =argumento.

Un ejemplo de código que escribo que genera estas notas

Aquí hay una subfunción en mi paquete que agrega puntos a una gráfica:

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, al analizar este código, dirá

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

¿Por qué la verificación R CMD es correcta?

La verificación es técnicamente correcta. x.valuesyy.values

  • No se definen localmente en la función JitteredResponsesByContrast()
  • No están predefinidos en la forma x.values <- [something]globalmente o en la persona que llama.

En cambio, son variables dentro de un marco de datos que se define anteriormente y se pasa a la función JitteredResponsesByContrast().

¿Por qué ggplot2 hace que sea difícil apaciguar la verificación R CMD?

ggplot2 parece alentar el uso de un dataargumento. El argumento de los datos, presumiblemente, es por qué este código se ejecutará

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

pero este código producirá un error de objeto no encontrado:

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

Dos soluciones y por qué no estoy contento con ninguna

La estrategia de anulación

Matthew Dowle recomienda establecer primero las variables problemáticas en NULL, que en mi caso se vería así:

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

Aprecio esta solución, pero no me gusta por tres razones.

  1. no tiene ningún propósito adicional más allá de apaciguar R CMD check.
  2. No refleja la intención. Eleva la expectativa de que la aes()llamada verá nuestras variables ahora NULAS (no lo hará), mientras que oculta el propósito real (hacer que R CMD verifique las variables que aparentemente no sabría que están vinculadas)
  3. Los problemas de 1 y 2 se multiplican porque cada vez que escribe una función que devuelve un elemento de trazado, debe agregar una declaración NULLing confusa

La estrategia con ()

Puede usar with()para indicar explícitamente que las variables en cuestión se pueden encontrar dentro de un entorno más grande. En mi caso, el uso se with()ve así:

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

Esta solución funciona Pero, no me gusta esta solución porque ni siquiera funciona de la manera que lo esperaría. Si with()realmente resolviera el problema de señalar al intérprete a dónde están las variables, entonces ni siquiera debería necesitar el data =argumento. Pero, with()no funciona de esa manera:

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

Entonces, nuevamente, creo que esta solución tiene fallas similares a la estrategia NULLing:

  1. Todavía tengo que pasar por cada función de elemento de la trama y ajustar la lógica en una with()llamada
  2. La with()llamada es engañosa. Todavía necesito proporcionar una data =discusión; todo with()lo que hace es apaciguar R CMD check.

Conclusión

A mi modo de ver, hay tres opciones que podría tomar:

  1. Presiona a CRAN para que ignore las notas argumentando que son "espurias" (de conformidad con la política de CRAN ), y hazlo cada vez que envíe un paquete
  2. Arreglar mi código con una de dos estrategias indeseables (NULLing o with()blocks)
  3. Zumba muy fuerte y espero que el problema desaparezca

Ninguno de los tres me hace feliz, y me pregunto qué sugiere la gente que yo (y otros desarrolladores de paquetes que quieran aprovechar ggplot2) debería hacer. Gracias a todos de antemano. Realmente aprecio que hayas leído esto :-)

briandk
fuente
20
Me gustan los n. ° 1 y n. ° 3.
Ben Bolker
8
@BenBolker esas son mis técnicas de referencia también.
Hadley
66
Hay una cuarta opción: modificar 'R CMD check' y enviar un parche a r-devel para su consideración. Sospecho que encontrará que es bastante difícil (y posiblemente imposible) detectar cuáles son espurios y cuáles no. Si a alguien se le ocurrió un código para hacer eso, entonces ...
Matt Dowle
66
Otra estrategia es usaraes_string
hadley
2
Esto parece ser un problema con transformy subsettambién (no es 100% seguro, pero que tiene sentido).
BrodieG

Respuestas:

45

¿Has probado con en aes_stringlugar de aes? Esto debería funcionar, aunque no lo he probado:

aes_string(x = 'x.values', y = 'y.values')
Harlan
fuente
44
solo una advertencia: aeshace while aes_stringno define parámetros posicionales xy y.
topchef
66
Solo otra advertencia. aes_string no le permite usar funciones para manipular los valores x e y. Supongamos que desea registrar la transformación y, en cuyo caso aes_string (x = 'x.values', y = 'log (y.values)'), por supuesto, no funciona. Utilizo mucho este tipo de transformaciones, así que aes_string no siempre es una opción para mí.
Dr. Mike
Tal vez esta respuesta (y la que tenga más votos) debería actualizarse ya que la documentación de aes_stringdice: "Todas estas funciones están en desuso. Por favor, use expresiones de evaluación ordenadas (consulte la sección de cuasiquotación en la documentación de aes ())". (ggplot2 versión 3.2.1). Eso probablemente sea rlang::.datael mejor candidato para silenciar estas notas.
Vandenman el
86

Tienes dos soluciones:

  • Vuelva a escribir su código para evitar una evaluación no estándar. Para ggplot2, esto significa usar en aes_string()lugar de aes()(como lo describe Harlan)

  • Agregue una llamada a globalVariables(c("x.values", "y.values"))algún lugar en el nivel superior de su paquete.

Debes esforzarte por 0 NOTAS en tu paquete cuando lo envíes a CRAN, incluso si tienes que hacer algo ligeramente hacky. Esto hace la vida más fácil para CRAN y más fácil para usted.

(Actualizado 2014-12-31 para reflejar mis últimos pensamientos sobre esto)

Hadley
fuente
26
globalVariableses un truco horrible y nunca lo usaré.
hadley
10
Por lo que vale, mi envío del paquete fue rechazado debido a estas notas y me dijeron que usara la función utils :: globalVariables. Como no estoy en condiciones de discutir, eso es lo que hice.
jbryer
9
Estoy de acuerdo en que sería mejor ignorarlos, pero mi código usa muchos ggploty data.table, por lo tanto, tiene toneladas de estas advertencias, lo que me ha impedido notar otras advertencias más importantes que realmente eran problemas que necesitaba solucionar.
Ken Williams
108
@hadley, no deberías decir que nunca usarás cosas cuando solo dos años después piensas que está bien
hadley
10
¿resolución del año Nuevo? Mantendré mis ojos abiertos ggplot::scale_dualAxis.sqrty gráficos circulares en 3D con patrones de relleno.
Baptiste
29

Esta pregunta se ha hecho y respondido hace un tiempo, pero solo para su información, desde la versión 2.1.0 hay otra forma de evitar las notas:aes_(x=~x.values,y=~y.values).

stefan.schroedl
fuente
12

Si

getRversion() >= "3.1.0"

Puede agregar una llamada en el nivel superior del paquete:

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

de:

help("suppressForeignCheck")
Bastiaan Quast
fuente
3
Esa es una solución justa. ¡Gracias! Lo consideré, pero el problema es que tengo muchas variables como x.valuesy y.values, por lo que tendría que registrar TODAS ellas.
briandk
44
Eso no suppressForeignCheckes para lo que se usa
hadley
10
¿Dónde está realmente el nivel superior ? ¿En qué archivo agrego este comando?
drmariod
9
Por costumbre, esto se coloca en un zzz.Rarchivo ./R/. Por ejemplo, github.com/HughParsonage/grattan/blob/master/R/zzz.R
Hugh
66
@ Hadley, ¿para qué se usa? help ("suppressForeignCheck") parece implicar que es para un "símbolo nativo calculado en tiempo de ejecución", pero ¿qué diablos es eso?
pdb
8

En 2019, la mejor manera de evitar esto es usar el .dataprefijo del rlangpaquete. Esto le dice a R que trate x.valuesy y.valuescomo columnas en un data.frame(por lo que no se quejará de variables indefinidas).

Nota: Esto funciona mejor si tiene nombres de columnas predefinidos que sabe que existirán en su entrada de datos

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

Agregue esta línea de código al archivo en el que proporciona documentación a nivel de paquete:

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

Ejemplo aquí

stevec
fuente