2012-05-18 26 views
45

Próbuję użyć zmiennej lokalnej w aes, kiedy działam z ggplotem. To jest mój problem sprowadza się do istoty:Zmienne lokalne w ramach AES

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) 

Powoduje następującego błędu:

Error in eval(expr, envir, enclos) : object 'YMul' not found 

Wydaje się, że nie mogę używać zmiennych lokalnych (lub argumenty funkcji) w aes. Czy to możliwe, że występuje z powodu zawartości aes wykonywanych później, gdy zmienna lokalna jest poza zakresem? Jak mogę uniknąć tego problemu (poza używaniem zmiennej lokalnej w ramach aes)?

+0

myślę ponieważ nadal oczekuje, aby przejść w dół Ymul ale tylko dać plotfunc (XY) – zhan2383

+0

nieprawda, powinno ono wykorzystać domyślna wartość – baptiste

+0

Używam powyższego kodu i nie otrzymuję żadnego błędu (23 października 2017 r.), czy była aktualizacja "ggplot2", aby wyjaśnić, dlaczego to zadziała? – PatrickT

Odpowiedz

37

i przechwyciłoby lokalne środowisko,

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

Być może jest to oficjalna (ale nieudokumentowana) droga, jak sądzę. – kohske

+8

Szczerze mówiąc, myślę, że tak naprawdę powinno to być domyślne. Podobnie jak w przypadku plyr, zawsze jestem głęboko zdezorientowany, gdy ** ply nie znajdzie zmiennej, którą mógłby znaleźć inny R z normalnymi regułami zasięgu. – baptiste

+2

+1 - @kohske and @baptiste. Też lubię to najlepiej.Warto jednak zauważyć, że robi on coś innego niż moje rozwiązanie, co można zaobserwować przez: (1) usunięcie 'y = 1: 10' z data.frame' xy'; (2) umieszczanie 'y <-1: 10' w środowisku globalnym; i (3) wstawianie 'y <-10: 1' w ciele funkcji przed wywołaniem ggplota. Zasadniczo moje rozwiązanie pozwala na przekazywanie wybranych argumentów, bez konieczności zmiany reguł zasięgu. Twój całkowicie zmienia zachowanie zakresu ggplot() (dlatego tak mi się podoba). –

5

ggplot() jest aes oczekuje YMul być zróżnicowany w ramach data danych. Spróbuj tym YMull tam zamiast:

Dzięki @Justin: ggplot() „s aes wydaje szukać YMul w ramie data danych pierwszy, a jeśli nie znaleziono, a następnie w globalnym środowisku. Lubię dodawać takie zmienne do ramki danych, co jest sensowne dla mnie koncepcyjnie. Nie muszę też martwić się zmianami zmiennych globalnych, które mają nieoczekiwane konsekwencje dla funkcji. Ale wszystkie inne odpowiedzi również są poprawne. Użyj więc tego, który ci odpowiada.

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

Albo, jeśli chcesz funkcję w swojej przykład:

plotfunc <- function(Data, YMul = 2) 
{ 
    ggplot(cbind(Data, YMul), aes(x = x, y = y * YMul)) + geom_line() 
} 

plotfunc(xy) 
+2

'YMul' nie musi być częścią data.frame. Trzeba go określić w zakresie, w którym oceniany jest obiekt 'ggplot', który jest raczej globalny niż w funkcji. – Justin

+0

@ Justin: Dzięki. Nie zdawałem sobie z tego sprawy. Interesujące, że 'ggplot()' wydaje się najpierw szukać 'YMul' w ramce danych, a jeśli nie zostanie znalezione w środowisku globalnym, najwyraźniej pomija argumenty funkcji. Nie znalazłem żadnych informacji o tym, jak 'ggplot()' przeszukuje przestrzenie nazw, ale potem znowu nie wyglądam bardzo ciężko. – jthetzel

+0

Jest to zdecydowanie łatwiejsza opcja do zapamiętania i wpisania. Być może nie wspaniale, jeśli twoja ramka danych ma miliard wierszy, ale jest wygodna w innych sytuacjach. – PatrickT

