由可变数量的寻址在AES x和y(Addressing x and y in aes by vari

2019-07-21 07:07发布

我需要绘制散点图与他们的列数,而不是名址变量,即代替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 

Answer 1:

使用于新的功能@影子的答案的变化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从包含在变量中的字符串创建一个符号(所以我们首先必须创建在函数开始的变量),然后!! unquotes它,这意味着它会工作,如果你喂了功能的原始名称。

!! 只能在设计,支持它的功能,通常tidyverse职能范围内,否则它只是意味着“不不”(相当于as.logical )..



Answer 2:

你的问题是, 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)
}

注意参数environment = environment()的内部ggplot()命令。 现在应该工作。



Answer 3:

尝试:

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用途报价参数,名字让他们使用你的号码。



Answer 4:

我强烈建议使用aes_q ,而不是通过向量aes (@ Arun的答案)。 它可能看起来有点复杂,但它更灵活,当如更新数据。

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_()以便与其他包的NSE功能SE版本保持一致。



Answer 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年2月18日reprex包 (v0.2.1.9000)



Answer 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<- ...



文章来源: Addressing x and y in aes by variable number
标签: r ggplot2