Передать аргументы функции как dplyr, так и ggplot

Я смущен тем, как передавать аргумент функции в коды 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 передается из аргумента функции.

Спасибо заранее.

Ответ 1

Теперь ggplot2 v3.0.0 полностью поддерживается в 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")

Создано в 2018-04-16 пакетом reprex (v0.2.0).

Ответ 2

Я не думаю, что вы можете так "правильно", но 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)

Чтобы обойти отсутствие поддержки tidyeval в ggplot2, вы могли бы сделать (обратите внимание на кавычки вокруг переменных в вызове функции):

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

Ответ 3

Ответ sinQueso является многообещающим, но он пропускает назначение функции, которая должна быть адаптирована к различным кадрам данных. Переменная "цена" кодируется в функции в следующей строке:

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

Ответ 4

Вы можете пойти еще дальше решения Даниэля, чтобы имя сводной переменной (метрики) изменилось с помощью ввода.

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

Ответ 5

Самый "tidyeval" путь к этой проблеме для меня выглядит как комбинация функций quo_name и aes_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)