【问题标题】:ggplot2 function - checking whether user input variable should be a mapped aestheticggplot2 函数 - 检查用户输入变量是否应该是映射美学
【发布时间】:2021-04-08 15:56:39
【问题描述】:

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

函数的简化版如下:

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)

# works as a variable
test_func(data, y)

reprex package (v2.0.0) 于 2021-04-08 创建

【问题讨论】:

    标签: r ggplot2 nse


    【解决方案1】:

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

    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
    

    【讨论】:

    • 这是一个比我更好的解决方案,非常感谢。
    【解决方案2】:

    你是对的。 NSE 可能有点麻烦。但是,如果您使用is.object(),请与 NSE 打交道,然后在您的 geom_point 通话中使用 show.legend 进行一些欺骗......

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

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

    【讨论】:

    • 太好了,非常感谢。这是一个比我更好的解决方案。我一直打算真正正确地进入 NSE,所以我真的理解它,而不是只在需要时学习单独的点点滴滴,但它正在寻找时间。
    • 哦,实际上,这恐怕不太行得通。使用test_func(data, 6) 时,它确实给出了一个图点大小实际上并没有改变点大小。
    • 该死的。你是对的。我只检查了你的两个测试用例。道歉。我有一个适用于variable 作为常量的解决方案,但是当variable 是一个变量时它会中断。交给我吧……
    • 没关系,我也花了一段时间才注意到!我的意思是有一个简单的方法来做到这一点 - 只需让用户必须写 6 或“y”,然后我可以使用一个简单的 is.numeric 控制流。但现在我的帽子里有一只蜜蜂,我不想强​​迫用户必须使用“y”而不是 y。我认为解决方案可能必须有某种 if 语句,然后是两个 geom_point,一个在 aes 内部,一个在外部。但它只是得到了一些可以在 if 语句中工作的东西,而不需要我的解决方案中的所有摆弄。
    猜你喜欢
    • 1970-01-01
    • 2016-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多