如何按列表中的项目名称保存绘图

How to save plots by names of items in a list

我可以保存一堆图,但它将它们命名为每个列表项的第一个值而不是变量的名称。

delm2<-data.frame(N = c(5.881, 5.671, 7.628, 4.643, 6.598, 4.485, 4.465, 4.978, 4.698, 3.685, 4.915, 4.983, 3.288, 5.455, 5.411, 2.585, 4.321, 4.661), 
                  t1 = c("N", "N", "T", "T", "N", "N", "T", "N", "N", "N", "N", "T", "T", "T", "T", "T", "T", "N"), 
                  t3 = c("r","v", "r", "v", "v", "r", "c", "c", "v", "r", "c", "c", "r", "v","c", "r", "v", "c"), 
                  B = c(1.3, 1.3, 1.33, 1.25, 1.4, 1.34, 1.36, 1.39, 1.36, 1.42, 1.38, 1.31, 1.37, 1.44, 1.22, 1.4, 1.46, 1.35))


library(boot)

lapply(as.list(delm2[,c('N','B')]), 
       function(i){
         bmp(filename = paste0(i,".bmp"), width = 350, height = 400)
         glm.diag.plots(glm(i ~ t1*t3,data=del))
         dev.off()   
       })

这会保存图,但它们是用数据中的数值命名的,而不是 lapply 的每个目标的名称... 即当前输出是两个名为“5.881”和“1.3”的文件,当我想要相同的两个文件但名为 "N" 和 "B"

我想我可以将 paste0(i,".bmp") 更改为 paste0(names(i),".bmp") 但这只是保存了第一个,根本没有名字。

看起来你可以在 How to save and name multiple plots with R 中给出仅是整数的名称,但我想要列表中变量的名称或 delm2 中的两个数字 NB .

Saving a list of plots by their names() 看来,使用 ggplot 输出会更容易,但 ggsave 在一个 glm.diag.plots 输出上不起作用。

(忽略我之前使用 Map 的建议。)

最大的收获是如何动态推导公式。一种方法是使用 as.formula,它接受一个字符串并将其转换为可以在模型生成函数中使用的公式(例如)。

使用 lapply(as.list(delm2[,c('N','B')]), ...) 的一个问题是数据的其余部分(即列 t1t3)不会被传递,一次只传递一个向量。 (我想知道您对 del 的引用是否是错字、un-released/hidden 数据或其他原因。)

试试这个:

lapply(c("N", "B"), function(nm) {
  bmp(filename = paste(nm, ".bmp"), width = 350, height = 400)
  glm.diag.plots(glm(as.formula(paste(nm, "~ t1*t3")), data = delm2))
  dev.off()
})

总的来说,我不喜欢在这些函数中破坏作用域。也就是说,当我可以很容易地传递数据时,我尽量不去 lapply 之外获取数据。上面的迂腐语言可能看起来像:

lapply(c("N", "B"), function(nm, x) {
  bmp(filename = paste(nm, ".bmp"), width = 350, height = 400)
  glm.diag.plots(glm(as.formula(paste(nm, "~ t1*t3")), data = x))
  dev.off()
}, x = delm2)

虽然这保留了范围,但如果您不了解正在发生的事情,可能会感到困惑。

这可能是使用 for 而不是 *apply* 函数之一的好时机。你想要的一切都有副作用,并且由于 for*apply 实际上是相同的速度,你获得了可读性:

for (nm in c("N", "B")) {
  bmp(filename = paste(nm, ".bmp"), width = 350, height = 400)
  glm.diag.plots(glm(as.formula(paste(nm, "~ t1*t3")), data = delm2))
  dev.off()
}

(本例中没有"scope breach",所以我使用了原来的变量。)


附带地,以配合我现在编辑的错误答案,其中包括 Map。这是一个使用 Map 的示例,它可以更多地展示 Map(和 mapply)正在做什么,反之实际上可以改善您的即时需求。

如果出于某种原因你想让它们命名为不同于 "N.bmp" 的东西,你可以这样做:

Map(function(fn, vn, x) {
  bmp(filename = paste(nm, ".bmp"), width = 350, height = 400)
  glm.diag.plots(glm(as.formula(paste(nm, "~ t1*t3")), data = x))
  dev.off()
}, c("N2.bmp", "b3456.bmp"), c("N", "B"), list(delm2))

这里有两点需要注意:

  • list(delm2) 的用途是将该结构包装成单个 "thing",重复传递给映射函数。如果我们只做 delm2(没有 list(...)),那么它将尝试将 delm2 的第一列与每个第一个元素一起使用。这在其他情况下可能很有用,但在您的 glm 示例中,您需要存在其他列,因此您不能一次只包含一列。 (好吧,也有办法做到这一点......但目前很重要。)
  • 第一次调用匿名函数,fn"N2.bmp",vnis"N", andxis the full dataset ofdelm2. The second time the anon-func is called,fnis"b3456.bmp",vnis"B", andxis again the full dataset ofdelm2`.

我将这部分标记为 "parenthetic" 因为它确实不会增加 这个 问题,但是自从我在我的第一个答案中开始那样,我想我会继续使用方法论,我选择 Map 的 "why"。最后,我认为 for 解决方案或 lapply 解决方案之一应该适合您。