Uso de ggplot () dentro de otra función en R

Intento escribir una función de trazado simple, usando la biblioteca ggplot2. Pero la llamada a ggplot no encuentra el argumento de la función.

Considere un data.frame llamado means que almacena dos condiciones y dos valores medios que quiero trazar (la condición aparecerá en el eje X, significa en la Y).

 library(ggplot2) m <- c(13.8, 14.8) cond <- c(1, 2) means <- data.frame(means=m, condition=cond) means # The output should be: # means condition # 1 13.8 1 # 2 14.8 2 testplot <- function(meansdf) { p <- ggplot(meansdf, aes(fill=meansdf$condition, y=meansdf$means, x = meansdf$condition)) p + geom_bar(position="dodge", stat="identity") } testplot(means) # This will output the following error: # Error in eval(expr, envir, enclos) : object 'meansdf' not found 

Entonces parece que ggplot llama a eval , que no puede encontrar el argumento meansdf . ¿Alguien sabe cómo puedo pasar con éxito el argumento de la función a ggplot?

(Nota: ¡Sí, podría simplemente llamar a la función ggplot directamente, pero al final espero hacer que mi función de diagtwigje haga cosas más complicadas! :))

Como Joris y Chase ya han respondido correctamente, la mejor práctica estándar es simplemente omitir la parte meansdf$ y referirse directamente a las columnas del dataframe.

 testplot < - function(meansdf) { p <- ggplot(meansdf, aes(fill = condition, y = means, x = condition)) p + geom_bar(position = "dodge", stat = "identity") } 

Esto funciona, porque las variables a las que se hace referencia en aes se ggplot en el entorno global o en el dataframe pasado a ggplot . Esa también es la razón por la cual su código de ejemplo - usando meansdf$condition etc. - no funcionó: meansdf no está disponible en el entorno global, ni está disponible dentro del dataframe pasado a ggplot , que es el mismo meansdf .


