为什么 r purrr 的 pmap 显示 "Only strings can be converted to symbols" 而不是遍历数据集?

Why does r purrr's pmap say "Only strings can be converted to symbols" and not iterate over dataset?

我正在尝试使用 purrr 包中的 pmap 自动创建 ggplot 幻灯片。作为此 的扩展,我正在尝试根据我的数据中的组成员变量(级别和位置)进行分面。

与上一个问题不同,我知道有 3 个输入,所以我需要使用 pmap() 而不是 map2(),并且由于某种原因我不断收到此错误:

Error: Only strings can be converted to symbols
Run `rlang::last_error()` to see where the error occurred.

当我深入研究错误时,它显示问题出在我的第一个 pmap() 调用中:

<error/rlang_error>
Only strings can be converted to symbols
Backtrace:
  1. purrr::pmap(...)
 14. rlang::sym(variable)

所有的组合我都试过了,就是破解不了。我希望 R 按级别和位置迭代每个图。

这是我的代码和数据:

#Packages
library(dplyr)
library(purrr)
library(ggplot2)

#Data
test <- tibble(s1 = c("Agree", "Neutral", "Strongly disagree"),
               s2rl = c("Agree", "Neutral", "Strongly disagree"),
               f1 = c("Strongly agree", "Disagree", "Strongly disagree"),
               f2rl = c("Strongly agree", "Disagree", "Strongly disagree"),
               level = c("Manager", "Employee", "Employee"),
               location = c("USA", "USA", "AUS"))

#Get just test items for name
test_items <- test %>%
  dplyr::select(s1, s2rl, f1, f2rl)

#titles of plots for R to iterate over
titles <- c("S1 results", "Results for S2RL", "Fiscal Results for F1", "Financial Status of F2RL")


#group levels
group_name <- c("level", "location")

#custom ggplot function
faceted_plots = function(variable, group, title) {

  sample_size <- test %>%
    group_by(!! rlang::sym(group), !! rlang::sym(variable)) %>%
    summarize(n = sum(!is.na(!! rlang::sym(variable))))
  

  test %>%
    count(!! rlang::sym(group), !! rlang::sym(variable)) %>%
    mutate(percent = 100*(n / sample_size$n)) %>%
    drop_na() %>%
    ggplot(aes(x = !! rlang::sym(variable), y = percent, fill = .data[[variable]])) + 
    geom_bar(stat = "identity") +
    geom_text(aes(label= paste0(percent, "%"), fontface = "bold", family = "Arial", size=14), vjust= 0, hjust = -.5) +
    ylab("\nPercentage") +
    labs(
      title = title,
      subtitle = paste0("(N = ", sample_size$n, ")")) +
    coord_flip() +
    theme_minimal() +
    scale_fill_manual(values = c("Strongly disagree" = "#CA001B", "Disagree" = "#1D28B0", "Neutral" = "#D71DA4", "Agree" = "#00A3AD", "Strongly agree" = "#FF8200")) +
    scale_x_discrete(labels = c("Strongly disagree" = "Strongly\nDisagree", "Disagree" = "Disagree", "Neutral" = "Neutral", "Agree" = "Agree", "Strongly agree" = "Strongly\nAgree"), drop = FALSE) + 
    theme(axis.title.y = element_blank(),
          axis.text = element_text(size = 14, color = "gray28", face = "bold", hjust = .5),
          axis.title.x = element_text(size = 18, color = "gray32", face = "bold"),
          legend.position = "none",
          text = element_text(family = "Arial"),
          plot.title = element_text(size = 20, color = "gray32", face = "bold", hjust = .5),
          plot.subtitle = element_text(size = 16, color = "gray32", face = "bold", hjust = .5),
          panel.spacing.x = unit(2, "lines")) +
    ylim(0, 100) +
    facet_grid(~!! rlang::sym(group))
}

#pmap call
plots_and_facet <- pmap(
  list(x = names(test_items),
       y= titles,
       z = group_name),
  faceted_plots(test_items, titles, group_name))

使用 Flick 先生的解决方案进行编辑——有效!忽略计数方面的任何问题,因为那是我的问题,超出了这个问题的范围:

#custom ggplot function
faceted_plots = function(variable, group, title) {

  sample_size <- test %>%
    group_by(.data[[group]], .data[[variable]]) %>%
    summarize(n = sum(!is.na(.data[[variable]])))
  

  test %>%
    count(.data[[group]], .data[[variable]]) %>%
    mutate(percent = 100*(n / sample_size$n)) %>%
    drop_na() %>%
    ggplot(aes(x = .data[[variable]], y = percent, fill = .data[[variable]])) + 
    geom_bar(stat = "identity") +
    geom_text(aes(label= paste0(percent, "%"), fontface = "bold", family = "Arial", size=14), vjust= 0, hjust = -.5) +
    ylab("\nPercentage") +
    labs(
      title = title,
      subtitle = paste0("(N = ", sample_size$n, ")")) +
    coord_flip() +
    theme_minimal() +
    scale_fill_manual(values = c("Strongly disagree" = "#CA001B", "Disagree" = "#1D28B0", "Neutral" = "#D71DA4", "Agree" = "#00A3AD", "Strongly agree" = "#FF8200")) +
    scale_x_discrete(labels = c("Strongly disagree" = "Strongly\nDisagree", "Disagree" = "Disagree", "Neutral" = "Neutral", "Agree" = "Agree", "Strongly agree" = "Strongly\nAgree"), drop = FALSE) + 
    theme(axis.title.y = element_blank(),
          axis.text = element_text(size = 14, color = "gray28", face = "bold", hjust = .5),
          axis.title.x = element_text(size = 18, color = "gray32", face = "bold"),
          legend.position = "none",
          text = element_text(family = "Arial"),
          plot.title = element_text(size = 20, color = "gray32", face = "bold", hjust = .5),
          plot.subtitle = element_text(size = 16, color = "gray32", face = "bold", hjust = .5),
          panel.spacing.x = unit(2, "lines")) +
    ylim(0, 100) +
    facet_grid(~.data[[group]])
}

#pmap call
expand_grid(tibble(item = names(test_items), title=titles),
              group = group_name) %>%
  pmap(function(item, group, title)
    faceted_plots(item, group, title))

使用 pmap 你实际上需要传递一个函数,而不是为 .f= 参数调用函数。此外,如果您想要事物的所有可能组合,您首先需要在调用 pmap 之前使用 purrr::expand_grid 创建组合。所以你的电话看起来像

plots_and_facet <-
  expand_grid(tibble(item = names(test_items), title=titles),
              group = group_name) %>%
  pmap(function(item, group, title)
    faceted_plots(item, group, title))

你也有一堆 !!rlang::sym(variable) 的用法,但现在推荐的方法是 .data[[variable]] 你在某些地方确实有,但你应该把所有这些都改成使用.data 代词是安全的。