J'essaie d'écrire une fonction de tracé simple en utilisant la bibliothèque ggplot2. Mais l'appel à ggplot ne trouve pas l'argument de la fonction.
Prenons un data.frame
appelé means
qui stocke deux conditions et deux valeurs moyennes que je veux tracer (la condition apparaîtra sur l’axe des X et signifiera sur le 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
Il semble donc que ggplot appelle eval
, qui ne trouve pas l'argument meansdf
. Est-ce que quelqu'un sait comment je peux passer avec succès l'argument de la fonction à ggplot?
(Remarque: oui, je pourrais simplement appeler directement la fonction ggplot, mais au final, j'espère que ma fonction de complot fera des choses plus compliquées! :))
Comme Joris et Chase ont déjà répondu correctement, la meilleure pratique consiste à omettre simplement la partie meansdf$
et à se référer directement aux colonnes du bloc de données.
testplot <- function(meansdf)
{
p <- ggplot(meansdf,
aes(fill = condition,
y = means,
x = condition))
p + geom_bar(position = "dodge", stat = "identity")
}
Cela fonctionne car les variables référencées dans aes
sont recherchées soit dans l'environnement global, soit dans le cadre de données transmis à ggplot
. C'est aussi la raison pour laquelle votre exemple de code - avec meansdf$condition
etc. - n'a pas fonctionné: meansdf
n'est pas disponible dans l'environnement global, ni dans le cadre de données transmis à ggplot
, qui est meansdf
.
Le fait que les variables soient recherchées dans l'environnement global plutôt que dans l'environnement appelant est en fait un bogue connu dans ggplot2 que Hadley ne considère pas réparable pour l'instant on souhaite utiliser une variable locale, par exemple, scale
, pour influencer les données utilisées pour le tracé:
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")
}
Winston Chang fournit une solution de contournement très intéressante dans le problème GitHub référencé: Définition explicite du paramètre environment
sur l'environnement actuel lors de l'appel à ggplot
. Voici à quoi ressemblerait cet exemple:
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)
La "bonne" façon d'utiliser ggplot
par programme consiste à utiliser aes_string()
au lieu de aes()
et à utiliser les noms des colonnes sous forme de caractères plutôt que sous forme d'objets:
Pour des utilisations plus programmatiques, par exemple si vous voulez que les utilisateurs puissent spécifier des noms de colonne pour diverses esthétiques sous forme d'arguments, ou si cette fonction est intégrée à un paquet devant passer R CMD CHECK
sans avertissements sur les noms de variable sans définitions, vous pouvez utiliser aes_string()
, avec les colonnes nécessaires en tant que caractères.
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")
}
Voici une astuce simple que j'utilise beaucoup pour définir mes variables dans l'environnement de mes fonctions (deuxième ligne):
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")
Notez que l'étiquette de l'axe des y change également lorsque différentes variables ou ensembles de données sont utilisés.
Je ne pense pas que vous deviez inclure la partie meansdf$
dans votre appel de fonction. Cela semble fonctionner sur ma machine:
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)
produire:
Ceci est un exemple de problème qui est discuté plus tôt . En gros, il faut que ggplot2 soit codé pour être utilisé principalement dans l’environnement mondial. Dans l'appel aes (), les variables sont recherchées dans l'environnement global ou dans la trame de données spécifiée.
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")
}
MODIFIER:
update: Après avoir vu l'autre réponse et mis à jour le paquet ggplot2, le code ci-dessus fonctionne. Comme expliqué dans les commentaires, le motif est que ggplot recherchera les variables dans aes dans l'environnement global (lorsque le cadre de données est spécifiquement ajouté en tant que meandf $ ...) ou dans l'environnement mentionné.
Pour cela, assurez-vous de travailler avec la dernière version de ggplot2.
Cela m'a frustré pendant un certain temps. Je voulais envoyer différents cadres de données avec différents noms de variables et pouvoir tracer différentes colonnes du cadre de données. J'ai finalement trouvé un moyen de contourner le problème en créant des variables factices (globales) pour gérer le traçage et forcer l'affectation dans la fonction.
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)
}
puis dans le code principal, je peux simplement appeler la fonction
plotgraph(data,data$time,data$Y1)
plotgraph(data,data$time,data$Y2)
Vous n'avez besoin de rien d'extraordinaire. Même pas de variables factices. Il vous suffit d’ajouter un print () dans votre fonction, c’est comme utiliser cat () lorsque vous voulez que quelque chose soit affiché dans la console.
myplot <- ggplot (......) + Tout ce que vous voulez ici print (myplot)
Cela a fonctionné pour moi plus d'une fois dans la même fonction
Réponse courte: Utilisez qplot
Réponse longue: Essentiellement, vous voulez quelque chose comme ceci:
my.barplot <- function(x=this.is.a.data.frame.typically) {
# R code doing the magic comes here
...
}
Mais cela manque de flexibilité, car vous devez vous en tenir à un nom de colonne cohérent pour éviter les idiosyncrasies gênantes de l'étendue R. Bien sûr, la prochaine étape logique est la suivante:
my.barplot <- function(data=data.frame(), x=..., y....) {
# R code doing something really really magical here
...
}
Mais alors cela commence à ressembler étrangement à un appel à qplot (), non?
qplot(data=my.data.frame, x=some.column, y=some.other column,
geom="bar", stat="identity",...)
Bien sûr, vous voudriez maintenant changer des choses comme les titres d'échelle, mais pour cela, une fonction est pratique ... La bonne nouvelle est que les problèmes de cadrage ont pour la plupart disparu.
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')
Une autre solution consiste à définir le aes (...) en tant que variable de votre fonction:
func<-function(meansdf, aes(...)){}
Cela a bien fonctionné pour moi sur un sujet similaire
S'il est important de transmettre les variables (noms de colonnes) à la fonction de traçage personnalisée sans les citer, tandis que différents noms de variables sont utilisés dans la fonction, une autre solution que j'ai essayée consistait à utiliser match.call()
et eval
(comme ici ainsi que):
library(ggplot2)
meansdf <- data.frame(means = c(13.8, 14.8), condition = 1:2)
testplot <- function(df, x, y) {
arg <- match.call()
scale <- 0.5
p <- ggplot(df, aes(x = eval(arg$x),
y = eval(arg$y) * scale,
fill = eval(arg$x)))
p + geom_bar(position = "dodge", stat = "identity")
}
testplot(meansdf, condition, means)
Créé le 2019-01-10 par le paquet reprex (v0.2.1)
Une autre solution de contournement, mais en passant des variables entre guillemets à la fonction de traçage personnalisée, utilise get()
:
meansdf <- data.frame(means = c(13.8, 14.8), condition = 1:2)
testplot <- function(df, x, y) {
scale <- 0.5
p <- ggplot(df, aes(x = get(x),
y = get(y) * scale,
fill = get(x)))
p + geom_bar(position = "dodge", stat = "identity")
}
testplot(meansdf, "condition", "means")
Créé le 2019-01-10 par le paquet reprex (v0.2.1)
Je viens de générer de nouvelles variables de cadre de données avec les noms souhaités dans la fonction:
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")
}