Подтвердить что ты не робот

Локальные переменные внутри aes

Я пытаюсь использовать локальную переменную в aes, когда я рисую с помощью ggplot. Это моя проблема сводилась к сути:

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)

Это приводит к следующей ошибке:

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

Кажется, я не могу использовать локальные переменные (или аргументы функции) в aes. Может быть, это происходит из-за того, что содержимое aes выполняется позже, когда локальная переменная выходит за пределы области видимости? Как я могу избежать этой проблемы (кроме как не использовать локальную переменную в aes)?

4b9b3361

Ответ 1

Я бы захватил локальную среду,

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)

Ответ 2

Здесь альтернатива, которая позволяет передавать любое значение через аргумент YMul, не добавляя его в файл Data data.frame или в глобальную среду:

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)

Чтобы узнать, как это работает, попробуйте следующую строку в отдельности:

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

Ответ 3

ggplot() aes ожидает, что YMul будет переменной в кадре данных data. Вместо этого попробуйте включить YMull:

Благодаря @Justin: ggplot() aes сначала ищет YMul в кадре данных data, а если не найден, то в глобальной среде. Мне нравится добавлять такие переменные в фрейм данных, как это следует, поскольку это имеет смысл для меня концептуально. Мне также не нужно беспокоиться об изменениях глобальных переменных, которые имеют неожиданные последствия для функций. Но все остальные ответы также верны. Итак, используйте то, что вам подходит.

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

Или, если вы хотите использовать функцию в вашем примере:

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

plotfunc(xy)

Ответ 4

Я использую ggplot2, и ваш пример, похоже, отлично работает с текущей версией.

Однако, легко придумать варианты, которые все еще создают проблемы. Я сам был смущен подобным поведением, и как я нашел этот пост (верхний результат Google для "ggplot, как оценивать переменные при передаче" ). Например, если мы переместим ggplot из 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

В приведенном выше варианте "захват локальной среды" не является решением, потому что ggplot не вызывается из функции, и только ggplot имеет аргумент "environment =".

Но теперь существует семейство функций "aes_", "aes_string", "aes_q", которые похожи на "aes", но фиксируют локальные переменные. Если мы используем "aes_" в приведенном выше, мы все равно получаем ошибку, потому что теперь он не знает о "x". Но легко обращаться к данным напрямую, что решает проблему:

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

Ответ 5

Вы посмотрели решение, данное @wch (W. Chang)?

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

Я думаю, что это лучший

по существу похож на файл @baptiste, но включает ссылку на среду непосредственно в вызове ggplot

Я сообщаю об этом здесь

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

g()
# Works

Ответ 6

Если вы выполняете свой код вне функции, он работает. И если вы выполняете код внутри функции с YMul, определяемым глобально, он работает. Я не совсем понимаю внутреннюю работу ggplot, но это работает...

YMul <- 2

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

plotfunc(xy)