R语言 AES中x和y的变址

ocebsuys  于 2023-03-10  发布在  其他
关注(0)|答案(8)|浏览(221)

我需要绘制一个散点图,用列号而不是名称来寻址变量,也就是说,我需要类似ggplot(dat, aes(x=dat[,1], y=dat[,2]))的东西来代替ggplot(dat, aes(x=Var1, y=Var2))。(我说'something'是因为后者不起作用)。
下面是我的代码:

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
oewdyzsn

oewdyzsn1#

问题是aes不知道你的函数的环境,它只在global environment中查找,所以,在函数中声明的变量dat对于ggplot2aes函数是 * 不可见的 除非你显式地 * 传递它:

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

注意ggplot()命令中的参数environment = environment(),它现在应该可以工作了。

mccptt67

mccptt672#

我强烈建议使用aes_q而不是将向量传递给aes(@Arun 's 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

**注意:*自 * ggplot 2 v2.0.0起,aes_q()已替换为aes_(),以与其他软件包中SE函数的SE版本保持一致。

nwnhqdif

nwnhqdif3#

试试看:

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使用带引号的参数,names使用您的数字获取它们。

gdrx4gfi

gdrx4gfi4#

使用ggplot2 V3.0.0中的新特性对@Shadow的答案进行了修改:

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函数,否则它只表示“not not”(类似于as.logical)。

hc8w905p

hc8w905p5#

出于完整性考虑,我认为使用列名而不是索引更安全,因为数据框中的列位置可以更改,从而导致意外结果。
下面的plot_duo函数(取自this answer)可以将输入用作字符串或空列名

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

使用purrr::map()跨列应用plot_duo函数

### 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]]

reprex package(版本0.2.1.9000)于2019年2月18日创建

qyyhg6bp

qyyhg6bp6#

aes_()aes_quote()方法现在已软弃用。一种与准引号一致的简单方法是通过.data[[col_name]]调用列名。您可以轻松地根据位置提取列名。例如:

library(ggplot2)
library(dplyr)

showplot1<-function(indata, inx, iny){
  dat<-indata
  col_names <- names(indata)
  col_name_x <- col_names[[inx]]
  col_name_y <- col_names[[iny]]
  
  print(nrow(dat)); # this is just to show that object 'dat' is defined
  p <- ggplot(dat, aes(x=.data[[col_name_x]], y=.data[[col_name_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))
showplot1(indata=testdata, inx=2, iny=3)
#> [1] 100

reprex package(v2.0.0)于2021年9月22日创建

zzzyeukh

zzzyeukh7#

作为@moodymudskipper答案的补充,如果您想在magrittr管道中使用它,可以使用

testdata %>% 
    ggplot(aes(x=!!sym(names(.)[2]), y=!!sym(names(.)[3]))) +
    geom_point(size=4, alpha = 0.5)

此外,如果只想在特定图层中使用aes,则可以使用

testdata %>% 
    {ggplot(., aes(x=!!sym(names(.)[2]))) +
    geom_point(aes(y=!!sym(names(.)[3])), size=4, alpha = 0.5)}

当然,如果需要,可以将其 Package 成函数:

showplot <- function(indata, inx, iny){
    indata %>% 
        ggplot(aes(x=!!sym(names(.)[inx]), y=!!sym(names(.)[iny]))) +
        geom_point(size=4, alpha = 0.5)
}

尽管这会失去使用管道的意义

u7up0aaq

u7up0aaq8#

我暂时找到了一个临时解决方案:

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<-中显式定义所有列...

相关问题