使用 purrr 时如何自定义 ggplot2 facet_grid 标签中的文本?

Posted

技术标签:

【中文标题】使用 purrr 时如何自定义 ggplot2 facet_grid 标签中的文本?【英文标题】:How to customize text in ggplot2 facet_grid label when using purrr? 【发布时间】:2021-10-24 20:45:10 【问题描述】:

我正在使用 purrr 和 ggplot2 一次创建多个图。对于每个方面的名称,我想保留组的名称,但我还想添加每个子组中的参与者数量。例如,“Manager (N = 200)”和“Employee (N = 3000)”。但是,当我尝试添加这个标签参数时:

    facet_grid(~.data[[group]],
               labeller = paste0(~.data[[group]], "(N = ", group_n$n, ")"))

我收到此错误:

Error in cbind(labels = list(), list(``, if (!is.null(.rows) || !is.null(.cols))  : 
  number of rows of matrices must match (see arg 2)

以下是带有简化数据集的可重现示例。我的目标是在他们的分面标题中包含子组及其样本大小。

library(purrr)
library(dplyr)
library(ggplot2)

#Data
test <- tibble(s1 = c("Agree", "Neutral", "Strongly disagree"),
               s2rl = c("Agree", "Neutral", NA),
               f1 = c("Strongly agree", NA, "Strongly disagree"),
               f2rl = c(NA, "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 function to make plots

facet_plots = function(variable, group, title) 
  total_n <- test %>%
    summarize(n = sum(!is.na(.data[[variable]])))
  
  
  group_n <- test %>%
    group_by(.data[[group]], .data[[variable]]) %>%
    summarize(n = sum(!is.na(.data[[variable]])))
  
  
  plot2 <- test %>%
    count(.data[[group]], .data[[variable]]) %>%
    mutate(percent = 100*(n / group_n$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 = ", total_n$n)) +
    coord_flip() +
    theme_minimal() +
    ylim(0, 100) +
    facet_grid(~.data[[group]],
               labeller = paste0(~.data[[group]], "(N = ", group_n$n, ")")) #issue is likely here
  
  output <- list(plot2)
  return(output)



#pmap call
my_plots <- expand_grid(tibble(item = names(test_items), title=titles),
                        group = group_name) %>%
  pmap(function(item, group, title)
    facet_plots(item, group, title))

my_plots

编辑:我也尝试了详细的解决方案here,我收到了同样的错误。

【问题讨论】:

【参考方案1】:

下面将允许您绘制具有特征variablegroup 的百分比,同时使用组名和计数绘制结果。

library(tidyr)
library(dplyr)
library(ggplot2)
library(purrr)
facet_plots <- function(variable, group, title="Title", dat) 
    
    variable <- sym(variable)
    group <- sym(group)
    sumdat <- dat %>%
        filter(!is.na(!!variable)) %>%
        group_by(!!group) %>%
        add_count() %>%
        mutate(lbl = paste0(!!group, " (N = ", n, ")")) %>%
        group_by(!!group, !!variable) %>%
        mutate(pct = 100 * n() / n) %>%
        slice(1L) %>%
        ungroup() %>%
        select(!!variable, !!group, n, pct, lbl)

    ggplot(sumdat, aes(x = !!variable, y = pct, group = !!group)) +
        geom_bar(stat = "identity") +
        labs(
            title = title
        ) +
        facet_grid(~lbl)



## Using starwars data
expand_grid(
    tibble(
        variable = c("hair_color", "skin_color", "birth_year"),
        title = c("Hair color", "Skin color", "Birth year")
    ),
    group = c("sex", "gender")) %>%
    mutate(title = paste(title, "by", group)) %>%
    pmap(facet_plots, dat = starwars)

使用pmap() 将创建一个存储为字符串的组合数据框。因此,facet_plots() 函数的参数将是字符串。前两行将字符串 variablegroup 转换为 R 可以在不带引号的情况下使用的符号(阅读更多 here 了解这意味着什么)。 “bang-bang 运算符”!! 告诉 R 您希望将值存储在变量中,而不是名称本身(请参阅help("!!"))。任何时候 R 看到!!variable,它都会将值理解为存储在参数variable 中的数据框中的变量名称。

下面,我展示了这适用于 OP 的原始数据,而不仅仅是 starwars 示例数据。

## Using OP's data
test <- tibble(s1 = c("Agree", "Neutral", "Strongly disagree"),
               s2rl = c("Agree", "Neutral", NA),
               f1 = c("Strongly agree", NA, "Strongly disagree"),
               f2rl = c(NA, "Disagree", "Strongly disagree"),
               level = c("Manager", "Employee", "Employee"),
               location = c("USA", "USA", "AUS"))

expand_grid(
    tibble(
        variable = c("s1", "s2rl", "f1", "f2rl"),
        title = c("S1 results", "Results for S2RL", 
                  "Fiscal Results for F1", "Financial Status of F2RL")
    ),
    group = c("level", "location")
) %>%
    mutate(title = paste(title, "by", group)) %>%
    pmap(facet_plots, dat = test)

我认为您的贴标机无法正常工作的原因是您传递的类型不正确。 labeller() 函数采用var = fxn 形式的参数,其中var 是构面网格中的变量名称fxn 是用于如何转换名称的函数。您向它传递了数据,然后传递了一个调用单独向量的函数。

【讨论】:

感谢您的回复! pmap 所做的是按组(例如,按位置的 S1、按员工的 S1、按位置的 S2rl 等)或在星球大战数据集中迭代我所有变量的整体组合,这相当于得到一个按性别绘制头发颜色,按性别绘制眼睛颜色等。迭代的某些东西使 R 感到困惑,当我不只做一个特定的变量/组时,我会遇到与您相同的问题。 啊,我明白了。我认为我已修复它,以便您可以使用pmap 并包含一个示例。我使用了starwars 数据,因为我很难准确地理解你想要从数据中得到什么。但是,我认为我更改了它,以便您可以通过facet_plotsdat 参数使用您喜欢的任何数据。 谢谢你的工作!它说我不能再奖励 18 小时的赏金,但我会的。如果您不介意,有几个问题: 和 !!意思是?另外,你能解释一下 slice(1L) 和 sym 在这里做什么吗?再次感谢您的帮助! 我扩展了解释,试图提供更好的上下文来帮助理解它为什么起作用。拥抱运算符 在这里解释得很好:***.com/a/62792494/12586249。 bang-bang 运算符!! 做同样的事情,所以我更改了答案以始终使用它。 slice(1L) 函数只接受每个变量组组合的第一次观察(1L 是表示 整数 1 的一种方式),因为相同的 npct 值重复变量组组合中的所有观察值。我们只需要一个,所以我们拿第一个。希望有帮助!

以上是关于使用 purrr 时如何自定义 ggplot2 facet_grid 标签中的文本?的主要内容,如果未能解决你的问题,请参考以下文章

R语言ggplot2可视化:使用purrr包的map函数基于嵌套的dataframe数据绘制多个可视化图像(包含2个子图)

自定义不同颜色的ggplot2轴标签

如何使用 ggplot2 + directlabels 为标签使用自定义名称

如何自定义ggplot2中geom_tile内的轮廓形状?

如何自定义 Plotly/R/ggplot2 动画断点(帧间距、持续时间)

如何在 ggplot2 中自定义图例?