0

Jeśli wykonanie kodu poza funkcją to działa. A jeśli wykonasz kod w ramach funkcji o zdefiniowanym globalnie YMul, to działa. Nie w pełni zrozumieć wewnętrzne funkcjonowanie ggplot ale to działa ...

YMul <- 2 

plotfunc <- function(Data){ 
    ggplot(Data,aes(x=x,y=y*YMul))+geom_line() 
} 

plotfunc(xy) 
10

Oto alternatywa, która pozwala przechodzić w dowolnej wartości przez YMul argumentu bez konieczności dodawania go do Data data.frame lub do globalnego środowiska:

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) 

, aby zobaczyć jak to działa, wypróbuj następującą linię w izolacji:

substitute({ggplot(Data, aes(x=x, y=y*YMul))}, list(YMul=100)) 
+0

+1 Dzięki! Wiedziałem, że jest sposób, żeby to zrobić, ale nigdy nie zdążyłem rozwiązać tego problemu. Bardzo fajny. – Justin

+1

@Justin - Cieszę się, że to pomocne. To, co * nigdy * nie znalazłem czasu na rozwiązanie, to jak działa oparte na protokole prototypowanie ggplota. Jako przykład, właśnie umieściłem instrukcję 'browser()' wewnątrz wywołania 'aes()', a po wpisaniu 'sys.frames()', otrzymuję listę 23 środowisk, z których żadna (??) wydaje się pozwalać na bezpośredni dostęp do wartości 'YMul'. Hmm. –

+0

Tak ... to poza mną. Miałem kod [kod niestandardowy] (http://stackoverflow.com/questions/9586882/new-ggplot2-and-ustom-boxplot-code) dzięki uprzejmości Kohske, który zerwał z nowym wydaniem i jest dla mnie całkowicie nieodgadniony! Któregoś dnia chciałbym zrozumieć proto ... – Justin

1

Czy spojrzałeś na rozwiązanie podane przez @wch (W. Chang)?

https://github.com/hadley/ggplot2/issues/743

myślę, że jest lepszy

istocie jest, że jak @baptiste ale zawierają odniesienie do środowiska bezpośrednio w wywołaniu ggplot

to zgłosić tutaj

g <- function() { 
    foo3 <- 4 
    ggplot(mtcars, aes(x = wt + foo3, y = mpg), 
     environment = environment()) + 
    geom_point() 
} 

g() 
# Works 
+0

To jest duplikat odpowiedzi @ baptiste, a IMO niepotrzebnie używa innego przykładu, pod warunkiem, że OP zapewnia odtwarzalny przykład. Proponuję usunąć (i być może komentować baptystę z problemem Githuba, który łączysz). –

4

Używam ggplot2, a twój przykład wydaje się działać dobrze z bieżącą wersją.

Jednak łatwo jest wymyślić warianty, które nadal stwarzają problemy. Sam byłem zdezorientowany przez podobne zachowanie i tak znalazłem ten post (najlepszy wynik Google dla "ggplot, jak oceniać zmienne po zdaniu"). Na przykład, jeśli poruszamy ggplot z 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 

W powyższym wariancie „przechwytywanie środowiska lokalnego” nie jest rozwiązaniem, ponieważ ggplot nie jest wywoływana z wewnątrz funkcji, a jedynie ggplot ma „środowisko = "argument.

Ale istnieje teraz rodzina funkcji "aes_", "aes_string", "aes_q", które są podobne do "aes", ale przechwytują zmienne lokalne. Jeśli użyjemy "aes_" w powyższym, nadal otrzymamy błąd, ponieważ teraz nie wie o "x". Ale łatwo jest odnieść się do tych danych, co rozwiązuje problem:

plotfunc <- function(Data,YMul=2){ 
    geom_line(aes_(x=Data$x,y=Data$y*YMul)) 
} 
ggplot(xy)+plotfunc(xy) 
# works 
Powiązane problemy