You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在R中为多页PDF添加标注时出现空白PDF及报错的求助

问题:多页PDF添加标注时生成空白文件并报错

问题现象

  • 单页PDF添加标注可正常生成
  • 无标注的多页PDF能正常输出
  • 为多页PDF添加标注时,生成空白PDF并抛出错误:
Error in gList(list(`1` = list(data = list(), layers = list(<environment>,  : 
  only 'grobs' allowed in "gList"

数据示例

Sample_ID <- c("P1014B", "P1014F", "P1036A")
SCORE <- c(1500,2000,2500)
SCORE2 <- c(1254, 2100,2550)
SCORE3 <- c(1599, 1900, 2533)
SCORE4 <- c(1400, 1995, 2400)
SCORE5 <- c(1376, 2300, 2600)
df<- data.frame(Sample_ID, SCORE, SCORE2,SCORE3,SCORE4, SCORE5)

原代码示例

fn<- c("file1","file2","file3","file4")

for (i in 1:length(fn)){

  df<- read_tsv(fn[i])

colors<- c("Lower Limit 1500" = "red")
  a <- ggplot(df,aes(x=Sample_ID,y=`SCORE2`)) +
    geom_bar( stat="identity", fill="cyan4") +
    geom_hline(aes(yintercept=SCORE[1]), col = colors, size = 1.5, linetype=2, show.legend = TRUE) +
    geom_text(aes(label = `SCORE2`), nudge_y=4) +
    ggtitle("Median Score") +
    theme(plot.title = element_text(hjust = 0.5)) +
    scale_colour_manual(values=colors)

  colors<- c("Lower Limit 2000" = "red")
  b <- ggplot(df,aes(x=Sample_ID,y=`SCORE3`)) +
    geom_bar( stat="identity", fill="cyan4") +
    geom_hline(aes(yintercept=SCORE[2]), col = colors, size = 1.5, linetype=2, show.legend = TRUE) +
    geom_text(aes(label = `SCORE3`), nudge_y=4) +
    ggtitle("Median Score") +
    theme(plot.title = element_text(hjust = 0.5)) +
    scale_colour_manual(values=colors)


  colors<- c("Lower Limit 2500" = "red")
 c <- ggplot(df,aes(x=Sample_ID,y=`SCORE4`)) +
    geom_bar( stat="identity", fill="cyan4") +
    geom_hline(aes(yintercept=SCORE[1]), col = colors, size = 1.5, linetype=2, show.legend = TRUE) +
    geom_text(aes(label = `SCORE4`), nudge_y=4) +
    ggtitle("Median Score") +
    theme(plot.title = element_text(hjust = 0.5)) +
    scale_colour_manual(values=colors)


 colors<- c("Lower Limit 1500" = "red")
 d <- ggplot(df,aes(x=Sample_ID,y=`SCORE5`)) +
    geom_bar( stat="identity", fill="cyan4") +
    geom_hline(aes(yintercept=SCORE[1]), col = colors, size = 1.5, linetype=2, show.legend = TRUE) +
    geom_text(aes(label = `SCORE5`), nudge_y=4) +
    ggtitle("Median Score") +
    theme(plot.title = element_text(hjust = 0.5)) +
    scale_colour_manual(values=colors)


 ############ create the pdf

 ############# with annotation one page works

 pdf(file=paste0(fn[1]," with annotation one page.pdf"))

 figure <- ggarrange(a, b + font("x.text", size = 10),
                     ncol = 1, nrow = 2)
 annotate_figure(figure,
                 top = text_grob(paste0("QC Report
",fn[1],"
"), color = "red", face = "bold", size = 14),
                 bottom = text_grob( paste0("Date of run: 
  ", my_date, "  "), color = "#80919E",
                                     hjust = 1, x = 1, face = "italic", size = 10)
 )


 dev.off()

 }

  #############  without annotation two page works

  pdf(file=paste0(fn[1]," without annotation two page.pdf"))

 figure<-(ggarrange(a, b ,
                  ncol = 1, nrow = 2,
                  ggarrange(c, d,  ncol=1,nrow=2) ))

  print(figure)
  dev.off()



  ############# with annotation two page doesn't work

  pdf(file=paste0(fn[1]," with annotation two page.pdf"))

  figure<-(ggarrange(a, b ,
                     ncol = 1, nrow = 2,
                     ggarrange(c, d,  ncol=1,nrow=2) ))

   annotate_figure(figure,
                   top = text_grob(paste0("QC Report
",fn[1],"
"), color = "red", face = "bold", size = 14),
                   bottom = text_grob( paste0("Date of run: 
  ", my_date, "  "), color = "#80919E",
                                       hjust = 1, x = 1, face = "italic", size = 10))

  dev.off()

报错原因

annotate_figure仅支持处理单页的ggarrange对象。当嵌套ggarrange生成多页复合对象时,它无法识别这种结构,导致抛出"only 'grobs' allowed in 'gList'"错误,同时因为没有正确渲染内容,生成空白PDF。

另外原代码存在一处逻辑错误:循环中始终使用fn[1]而非fn[i],会导致所有输出文件都复用第一个文件名,需修正。

解决方案

方法:拆分页面分别添加标注后输出

将图表按页面分组排版,给每个单页的ggarrange对象单独添加标注,再依次打印到PDF中:

fn<- c("file1","file2","file3","file4")
# 假设my_date已定义,示例用系统日期
my_date <- Sys.Date()

for (i in 1:length(fn)){

  df<- read_tsv(fn[i])

  # 生成图表a-d的代码保持不变
  colors<- c("Lower Limit 1500" = "red")
  a <- ggplot(df,aes(x=Sample_ID,y=`SCORE2`)) +
    geom_bar( stat="identity", fill="cyan4") +
    geom_hline(aes(yintercept=SCORE[1]), col = colors, size = 1.5, linetype=2, show.legend = TRUE) +
    geom_text(aes(label = `SCORE2`), nudge_y=4) +
    ggtitle("Median Score") +
    theme(plot.title = element_text(hjust = 0.5)) +
    scale_colour_manual(values=colors)

  colors<- c("Lower Limit 2000" = "red")
  b <- ggplot(df,aes(x=Sample_ID,y=`SCORE3`)) +
    geom_bar( stat="identity", fill="cyan4") +
    geom_hline(aes(yintercept=SCORE[2]), col = colors, size = 1.5, linetype=2, show.legend = TRUE) +
    geom_text(aes(label = `SCORE3`), nudge_y=4) +
    ggtitle("Median Score") +
    theme(plot.title = element_text(hjust = 0.5)) +
    scale_colour_manual(values=colors)

  colors<- c("Lower Limit 2500" = "red")
  c <- ggplot(df,aes(x=Sample_ID,y=`SCORE4`)) +
    geom_bar( stat="identity", fill="cyan4") +
    geom_hline(aes(yintercept=SCORE[1]), col = colors, size = 1.5, linetype=2, show.legend = TRUE) +
    geom_text(aes(label = `SCORE4`), nudge_y=4) +
    ggtitle("Median Score") +
    theme(plot.title = element_text(hjust = 0.5)) +
    scale_colour_manual(values=colors)

  colors<- c("Lower Limit 1500" = "red")
  d <- ggplot(df,aes(x=Sample_ID,y=`SCORE5`)) +
    geom_bar( stat="identity", fill="cyan4") +
    geom_hline(aes(yintercept=SCORE[1]), col = colors, size = 1.5, linetype=2, show.legend = TRUE) +
    geom_text(aes(label = `SCORE5`), nudge_y=4) +
    ggtitle("Median Score") +
    theme(plot.title = element_text(hjust = 0.5)) +
    scale_colour_manual(values=colors)

  # 分页面组合图表
  page1 <- ggarrange(a, b, ncol=1, nrow=2)
  page2 <- ggarrange(c, d, ncol=1, nrow=2)

  # 给每个页面添加标注
  annotated_page1 <- annotate_figure(page1,
                   top = text_grob(paste0("QC Report\n",fn[i],"\n"), color = "red", face = "bold", size = 14),
                   bottom = text_grob( paste0("Date of run: \n  ", my_date, "  "), color = "#80919E",
                                       hjust = 1, x = 1, face = "italic", size = 10))

  annotated_page2 <- annotate_figure(page2,
                   top = text_grob(paste0("QC Report\n",fn[i],"\n"), color = "red", face = "bold", size = 14),
                   bottom = text_grob( paste0("Date of run: \n  ", my_date, "  "), color = "#80919E",
                                       hjust = 1, x = 1, face = "italic", size = 10))

  # 输出多页PDF
  pdf(file=paste0(fn[i]," with annotation two page.pdf"))
  print(annotated_page1)
  print(annotated_page2)
  dev.off()
}

关键修正点

  1. 将嵌套的ggarrange拆分为独立单页对象,分别用annotate_figure处理
  2. 修正循环中文件名引用错误:将fn[1]改为fn[i],确保每个输入文件对应正确的输出PDF
  3. 用print()显式打印每个标注后的页面,确保PDF正常渲染内容

内容的提问来源于stack exchange,提问作者user483292

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 15:15:36