pass function arguments to both dplyr and ggplot

大城市里の小女人 提交于 2019-11-27 14:23:57

Tidy evaluation is now fully supported in ggplot2 v3.0.0 so it's not necessary to use aes_ or aes_string anymore.

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

Created on 2018-04-16 by the reprex package (v0.2.0).

I don't think you can that the "correct" way quite yet, as ggplot2 doesn't support the tidyeval syntax, but it's coming.

The best practice with the dplyr part of the code would be:

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)

To work around the lack of support of the tidyeval in ggplot2, you could do (note the quotes around the variables in the function call):

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

EDIT -- Following @lionel's comment:

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

sinQueso's answer is promising but it misses the purpose of a function, which is to be adaptable to different data frames. The "price" variable is encoded in the function in the following line:

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

so this function will only work if the input variable is "price".

Here is a better solution that can be used for any data frame:

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

You can go even further than Daniel's solution so that the name of the summary variable (metric) changes with the input.

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

The most "tidyeval" way to this problem to me looks as combination of quo_name and aes_string functions. Avoid using trailing underscore verbs like aes_ since they're getting deprecated.

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)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!