打印存储在列表中的 ggplot 对象时不保留 Facet 标签

Facet Labels not being retained when printing ggplot objects stored in a list

这是我将用来为我的问题提供上下文的数据:

library(dplyr)
library(tidyr)
library(ggplot2)

set.seed(1)
f1 <- sample(c(letters[1:3],NA),100, prob = c(rep((0.9/3),times = 3),0.1),replace = T)
f2 <- sample(c(letters[1:3],NA),100, prob = c(rep((0.8/3),times = 3),0.2),replace = T)
f3 <- sample(c(letters[1:3],NA),100, prob = c(rep((0.95/3),times = 3),0.01),replace = T)

sample_dat <- tibble(
  x1 = factor(f1, level=letters[1:3]),
  x2 = factor(f2, level=letters[1:3]),
  x3 = factor(f3, level=letters[1:3]),
  grpA = factor(sample(c("grp1","grp2"),100, prob=c(0.3, 0.7) ,replace=T), 
    levels = c("grp1", "grp2"))
  
)

sample_dat

这是我创建的用于准备绘图数据的函数:

plot_data_prepr <- function(dat, groupvar, mainvar){
  
  groupvar <- sym(groupvar)
  mainvar <- sym(mainvar)
  
  plot_data <- dat %>% 
    group_by(!!groupvar) %>% 
    count(!!mainvar, .drop = F) %>% drop_na() %>% 
    mutate(pct = n/sum(n),
         pct2 = ifelse(n == 0, 0.005, n/sum(n)),
         grp_tot = sum(n),
         pct_lab = paste0(format(pct*100, digits = 1),'%'),
         pct_pos = pct2 + .02)
  
  return(plot_data)
}

这里是生成数据集的函数应用程序,我将用于绘图

plot_data_prepr(dat = sample_dat, groupvar = "grpA", mainvar = "x1")
plot_data_prepr(dat = sample_dat, groupvar = "grpA", mainvar = "x2")
plot_data_prepr(dat = sample_dat, groupvar = "grpA", mainvar = "x3")

这里我使用 for 循环来绘制数据并动态更改刻面的标签——如果在 rstudio 作为一个 RMarkdown 文件,可以看到生成了图并且刻面的标签是 每个不同的,因为他们应该被赋予不同程度的缺失和采样密度 'grpA'变量。

plot_list <- vector('list', length = 0)

for (fct in names(sample_dat)[1:3]){
  
  mvar <- fct
  smvar <- sym(mvar)
  
  gvar <- "grpA"
  sgvar <- sym(gvar)
  
  
dd <- plot_data_prepr(dat = sample_dat, groupvar = gvar, mainvar = mvar)

pre_lookup <- dd %>% 
  select(!!sgvar, grp_tot) %>% 
  group_by(!!sgvar) %>% 
  summarise(lookup = mean(grp_tot))


lookup <- pre_lookup$lookup

  my_label <- function(x) {
    var <- names(x)[1]
    list(paste0(x[[var]], " (N = ", lookup, ")"))
  }
  
  
  plot <- ggplot(dd,
         mapping = aes(x=!!smvar, y = pct2, fill = !!smvar)) +
    geom_bar(stat = 'identity') +
    ylim(0,1.3) +
    geom_text(aes(x=!!smvar, label=pct_lab, y = pct_pos + .02)) +
    facet_grid(as.formula(paste0(".~", gvar)), labeller = my_label) +
    ggtitle(paste(gvar,"by",mvar))
  
  plot_list[[fct]] <- plot
  
  print(plot)

}

这是我的问题 -- 当我打印存储在列表中的图时, 他们似乎都保留了上一个图中的刻面标签,而不是保留 它们最初生成时显示的不同面标签。

for (name in names(sample_dat)[1:3]){
  print(plot_list[[name]])
}

基本上,我希望能够打印列表中的图 当我需要它们并让它们显示不同的面标签时 因为它们是最初制作地块时显示的。

也许社区中有人可以帮助我?

我建议你尽量避免地块建筑的循环。它用于创建标签或有时数据时遇到的那种问题。在这里,我将您的循环打包在一个函数中,并将结果存储在一个列表中。此外,您可以将 lapply() 与数据名称一起使用,以便直接创建包含图表的列表。这里的代码:

#Function for plot
myplotfun <- function(fct)
{
  mvar <- fct
  smvar <- sym(mvar)
  
  gvar <- "grpA"
  sgvar <- sym(gvar)
  
  
  dd <- plot_data_prepr(dat = sample_dat, groupvar = gvar, mainvar = mvar)
  
  pre_lookup <- dd %>% 
    select(!!sgvar, grp_tot) %>% 
    group_by(!!sgvar) %>% 
    summarise(lookup = mean(grp_tot))
  
  
  lookup <- pre_lookup$lookup
  
  
  my_label <- function(x) {
    var <- names(x)[1]
    list(paste0(x[[var]], " (N = ", lookup, ")"))
  }
  
  
  plot <- ggplot(dd,
                 mapping = aes(x=!!smvar, y = pct2, fill = !!smvar)) +
    geom_bar(stat = 'identity') +
    ylim(0,1.3) +
    geom_text(aes(x=!!smvar, label=pct_lab, y = pct_pos + .02)) +
    facet_grid(as.formula(paste0(".~", gvar)), labeller = my_label) +
    ggtitle(paste(gvar,"by",mvar))
  
  return(plot)
}

现在,我们创建一个列表:

#Create a list
plot_list <- lapply(names(sample_dat)[1:3],myplotfun)

最后,您在上一个循环中使用的图:

#Loop
for (i in 1:length(plot_list)){
  plot(plot_list[[i]])
}

输出:

问题是您的 my_label 函数有一个自由变量 lookup 只有当您实际绘制函数时才会解决。 for-loop 运行后,它只包含循环中的最后一个值。要捕获当前循环值,您可以将其放置在外壳内。因此,您可以将 my_label 函数更改为

  my_labeler <- function(lookup) {
    function(x) {
      var <- names(x)[1]
      list(paste0(x[[var]], " (N = ", lookup, ")"))
    }
  }

然后用

调用facet_grid
  facet_grid(as.formula(paste0(".~", gvar)), labeller = my_labeler(lookup))

但我同意@Duck 的观点,在这种情况下避免 for-loop 会更容易。