Адресация x и y в aes по переменному числу
Мне нужно нарисовать диаграмму рассеяния с переменными адресации по номерам столбцов вместо имен, т.е. вместо ggplot(dat, aes(x=Var1, y=Var2))
Мне нужно что-то вроде ggplot(dat, aes(x=dat[,1], y=dat[,2]))
. (Я говорю "что-то", потому что последнее не работает).
Вот мой код:
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
Ответы
Ответ 1
Вариант ответа @Shadow с использованием новых функций из 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
создает символ из строки, содержащейся в переменной (поэтому сначала мы должны создать эти переменные в начале функции), затем !!
заключает в кавычки его, что означает, что он будет работать так, как если бы вы указали необработанные имена функций.
!!
работает только в контексте функций, предназначенных для его поддержки, обычно это функции tidyverse, иначе это просто означает "нет" (аналогично as.logical
)..
Ответ 2
Ваша проблема в том, что aes
не знает вашу функциональную среду, и она выглядит только внутри global environment
. Таким образом, переменная dat
, объявленная внутри функции, не видна функции ggplot2
aes
, если вы не передадите ее явно:
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)
}
Обратите внимание на аргумент environment = environment()
внутри команды ggplot()
. Теперь он должен работать.
Ответ 3
Try:
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)
}
Отредактировано, чтобы показать, что происходит. - aes_string использует цитируемые аргументы, имена получают их с помощью ваших чисел.
Ответ 4
Я настоятельно рекомендую использовать aes_q
вместо передачи векторов в aes
(@Arun answer). Это может выглядеть немного сложнее, но оно более гибко, когда, например, обновление данных.
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)
}
И вот причина, почему это предпочтительнее:
# 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
Примечание.. По состоянию на ggplot2 v2.0.0 aes_q()
был заменен на aes_()
, чтобы он соответствовал SE-версиям функций NSE в других пакетах.
Ответ 5
Для полноты я думаю, что безопаснее использовать имена столбцов вместо индексов, потому что позиции столбцов внутри фрейма данных могут быть изменены, что приведет к неожиданным результатам.
Функция plot_duo
ниже (взято из этого ответа), может использовать ввод либо в виде строк, либо в виде имен столбцов
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 ensym() 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)
}
Примените функцию plot_duo
столбцам, используя 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 <- rlang::exprs(v2, v3, v4)
plt2 <- plot_vars2 %>% purrr::map(., ~ plot_duo(testdata, .x, rlang::expr(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]]
![]()
Создано 2019-02-18 пакетом представлением (v0.2.1.9000)
Ответ 6
временное решение, которое я нашел на данный момент:
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)
}
Но мне это не очень нравится, потому что в моем реальном коде мне нужны другие столбцы из indata
, и здесь мне нужно будет определить их все явно в dat<-
...