Uso de ggplot () dentro de outra function em R

Estou tentando escrever uma function de plotagem simples, usando a biblioteca ggplot2. Mas a chamada para ggplot não encontra o argumento da function.

Considere um data.frame chamado means que armazena duas condições e dois valores médios que eu quero plotar (a condição aparecerá no eixo X, significa no 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 

Então parece que ggplot está chamando eval , que não consegue encontrar o argumento meansdf . Alguém sabe como posso passar com sucesso o argumento de function para ggplot?

(Nota: Sim, eu poderia simplesmente chamar a function ggplot diretamente, mas no final eu espero fazer a minha function de plotagem fazer coisas mais complicadas! :))

   

Como Joris e Chase já responderam corretamente, a melhor prática padrão é simplesmente omitir a parte meansdf$ e referir-se diretamente às colunas do frame de dados.

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

Isso funciona, porque as variables ​​referidas em aes são procuradas no ambiente global ou no quadro de dados passado para ggplot . Essa é também a razão pela qual o seu código de exemplo - usando a meansdf$condition etc. - não funcionou: o meansdf não está disponível no ambiente global, nem está disponível dentro do data frame passado para o ggplot , que é o próprio meansdf .


O fato de que as variables ​​são procuradas no ambiente global, e não no ambiente de chamada, é na verdade um bug conhecido no ggplot2 que Hadley não considera consertável no momento. Isto leva a problemas, se alguém quiser usar uma variável local, digamos, scale , para influenciar os dados usados ​​para o enredo:

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

Uma solução muito interessante para esse caso é fornecida por Winston Chang no problema referenciado do GitHub: Definição explícita do parâmetro de environment para o ambiente atual durante a chamada para ggplot . Aqui está como isso seria para o exemplo acima:

 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) 

A maneira “correta” de usar o ggplot programaticamente é usar aes_string() invés de aes() e usar os nomes das colunas como caracteres ao invés de objects:

Para usos mais programáticos, por exemplo, se você quiser que os usuários possam especificar nomes de colunas para várias estéticas como argumentos, ou se esta function estiver em um pacote que precisa passar R CMD CHECK sem avisos sobre nomes de variables ​​sem definições, você pode use aes_string() , com as colunas necessárias 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") } 

Aqui está um truque simples que eu uso muito para definir minhas variables ​​no meu ambiente de funções (segunda linha):

 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 como o label do eixo y também muda quando diferentes variables ​​ou conjuntos de dados são usados.

Eu não acho que você precise include a parte meansdf$ em sua chamada de function. Isso parece funcionar na minha 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 produzir:

insira a descrição da imagem aqui

Este é um exemplo de um problema que é discutido anteriormente . Basicamente, trata-se de ggplot2 sendo codificado para uso principalmente no ambiente global. Na chamada aes (), as variables ​​são procuradas no ambiente global ou no 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:

update: Depois de ver a outra resposta e atualizar o pacote ggplot2 , o código acima funciona. Razão é, como explicado nos comentários, que ggplot irá procurar as variables ​​em aes no ambiente global (quando o dataframe é especificamente adicionado como meandf $ ...) ou dentro do ambiente mencionado.

Para isso, certifique-se de trabalhar com a versão mais recente do ggplot2.

Isso me frustrou por algum tempo. Eu queria enviar frameworks de dados diferentes com nomes de variables ​​diferentes e queria poder plotar colunas diferentes do quadro de dados. Eu finalmente consegui um trabalho criando algumas variables ​​fictícias (globais) para lidar com plotagem e forçando a atribuição dentro da function

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

então no código principal eu posso apenas chamar a function

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

Resposta curta: use qplot

Resposta longa: Em essência, você quer algo como isto:

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

Mas isso carece de flexibilidade porque você deve se ater à nomenclatura de coluna consistente para evitar as idiossincrasias do escopo R irritante. Claro que o próximo passo lógico é:

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

Mas então isso começa a parecer suspeito como uma binding para o qplot (), certo?

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

Claro que agora você gostaria de mudar coisas como escalar títulos, mas para isso uma function vem a calhar ... a boa notícia é que as questões de escopo estão praticamente acabadas.

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

Outra solução alternativa é definir o aes (…) como uma variável da sua function:

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

Isso só funcionou bem para mim em um tópico semelhante

Acabei de gerar novas variables ​​de frame de dados com os nomes desejados dentro da function:

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

Você não precisa de nada extravagante. Nem mesmo variables ​​fictícias. Você só precisa adicionar um print () dentro de sua function, é como usar cat () quando você quer algo para mostrar no console.

myplot < - ggplot (......) + O que você quiser aqui print (myplot)

Funcionou para mim mais de uma vez dentro da mesma function