El hecho de que las variables se busquen en el entorno global en lugar de en el entorno de llamada es en realidad un error conocido en ggplot2 que Hadley no considera reparable en este momento. Esto genera problemas, si se desea utilizar una variable local, por ejemplo, una scale , para influir en los datos utilizados para la ttwig:

 testplot < - function(meansdf) { scale <- 0.5 p <- ggplot(meansdf, aes(fill = condition, y = means * scale, # does not work, since scale is not found x = condition)) p + geom_bar(position = "dodge", stat = "identity") } 

Winston Chang proporciona una muy buena solución para este caso en el problema de GitHub al que se hace referencia: establecer explícitamente el parámetro de environment en el entorno actual durante la llamada a ggplot . Esto es lo que se vería para el ejemplo anterior:

 testplot < - function(meansdf) { scale <- 0.5 p <- ggplot(meansdf, aes(fill = condition, y = means * scale, x = condition), environment = environment()) # This is the only line changed / added p + geom_bar(position = "dodge", stat = "identity") } ## Now, the following works testplot(means) 

La forma “correcta” de usar ggplot progtwigción es usar aes_string() lugar de aes() y usar los nombres de las columnas como caracteres en lugar de como objetos:

Para más usos programáticos, por ejemplo, si desea que los usuarios puedan especificar nombres de columnas para varias estéticas como argumentos, o si esta función va en un paquete que necesita pasar R CMD CHECK sin advertencias sobre nombres de variables sin definiciones, puede use aes_string() , con las columnas necesarias como caracteres.

 testplot < - function(meansdf, xvar = "condition", yvar = "means", fillvar = "condition") { p <- ggplot(meansdf, aes_string(x = xvar, y= yvar, fill = fillvar)) + geom_bar(position="dodge", stat="identity") } 

Aquí hay un truco simple que uso mucho para definir mis variables en el entorno de mis funciones (segunda línea):

 FUN < - function(fun.data, fun.y) { fun.data$fun.y <- fun.data[, fun.y] ggplot(fun.data, aes(x, fun.y)) + geom_point() + scale_y_continuous(fun.y) } datas <- data.frame(x = rnorm(100, 0, 1), y = x + rnorm(100, 2, 2), z = x + rnorm(100, 5, 10)) FUN(datas, "y") FUN(datas, "z") 

Observe cómo la etiqueta del eje y también cambia cuando se usan diferentes variables o conjuntos de datos.

No creo que deba incluir la parte meansdf$ en su llamada de función. Esto parece funcionar en mi máquina:

 meansdf < - data.frame(means = c(13.8, 14.8), condition = 1:2) testplot <- function(meansdf) { p <- ggplot(meansdf, aes(fill=condition, y=means, x = condition)) p + geom_bar(position="dodge", stat="identity") } testplot(meansdf) 

para producir:

enter image description here

Este es un ejemplo de un problema que se discutió anteriormente . Básicamente, se trata de que ggplot2 esté codificado para su uso principalmente en el entorno global. En la llamada aes (), las variables se buscan en el entorno global o dentro del dataframe especificado.

 library(ggplot2) means < - data.frame(means=c(13.8,14.8),condition=1:2) testplot <- function(meansdf) { p <- ggplot(meansdf, aes(fill=condition, y=means, x = condition)) p + geom_bar(position="dodge", stat="identity") } 

EDITAR:

actualización: después de ver la otra respuesta y actualizar el paquete ggplot2 , el código anterior funciona. La razón es que, como se explica en los comentarios, ggplot buscará las variables en aes en el entorno global (cuando el dataframe se agrega específicamente como meandf $ ...) o dentro del entorno mencionado.

Para esto, asegúrese de trabajar con la última versión de ggplot2.

Esto me frustró por un tiempo. Quería enviar diferentes marcos de datos con diferentes nombres de variables y quería la capacidad de trazar diferentes columnas desde el dataframe. Finalmente tuve una solución al crear algunas variables ficticias (globales) para manejar el trazado y forzar la asignación dentro de la función

 plotgraph function(df,df.x,df.y) { dummy.df < <- df dummy.x <<- df.x dummy.y <<- df.y p = ggplot(dummy.df,aes(x=dummy.x,y=dummy.y,.....) print(p) } 

luego en el código principal puedo llamar a la función

 plotgraph(data,data$time,data$Y1) plotgraph(data,data$time,data$Y2) 

Respuesta corta: use qplot

Respuesta larga: en esencia, quieres algo como esto:

 my.barplot < - function(x=this.is.a.data.frame.typically) { # R code doing the magic comes here ... } 

Pero eso carece de flexibilidad porque debe apegarse a los nombres de columnas coherentes para evitar la molesta idiosincrasia del scope de R. Por supuesto, el próximo paso lógico es:

 my.barplot < - function(data=data.frame(), x=..., y....) { # R code doing something really really magical here ... } 

Pero luego eso comienza a parecerse sospechosamente a una llamada a qplot (), ¿verdad?

 qplot(data=my.data.frame, x=some.column, y=some.other column, geom="bar", stat="identity",...) 

Por supuesto, ahora le gustaría cambiar cosas como títulos de escala, pero para eso una función es útil ... la buena noticia es que los problemas de scope han desaparecido.

 my.plot < - qplot(data=my.data.frame, x=some.column, y=some.other column,...) set.scales(p, xscale=scale_X_continuous, xtitle=NULL, yscale=scale_y_continuous(), title=NULL) { return(p + xscale(title=xtitle) + yscale(title=ytitle)) } my.plot.prettier <- set.scale(my.plot, scale_x_discrete, 'Days', scale_y_discrete, 'Count') 

Otra solución es definir los aes (…) como una variable de su función:

 func< -function(meansdf, aes(...)){} 

Esto funcionó bien para mí en un tema similar

Solo genero nuevas variables de marcos de datos con los nombres deseados dentro de la función:

 testplot < - function(df, xVar, yVar, fillVar) { df$xVar = df[,which(names(df)==xVar)] df$yVar = df[,which(names(df)==yVar)] df$fillVar = df[,which(names(df)==fillVar)] p <- ggplot(df, aes(x=xvar, y=yvar, fill=fillvar)) + geom_bar(position="dodge", stat="identity") } 

No necesitas nada lujoso. Ni siquiera variables ficticias. Solo necesita agregar una impresión () dentro de su función, es como usar cat () cuando desea que se muestre algo en la consola.

myplot < - ggplot (......) + Lo que quieras aquí imprime (myplot)

Me funcionó más de una vez dentro de la misma función