ggplot2 函数 - 检查用户输入变量是否应该是映射的美学

问题描述

我编写了一个函数来制作散点图,允许用户将点的大小输入为数值(保留在 R-10 调用之外)或作为数据中的变量要映射的框架(需要进入 aes() 调用)。我远非 NSE 专家,虽然我已经开始使用它,但我觉得一定有更好的方法来做到这一点?

函数的简化版本如下:

aes()

library(tidyverse)

data <- tibble(x = 1:10,y = 1:10)

test_func <- function(data,variable = 6){
  # capture the variable in vars (I think quote would also work in this function)
  variable <- vars({{variable}})
  
  # convert it to a string and check if the string starts with a digit
  # i.e. checking if this is a simple point size declaration not an aes mapping
  is_number <- variable[[1]] %>% 
    rlang::as_label() %>% 
    str_detect("^[:digit:]*$")
  
  # make initial ggplot object
  p <- ggplot(data,aes(x = x,y = y))
  
  # if variable is a simple number,add geom_point with no aes mapping
  if(is_number){
    variable <- variable[[1]] %>% 
      rlang::as_label() %>% 
      as.numeric()
    
    p <- p + geom_point(size = variable)
  } else{
    # otherwise it must be intended as an aes mapping variable  
    variable <- variable[[1]] %>% 
      rlang::as_label()
    
    p <- p + geom_point(aes(size = .data[[variable]]))
  }
  p
}

# works as a number
test_func(data,10)

reprex package (v2.0.0) 于 2021 年 4 月 8 日创建

解决方法

你说得对。 NSE 可能有点麻烦。但是,如果您使用 is.object(),请处理 NSE,然后在您的 show.legend 调用中使用 geom_point 作弊...

test_func <- function(data,variable = 6){
  qVariable = enquo(variable)
  needLegend <- !is.object(qVariable)
  data %>% 
    ggplot(aes(x = x,y = y)) + 
    geom_point(
      aes(size = !! qVariable),show.legend=needLegend
    )
}

在您的两个测试用例中提供与您的函数相同的输出。

,

一种选择是检查用户提供给 variable 的内容是否是 data 中的列。如果是,请在 aes() 映射中使用该列。如果不是,则评估变量并将结果提供给 size 之外的 aes()

test_func <- function(data,variable = 6) {
  v <- enquo(variable)
  gg <- ggplot(data,aes(x=x,y=y))
  
  if(exists(rlang::quo_text(v),data))
    gg + geom_point(aes(size=!!v))
  else
    gg + geom_point(size = rlang::eval_tidy(v))
}

# All of these work as expected:
test_func(data)      # Small points
test_func(data,10)  # Bigger points
test_func(data,x)   # Using column x

作为奖励,此解决方案允许您传递存储在变量中的值,而不是直接输入数字。只要变量名称不在 data 中,它就会被正确评估并提供给 size=

z <- 20
test_func(data,z)   # Works

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...