【问题标题】:Using tidy eval in R packages在 R 包中使用 tidy eval
【发布时间】:2020-03-30 14:35:32
【问题描述】:

我有一个函数stacked_plot(),它使用整洁的评估来制作堆积图。我想将它包含在我的包中,并让该包中的另一个函数调用它。这是最小的示例:

stacked_plot <- function(data, what, by = NULL, date_col = date){

  by <- rlang::enquo(by)
  what <- rlang::ensym(what)
  date_col <- rlang::ensym(date_col)
  data <- data %>%
    dplyr::group_by(!!date_col, !!by) %>%
    dplyr::summarise(!!what := sum(!!what, na.rm = TRUE)) %>%
    dplyr::ungroup() %>%
    tidyr::complete(!!date_col, !!by, fill = rlang::list2(!!what := 0))

  p <- data %>%
    ggplot2::ggplot(ggplot2::aes(!!date_col, !!what, fill = !!by)) +
    ggplot2::geom_area(position = 'stack')
  print(p)
}

#' @importFrom rlang .data
call_plot <- function() {
  to_plot <- data.frame(date = rep(seq(lubridate::ymd('2020-01-01'),
                                       lubridate::ymd('2020-03-30'),
                                       by = '1 day'), each = 3)) %>%
    dplyr::mutate(cat = rep(c('A', 'B', 'C'), 90), v1 = runif(270))

  p <- to_plot %>%
    stacked_plot(what = .data$v1, by = .data$cat)
  return(p)
}

stacked_plot() 合并到一个包中效果很好,我可以交互地调用它。但是,load_all() 之后的 call_plot() 会导致错误。这是rlang::last_error() 的输出:

rlang::last_error()
<error/rlang_error>
Only strings can be converted to symbols
Backtrace:
  1. global::call_plot()
 10. mmmtools::stacked_plot(., what = .data$v1, by = .data$cat)
 11. rlang::ensym(what) R/stacked_plot.R:4:2
Run `rlang::last_trace()` to see the full context.

我相信这是由于整洁评估的一些特质。但是,我真的找不到任何关于在 R 包中使用 tidyeval 的特性的来源。我唯一知道的是,我不能真正直接使用带引号的变量,而是使用.data$variable 模式,我在call_plot() 中这样做了。

如何使用 adjust stacked_plot() 使其可用于其他包函数?

【问题讨论】:

  • @akrun 给出了一个很好的答案,但实际上,如果您尝试在您的 call_plot 函数中调用 stacked_plot(what = v1, by = cat),您的设置将起作用。

标签: r dplyr r-package rlang tidyeval


【解决方案1】:

似乎 OP 想要使用不带引号的列名。如果是这种情况,请将ensym 更改为enquo

stacked_plot <- function(data, what, by = NULL, date_col = date){

  by <- rlang::enquo(by)
  what <- rlang::enquo(what)
  date_col <- rlang::enquo(date_col)
  data %>%
    dplyr::group_by(!! date_col, !!by) %>%
    dplyr::summarise(!!what := sum(!!what, na.rm = TRUE)) %>%
      dplyr::ungroup() %>%
      tidyr::complete(!!date_col, !!by, fill = rlang::list2(!!what := 0)) %>%  
    ggplot2::ggplot(ggplot2::aes(!!date_col, !!what, fill = !!by)) +
     ggplot2::geom_area(position = 'stack')



}

call_plot <- function() {
  to_plot <- data.frame(date = rep(seq(lubridate::ymd('2020-01-01'),
                                       lubridate::ymd('2020-03-30'),
                                       by = '1 day'), each = 3)) %>%
    dplyr::mutate(cat = rep(c('A', 'B', 'C'), 90), v1 = runif(270))

  p <- to_plot %>%
    stacked_plot(what =  v1, by =  cat)
  return(p)
}

-调用函数

call_plot()


另外,enquo + !! 可以完全替换为{{}}

stacked_plot <- function(data, what, by = NULL, date_col = date){



  data %>%
    dplyr::group_by({{date_col}}, {{by}}) %>%
    dplyr::summarise( {{what}} := sum({{what}}, na.rm = TRUE)) %>%
    dplyr::ungroup() %>%
    tidyr::complete({{date_col}}, {{by}}, fill = rlang::list2({{what}} := 0))  %>% 
    ggplot2::ggplot(ggplot2::aes({{date_col}}, {{what}}, fill = {{by}})) +
    ggplot2::geom_area(position = 'stack')



}

也可以和上一个一样

call_plot()

【讨论】:

  • 正如@AllanCameron 所指出的,ensym 实际上工作得很好,解决方案是调用stacked_plot(what = v1, by = cat) 而不是stacked_plot(what = .data$v1, by = .data$cat)。但是,它会在构建包时引发no visible binding for global variable 'v1' 警告,我想知道什么是好的做法,因为推荐的做法是调用.data$v1 显然在这里失败了。
  • @kuba_ 你能不能作为一个新问题发帖。谢谢
  • 我知道我打开这个话题已经有一段时间了,但这确实是最初的问题。因此,我不确定如何从打开新线程中受益,因为问题和示例都是一样的。它现在唯一改变的是我们知道如何让它工作,但它似乎仍然是一个肮脏的解决方案,因为它无法通过 pkgbuild 检查。
猜你喜欢
  • 2019-04-25
  • 2019-03-29
  • 1970-01-01
  • 1970-01-01
  • 2020-10-23
  • 2018-08-11
  • 1970-01-01
  • 2021-12-03
  • 1970-01-01
相关资源
最近更新 更多