Je dois dessiner un diagramme de dispersion avec les variables d'adressage par leur numéro de colonne plutôt que par leur nom, c'est-à-dire plutôt que par ggplot(dat, aes(x=Var1, y=Var2))
, il me faut quelque chose comme ggplot(dat, aes(x=dat[,1], y=dat[,2]))
. (Je dis «quelque chose» parce que ce dernier ne fonctionne pas).
Voici mon code:
showplot1<-function(indata, inx, iny){
dat<-indata
print(nrow(dat)); # this is just to show that object 'dat' is defined
p <- ggplot(dat, aes(x=dat[,inx], y=dat[,iny]))
p + geom_point(size=4, alpha = 0.5)
}
testdata<-data.frame(v1=rnorm(100), v2=rnorm(100), v3=rnorm(100), v4=rnorm(100), v5=rnorm(100))
showplot1(indata=testdata, inx=2, iny=3)
# Error in eval(expr, envir, enclos) : object 'dat' not found
Une variante de la réponse de @ Shadow utilisant les nouvelles fonctionnalités de ggplot2 V3.0.0
:
showplot <- function(indata, inx, iny){
nms <- names(indata)
x <- nms[inx]
y <- nms[iny]
p <- ggplot(indata, aes(x = !!ensym(x), y = !!ensym(y)))
p + geom_point(size=4, alpha = 0.5)
}
testdata <- data.frame(v1=rnorm(100), v2=rnorm(100), v3=rnorm(100), v4=rnorm(100), v5=rnorm(100))
names(testdata) <- c("a-b", "c-d", "e-f", "g-h", "i-j")
showplot(indata=testdata, inx=2, iny=3)
ensym
crée un symbole à partir de la chaîne contenue dans une variable (nous devons donc d'abord créer ces variables au début de la fonction), puis !!
le cite, ce qui signifie que cela fonctionnera comme si vous aviez alimenté les noms bruts de la fonction.
!!
fonctionne uniquement dans le contexte de fonctions conçues pour le prendre en charge, généralement des fonctions ordonnées, sinon cela signifie simplement "ne pas" (équivalent à as.logical
).
Votre problème est que aes
ne connaît pas l'environnement de votre fonction et qu'elle ne fait que regarder dans global environment
. Ainsi, la variable dat
déclarée dans la fonction est non visible à ggplot2
'aes
fonction à moins que vous ne la transmettiez explicitement as:
showplot1<-function(indata, inx, iny) {
dat <- indata
p <- ggplot(dat, aes(x=dat[,inx], y=dat[,iny]), environment = environment())
p <- p + geom_point(size=4, alpha = 0.5)
print(p)
}
Notez l'argument environment = environment()
dans la commande ggplot()
. Cela devrait fonctionner maintenant.
Essayer:
showplot1 <- function(indata, inx, iny) {
x <- names(indata)[inx]
y <- names(indata)[iny]
p <- ggplot(indata, aes_string(x = x, y = y))
p + geom_point(size=4, alpha = 0.5)
}
Edité pour montrer ce qui se passe - aes_string utilise des arguments cités, les noms les obtiennent en utilisant vos numéros.
Je suggère fortement d'utiliser aes_q
au lieu de passer les vecteurs à aes
(la réponse de @ Arun). Cela peut sembler un peu plus compliqué, mais il est plus flexible, par exemple lorsque mise à jour des données.
showplot1 <- function(indata, inx, iny){
p <- ggplot(indata,
aes_q(x = as.name(names(indata)[inx]),
y = as.name(names(indata)[iny])))
p + geom_point(size=4, alpha = 0.5)
}
Et voici la raison pour laquelle c'est préférable:
# test data (using non-standard names)
testdata<-data.frame(v1=rnorm(100), v2=rnorm(100), v3=rnorm(100), v4=rnorm(100), v5=rnorm(100))
names(testdata) <- c("a-b", "c-d", "e-f", "g-h", "i-j")
testdata2 <- data.frame(v1=rnorm(100), v2=rnorm(100), v3=rnorm(100), v4=rnorm(100), v5=rnorm(100))
names(testdata2) <- c("a-b", "c-d", "e-f", "g-h", "i-j")
# works
showplot1(indata=testdata, inx=2, iny=3)
# this update works in the aes_q version
showplot1(indata=testdata, inx=2, iny=3) %+% testdata2
Remarque: À partir de ggplot2 v2.0.0 aes_q()
a été remplacé par aes_()
pour être cohérent avec les versions SE des fonctions NSE dans d'autres packages.
Pour être complet, je pense qu'il est plus prudent d'utiliser des noms de colonne plutôt que des index car les positions de colonne dans un cadre de données peuvent être modifiées, ce qui entraîne des résultats inattendus.
La fonction plot_duo
ci-dessous (tirée de cette réponse ) peut utiliser l'entrée sous forme de chaînes ou de noms de colonnes nues
library(rlang)
library(purrr)
library(dplyr)
library(ggplot2)
theme_set(theme_classic(base_size = 14))
set.seed(123456)
testdata <- data.frame(v1 = rnorm(100), v2 = rnorm(100), v3 = rnorm(100),
v4 = rnorm(100), v5 = rnorm(100))
plot_duo <- function(df, plot_var_x, plot_var_y) {
# check if input is character or bare column name to
# use sym() or enquo() accordingly
if (is.character(plot_var_x)) {
print('character column names supplied, use ensym()')
plot_var_x <- ensym(plot_var_x)
} else {
print('bare column names supplied, use enquo()')
plot_var_x <- enquo(plot_var_x)
}
if (is.character(plot_var_y)) {
plot_var_y <- ensym(plot_var_y)
} else {
plot_var_y <- enquo(plot_var_y)
}
# unquote the variables using !! (bang bang) so ggplot can evaluate them
pts_plt <- ggplot(df, aes(x = !! plot_var_x, y = !! plot_var_y)) +
geom_point(size = 4, alpha = 0.5)
return(pts_plt)
}
Appliquer la fonction plot_duo
sur les colonnes à l'aide de purrr::map()
### use character column names
plot_vars1 <- names(testdata)
plt1 <- plot_vars1 %>% purrr::map(., ~ plot_duo(testdata, .x, "v1"))
#> [1] "character column names supplied, use ensym()"
#> [1] "character column names supplied, use ensym()"
#> [1] "character column names supplied, use ensym()"
#> [1] "character column names supplied, use ensym()"
#> [1] "character column names supplied, use ensym()"
str(plt1, max.level = 1)
#> List of 5
#> $ :List of 9
#> ..- attr(*, "class")= chr [1:2] "gg" "ggplot"
#> $ :List of 9
#> ..- attr(*, "class")= chr [1:2] "gg" "ggplot"
#> $ :List of 9
#> ..- attr(*, "class")= chr [1:2] "gg" "ggplot"
#> $ :List of 9
#> ..- attr(*, "class")= chr [1:2] "gg" "ggplot"
#> $ :List of 9
#> ..- attr(*, "class")= chr [1:2] "gg" "ggplot"
# test plot
plt1[[3]]
### use bare column names
# Ref: https://stackoverflow.com/a/49834499/
plot_vars2 <- alist(v2, v3, v4)
plt2 <- plot_vars2 %>% purrr::map(., ~ plot_duo(testdata, .x, alist(v1)))
#> [1] "bare column names supplied, use enquo()"
#> [1] "bare column names supplied, use enquo()"
#> [1] "bare column names supplied, use enquo()"
str(plt2, max.level = 1)
#> List of 3
#> $ :List of 9
#> ..- attr(*, "class")= chr [1:2] "gg" "ggplot"
#> $ :List of 9
#> ..- attr(*, "class")= chr [1:2] "gg" "ggplot"
#> $ :List of 9
#> ..- attr(*, "class")= chr [1:2] "gg" "ggplot"
plt1[[2]]
Créé le 2019-02-18 par le paquet reprex (v0.2.1.9000)
solution provisoire que j'ai trouvée pour le moment:
showplot1<-function(indata, inx, iny){
dat<-data.frame(myX=indata[,inx], myY=indata[,iny])
print(nrow(dat)); # this is just to show that object 'dat' is defined
p <- ggplot(dat, aes(x=myX, y=myY))
p + geom_point(size=4, alpha = 0.5)
}
Mais je n'aime pas vraiment ça parce que dans mon vrai code, j'ai besoin d'autres colonnes de indata
et ici je devrai toutes les définir explicitement dans dat<-
...