16

我对如何将函数参数传递给 dplyr 和 ggplot 代码感到困惑。我正在使用最新版本的 dplyr 和 ggplot2 这是我生成条形图的代码(清晰度与平均价格)

diamond.plot<- function (data, group, metric) {
    group<- quo(group)
    metric<- quo(metric)
    data() %>% group_by(!! group) %>%
           summarise(price=mean(!! metric)) %>% 
           ggplot(aes(x=!! group,y=price))+
           geom_bar(stat='identity') 
}

diamond.plot(diamonds, group='clarity', metric='price')

错误:

Error in UseMethod("group_by_") : no applicable method for 'group_by_' applied to an object of class "packageIQR"

对于最新版本的 dplyr,下划线的 verbs_() 已被轻柔地弃用。看来我们应该使用quosures。

我的问题:

  • 有人可以澄清目前的最佳做法吗?
  • 上面的代码有什么问题?(请不要使用下划线 dplyr 动词..)

  • 在 ggplot 中,我知道我们可以使用 aes_string(),但在我的例子中,aes 中只有一个参数是从函数参数传递的。

提前致谢。

4

5 回答 5

8

现在完全支持整洁的评估,ggplot2 v3.0.0因此无需使用aes_aes_string不再使用。

library(rlang)
library(tidyverse)

diamond_plot <- function (data, group, metric) {
    quo_group  <- sym(group)
    quo_metric <- sym(metric)

    data %>%
        group_by(!! quo_group) %>%
        summarise(price = mean(!! quo_metric)) %>%
        ggplot(aes(x = !! quo_group, y = !! quo_metric)) +
        geom_col()
}

diamond_plot(diamonds, "clarity", "price")

reprex 包(v0.2.0) 于 2018 年 4 月 16 日创建。

于 2018-04-17T05:39:28.117 回答
6

我认为您还不能采用“正确”的方式,因为 ggplot2 不支持 tidyeval 语法,但它即将到来。

dplyr 部分代码的最佳实践是:

library(tidyverse)
library(rlang)

diamond_data <- function (data, group, metric) {
   quo_group <- enquo(group)
   quo_metric <- enquo(metric)
   data %>%
     group_by(!!quo_group) %>%
     summarise(price=mean(!!quo_metric))
}
diamond_data(diamonds, clarity, price)

要解决 ggplot2 中缺乏对 tidyeval 的支持,您可以这样做(注意函数调用中变量周围的引号):

diamond_plot <- function (data, group, metric) {
    quo_group <- parse_quosure(group)
    quo_metric <- parse_quosure(metric)
    data %>%
        group_by(!!quo_group) %>%
        summarise(price=mean(!!quo_metric)) %>%
        ggplot(aes_(x = as.name(group), y=as.name(metric)))+
        geom_bar(stat='identity')
}
diamond_plot(diamonds, "clarity", "price")

编辑——遵循@lionel 的评论:

diamond_plot <- function (data, group, metric) {
    quo_group <- sym(group)
    quo_metric <- sym(metric)
    data %>%
        group_by(!!quo_group) %>%
        summarise(price=mean(!!quo_metric)) %>%
        ggplot(aes_(x = quo_group, y= quo_metric)) +
        geom_bar(stat='identity')
}
diamond_plot(diamonds, "clarity", "price")
于 2017-08-01T14:36:54.600 回答
4

对我来说,解决这个问题的最“整洁”的方法看起来是quo_nameaes_string函数的组合。避免使用尾随下划线动词,aes_因为它们已被弃用。

diamond_plot <- function(data, group, metric) {
  quo_group <- enquo(group)
  str_group <- quo_name(quo_group)

  quo_metric <- enquo(metric)

  summary <- data %>%
     groupby(!!quo_group) %>%
     summarise(mean = mean(!!quo_metric))

  ggplot(summary) +
  geom_bar(aes_string(x = str_group, y = "mean"), stat = "identity")
}

diamond_plot(diamnonds, clarity, price)
于 2018-01-31T09:59:59.700 回答
3

sinQueso 的答案很有希望,但它错过了函数的目的,即适应不同的数据帧。“price”变量在以下行的函数中编码:

summarise(price=mean(!!quo_metric)) %>%

所以这个函数只有在输入变量是“价格”时才有效。

这是一个更好的解决方案,可用于任何数据框:

diamond_plot <- function (data, group, metric) {
        quo_group <- sym(group)
        quo_metric <- sym(metric)
        summary <- data %>%
                group_by(!!quo_group) %>%
                summarise(mean=mean(!!quo_metric))
                ggplot(summary, aes_string(x = group, y= "mean")) +
                geom_bar(stat='identity')
}
diamond_plot(diamonds, "clarity", "price")
于 2017-10-27T17:45:27.267 回答
3

您可以比 Daniel 的解决方案更进一步,以便汇总变量(度量)的名称随输入而变化。

diamond_plot <- function(data, group, metric) {
    quo_group <- rlang::sym(group)
    quo_metric <- rlang::sym(metric)
    metric_name <- rlang::sym(stringr::str_c("mean_", metric))
    data %>%
        group_by(!!quo_group) %>%
        summarize(!!metric_name := mean(!!quo_metric)) %>%
        ggplot(aes_(x = quo_group, y = metric_name)) +
        geom_bar(stat = 'identity')
}
diamond_plot(diamonds, "clarity", "price")
于 2017-11-29T14:13:53.950 回答