2011-02-24 7 views
34

Sto provando a scrivere una semplice funzione di stampa, utilizzando la libreria ggplot2. Ma la chiamata a ggplot non trova l'argomento della funzione.Uso di ggplot() all'interno di un'altra funzione in R

Si consideri un data.frame chiamato means che memorizza due condizioni e due valori medi che voglio stampare (la condizione apparirà sull'asse X, significa su 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 

Così sembra che ggplot sta chiamando eval, che non riesce a trovare l'argomento meansdf. Qualcuno sa come posso passare correttamente l'argomento della funzione a ggplot?

(Nota: Sì ho potuto solo chiamare direttamente la funzione ggplot, ma alla fine spero di fare la mia funzione plot fare cose più complicate :)!)

risposta

28

Come Joris e Chase hanno già risposto correttamente, migliore pratica standard è di omettere semplicemente la parte meansdf$ e si riferiscono direttamente alle colonne della struttura dati.

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

questo funziona, perché le variabili di cui al aes sono guardati sia per l'ambiente globale o nella cornice di dati passata a ggplot. Questo è anche il motivo per cui il tuo codice di esempio - utilizzando meansdf$condition - non ha funzionato: meansdf non è disponibile nell'ambiente globale, né è disponibile all'interno del frame di dati passato a ggplot, che è lo stesso meansdf.


Il fatto che le variabili sono cercati nel contesto globale invece che nell'ambiente chiamante è in realtà a known bug in ggplot2 che Hadley non considera risolvibile in questo momento. Questo porta a problemi, se si vuole utilizzare una variabile locale, ad esempio, scale, di influenzare i dati utilizzati per la trama:

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

Un bel soluzione per questo caso è fornito da Winston Chang nel riferimento Problema GitHub: impostazione esplicita del parametro environment nell'ambiente corrente durante la chiamata a ggplot. Ecco che cosa sarebbe simile per l'esempio precedente:

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) 
+1

Cosa succede se voglio chiamare solo geom_bar/geom_line/geom_point con variabili locali all'interno di una funzione - l'ambiente è un parametro sconosciuto. – Valentas

+0

Non riesco a ottenere queste proposte con 'p <- ggplot ... p + ggplot ...' funziona. Qualche modifica in 'ggplot' nella cosa? –

+0

Tuttavia, questo divertente simile * non * lavorare sulla mia macchina (ggplot2 2.2.1.9000): 'gg_fun <- la funzione (i dati, col) { p <- ggplot (dati, aes (x = COL), ambiente = ambiente()) p + geom_histogram()} ' ' gg_fun (mtcars, HP) ' –

15

Questo è un esempio di un problema che viene discusso earlier. Fondamentalmente, si tratta principalmente di ggplot2 che viene codificato per l'utilizzo nell'ambiente globale. Nella chiamata aes(), le variabili vengono cercate nell'ambiente globale o all'interno del dataframe specificato.

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

EDIT:

aggiornamento: Dopo aver visto l'altra risposta e aggiornare il pacchetto ggplot2, il codice precedente funziona. La ragione è, come spiegato nei commenti, che ggplot cercherà le variabili in aes nell'ambiente globale (quando il dataframe è specificamente aggiunto come meandf $ ...) o all'interno dell'ambiente menzionato.

Per questo, assicurati di lavorare con l'ultima versione di ggplot2.

+0

Questo non è corretto. ggplot valuta i nomi delle variabili all'interno di 'aes()' rispetto all'argomento 'data'. Hai solo bisogno di fare come gli altri stati di risposta. – Aaron

+0

@Aaron: il pacchetto ggplot deve essere aggiornato alla versione più recente affinché funzioni. Vedi la spiegazione nella modifica –

+1

Non dovresti usare '' 'aes_string()' '' qui ?? – marbel

16

Non credo che sia necessario includere la parte meansdf$ nella propria chiamata di funzione. Questo sembra funzionare sulla mia macchina:

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) 

produrre:

enter image description here

+0

