Estoy tratando de usar una variable local en aes
cuando trazo con ggplot. Este es mi problema reducido a la esencia:
xy <- data.frame(x=1:10,y=1:10) plotfunc <- function(Data,YMul=2){ ggplot(Data,aes(x=x,y=y*YMul))+geom_line() } plotfunc(xy)
Esto produce el siguiente error:
Error in eval(expr, envir, enclos) : object 'YMul' not found
Parece que no puedo usar variables locales (o argumentos de funciones) en aes
. ¿Podría ser que ocurriera debido a que el contenido de aes
se ejecuta más adelante cuando la variable local está fuera del scope? ¿Cómo puedo evitar este problema (aparte de no usar la variable local dentro de aes
)?
Capturaría el entorno local,
xy <- data.frame(x=1:10,y=1:10) plotfunc <- function(Data, YMul = 2){ .e <- environment() ggplot(Data, aes(x = x, y = y*YMul), environment = .e) + geom_line() } plotfunc(xy)
Aquí hay una alternativa que le permite pasar cualquier valor a través del argumento de YMul
sin tener que agregarlo a Data
data.frame o al entorno global:
plotfunc <- function(Data, YMul = 2){ eval(substitute( expr = { ggplot(Data,aes(x=x,y=y*YMul)) + geom_line() }, env = list(YMul=YMul))) } plotfunc(xy, YMul=100)
Para ver cómo funciona esto, prueba la siguiente línea de forma aislada:
substitute({ggplot(Data, aes(x=x, y=y*YMul))}, list(YMul=100))
ggplot()
espera que YMul
sea una variable dentro del dataframe.Intenta incluir YMull
allí en su lugar:
Gracias a @Justin: ggplot()
parece buscar YMul
en el dataframe y, si no se encuentra, en el entorno global. Me gusta agregar tales variables al dataframe, de la siguiente manera, ya que tiene sentido para mí conceptualmente. Tampoco tengo que preocuparme por los cambios en las variables globales que tienen consecuencias inesperadas para las funciones. Pero todas las demás respuestas también son correctas. Por lo tanto, use el que más le convenga.
require("ggplot2") xy <- data.frame(x = 1:10, y = 1:10) xy <- cbind(xy, YMul = 2) ggplot(xy, aes(x = x, y = y * YMul)) + geom_line()
O bien, si desea la función en su ejemplo:
plotfunc <- function(Data, YMul = 2) { ggplot(cbind(Data, YMul), aes(x = x, y = y * YMul)) + geom_line() } plotfunc(xy)
Estoy usando ggplot2, y su ejemplo parece funcionar bien con la versión actual.
Sin embargo, es fácil encontrar variantes que sigan creando problemas. Yo mismo estaba confundido por un comportamiento similar, y así es como encontré esta publicación (resultado superior de Google para “ggplot cómo evaluar variables cuando se pasa”). Por ejemplo, si movemos ggplot fuera de plotfunc:
xy <- data.frame(x=1:10,y=1:10) plotfunc <- function(Data,YMul=2){ geom_line(aes(x=x,y=y*YMul)) } ggplot(xy)+plotfunc(xy) # Error in eval(expr, envir, enclos) : object 'YMul' not found
En la variante anterior, "capturar el entorno local" no es una solución porque ggplot no se llama desde la función, y solo ggplot tiene el argumento "environment =".
Pero ahora hay una familia de funciones "aes_", "aes_string", "aes_q" que son como "aes" pero capturan variables locales. Si utilizamos "aes_" en el cuadro anterior, aún recibimos un error porque ahora no se conoce acerca de "x". Pero es fácil referirse a los datos directamente, lo que resuelve el problema:
plotfunc <- function(Data,YMul=2){ geom_line(aes_(x=Data$x,y=Data$y*YMul)) } ggplot(xy)+plotfunc(xy) # works
¿Has mirado la solución dada por @wch (W. Chang)?
https://github.com/hadley/ggplot2/issues/743
Creo que es el mejor
esencialmente es como el de @baptiste pero incluye la referencia al entorno directamente en la llamada a ggplot
Lo reporto aquí
g <- function() { foo3 <- 4 ggplot(mtcars, aes(x = wt + foo3, y = mpg), environment = environment()) + geom_point() } g() # Works
Si ejecuta su código fuera de la función, funciona. Y si ejecuta el código dentro de la función con YMul
definido globalmente, funciona. No entiendo completamente el funcionamiento interno de ggplot
pero esto funciona …
YMul <- 2 plotfunc <- function(Data){ ggplot(Data,aes(x=x,y=y*YMul))+geom_line() } plotfunc(xy)