web-dev-qa-db-fra.com

Variables locales dans aes

J'essaie d'utiliser une variable locale dans aes lorsque je trace avec ggplot. C'est mon problème qui se résume à l'essentiel:

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)

Cela entraîne l'erreur suivante:

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

Il semble que je ne puisse pas utiliser de variables locales (ni d'arguments de fonction) dans aes. Se pourrait-il que cela se produise à cause du contenu de aes exécuté ultérieurement lorsque la variable locale est hors de portée? Comment puis-je éviter ce problème (autre que de ne pas utiliser la variable locale dans aes)?

45
fabb

Je capturerais l'environnement local,

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)
37
baptiste

Voici une alternative qui vous permet de transmettre n'importe quelle valeur à l'aide de l'argument YMul sans avoir à l'ajouter à Data data.frame ou à l'environnement global:

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)

Pour voir comment cela fonctionne, essayez la ligne suivante de manière isolée:

substitute({ggplot(Data, aes(x=x, y=y*YMul))}, list(YMul=100))
10
Josh O'Brien

La aes de ggplot() s'attend à ce que YMul soit une variable du cadre de données data. Essayez d’y inclure YMull:

Grâce à @Justin: la aes de ggplot() semble rechercher YMul dans le bloc de données data en premier, et si elle n’est pas trouvée, dans l’environnement global. J'aime ajouter de telles variables au bloc de données, comme suit, car cela me semble logique. De plus, je n'ai pas à m'inquiéter des changements apportés aux variables globales ayant des conséquences inattendues sur les fonctions. Mais toutes les autres réponses sont également correctes. Alors, utilisez celui qui vous convient le mieux.

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

Ou, si vous voulez la fonction dans votre exemple:

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

plotfunc(xy)
5
jthetzel

J'utilise ggplot2 et votre exemple semble bien fonctionner avec la version actuelle.

Cependant, il est facile de trouver des variantes qui créent encore des problèmes. J'étais moi-même décontenancé par un comportement similaire, et c'est la raison pour laquelle j'ai trouvé ce message (résultat Google supérieur pour "ggplot comment évaluer les variables une fois passées"). Par exemple, si nous déplaçons ggplot en dehors de 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

Dans la variante ci-dessus, "capturer l'environnement local" n'est pas une solution car ggplot n'est pas appelé depuis la fonction, et seul ggplot a l'argument "environment =".

Mais il existe maintenant une famille de fonctions "aes_", "aes_string", "aes_q" qui ressemblent à "aes" mais capturent des variables locales. Si nous utilisons "aes_" dans ce qui précède, nous avons toujours une erreur car maintenant, il ne sait pas à propos de "x". Mais il est facile de se référer directement aux données, ce qui résout le problème:

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

Avez-vous examiné la solution donnée par @wch (W. Chang)?

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

Je pense que c'est le meilleur

est essentiellement comme celle de @baptiste mais incluez la référence à l'environnement directement dans l'appel à ggplot

Je le rapporte ici

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

g()
# Works
1
BBrill

Si vous exécutez votre code en dehors de la fonction, cela fonctionne. Et si vous exécutez le code dans la fonction avec YMul défini globalement, cela fonctionne. Je ne comprends pas bien le fonctionnement interne de ggplot mais cela fonctionne ...

YMul <- 2

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

plotfunc(xy)
0
Justin