Qui c'è una cosa sottile: significa che il file PDF è definito nell'ambiente globale. Tuttavia, anche senza farlo, funziona come suggerisci (senza i mezzi $). Qualcuno sa perché è ?? – trev

+3

@trev: perché ggplot cerca le variabili all'interno dell '"ambiente" del dataframe meansdf. –

+0

+1 come hai avuto la soluzione corretta. –

1

Risposta breve: Usa qplot

Risposta lunga: In sostanza si vuole qualcosa di simile:

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

Ma manca la flessibilità y perché è necessario attenersi alla costante denominazione delle colonne per evitare le fastidiose idiosincrasie del campo R. Naturalmente il passo logico successivo è:

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

Ma allora che inizia a cercare con sospetto, come una chiamata a qplot(), giusto?

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

Naturalmente ora si desidera cambiare le cose come i titoli di scala, ma per che una funzione è particolarmente utile ... la buona notizia è che le questioni di scoping sono per lo più andati.

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

Ecco un semplice trucco che uso molto per definire le mie variabili nel mio ambiente di funzioni (seconda riga):

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

Si noti come l'etichetta dell'asse y cambia anche variabili o dati quando diversi -set sono usati.

+1

Nota che esiste (al giorno d'oggi? Non sono sicuro che esistesse sempre.) Una soluzione molto meno invadente/hacky che funziona solo con il comando ggplot standard e in tutte le circostanze. Vedi [la mia risposta sotto] (http://stackoverflow.com/a/29595312/2207840). – jhin

+0

@jhin, sono d'accordo che questo metodo è hacky, ma meglio dire che la tua risposta non fornisce un esempio su come passare un secondo argomento (ad esempio 'x' o' y' in 'aes') su ggplot. Potresti aggiungere un esempio alla tua risposta con due argomenti nella funzione 'testplot'? – r3robertson

+0

@ r3robertson Non sono sicuro di aver capito cosa stai chiedendo. Nel mio esempio sto passando più argomenti a ggplot, tra gli altri per 'x' e' y'. Che cosa esattamente ti manca dall'esempio? Se vuoi passare, ad es., 'X' o' y' da un altro dataframe, fallo semplicemente ('aes (x = condition, y = otherdataframe $ colname)') ...? – jhin

1

Un'altra soluzione è quella di definire le aes (...) come una variabile della funzione:

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

Questo solo ha funzionato bene per me su un argomento simile

4

Questo mi frustrato per qualche tempo . Volevo inviare diversi frame di dati con nomi di variabili differenti e volevo la possibilità di tracciare colonne diverse dal frame di dati. Finalmente ho avuto un lavoro in giro con la creazione di alcuni fittizi variabili (globali) per gestire la stampa e costringendo l'assegnazione all'interno della funzione

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) 

} 

poi nel codice principale posso solo chiamare la funzione

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

IMHO questa è la soluzione più pragmatica, anche se non mi piacciono molto i globals. –

17

Il modo "corretto" per utilizzare ggplot di programmazione è quello di utilizzare al posto di aes_string()aes() e utilizzare i nomi delle colonne come caratteri piuttosto che come oggetti:

Per altri usi programmatici, ad esempio se si desidera che gli utenti siano in grado di specificare i nomi delle colonne per vari aspetti estetici come argomenti o se questa funzione sta andando in un pacchetto che deve passare R CMD CHECK senza avvisi sui nomi delle variabili senza definizioni, è possibile utilizzare aes_string(), con le colonne necessarie come caratteri.

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

Questa soluzione è esattamente ciò di cui avevo bisogno; grazie. – fredtal

+0

Perfetto, grazie –

0

ho solo creare nuove variabili cornice di dati con i nomi desiderati all'interno della funzione:

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

Non hai bisogno di qualcosa di speciale. Neanche variabili fittizie. Hai solo bisogno di aggiungere una stampa() all'interno della tua funzione, è come usare cat() quando vuoi che qualcosa venga mostrato nella console.

MyPlot < - ggplot (......) + Tutto quello che vuoi qui di stampa (MyPlot)

Ha funzionato per me più di una volta all'interno della stessa funzione