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

在R中使用lapply与ggplot保存多幅PDF图像失败的问题求助

问题:使用ggplot按分组保存图像时生成的PDF无法打开

我有一个带分组变量的数据框,想用ggplot为每个分组生成并保存单独的图像。用lapply拆分数据后,用pdf函数保存以分组命名的文件,但生成的文件打不开。

示例代码与数据

# 生成带分组变量的随机数据框
set.seed(123)
df <- data.frame(
  x = rnorm(100),
  y = rnorm(100),
  group = sample(LETTERS[1:4], 100, replace = TRUE)
)

# 使用lapply遍历每个分组
lapply(split(df, df$group), function(d) {
  # 绘制每个分组的x vs y散点图
  p <- ggplot(d, aes(x, y)) + geom_point() + ggtitle(paste("Group", d$group[1]))
  # 保存为以分组命名的PDF文件
  pdf(paste0("output_data/", d$group[1], ".pdf"))
  p
  dev.off()
})

已尝试的方法

  • 使用print(p)替代p
  • ggsave在我的数据上表现不佳
  • 不在sapply或lapply中运行脚本时一切正常

注意:同一脚本在其他设备上可以正常输出。


更新:sessionInfo() 输出

R version 4.2.1 (2022-06-23 ucrt)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 22000)

Matrix products: default

locale:
[1] LC_COLLATE=Chinese (Simplified)_China.utf8  LC_CTYPE=Chinese (Simplified)_China.utf8    LC_MONETARY=Chinese (Simplified)_China.utf8
[4] LC_NUMERIC=C                                LC_TIME=Chinese (Simplified)_China.utf8    

attached base packages:
[1] stats4    stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] cowplot_1.1.1          patchwork_1.1.2        ggrepel_0.9.1          plyranges_1.16.0       org.Hs.eg.db_3.15.0    annotatr_1.22.0       
 [7] ggforce_0.4.1          GenomicFeatures_1.48.4 AnnotationDbi_1.58.0   Biobase_2.56.0         ggbio_1.44.1           ggplot2_3.4.0         
[13] dplyr_1.1.0            rtracklayer_1.56.1     GenomicRanges_1.48.0   GenomeInfoDb_1.32.4    IRanges_2.30.1         S4Vectors_0.34.0      
[19] AnnotationHub_3.4.0    BiocFileCache_2.4.0    dbplyr_2.2.1           BiocGenerics_0.42.0   

loaded via a namespace (and not attached):
  [1] backports_1.4.1               Hmisc_4.7-1                   systemfonts_1.0.4             plyr_1.8.7                    
  [5] lazyeval_0.2.2                splines_4.2.1                 BiocParallel_1.30.4           digest_0.6.29                
  [9] ensembldb_2.20.2              htmltools_0.5.3               fansi_1.0.3                   magrittr_2.0.3               
 [13] checkmate_2.1.0               memoise_2.0.1                 BSgenome_1.64.0               cluster_2.1.3                
 [17] tzdb_0.3.0                    readr_2.1.3                   Biostrings_2.64.1             matrixStats_0.62.0           
 [21] timechange_0.1.1              prettyunits_1.1.1             jpeg_0.1-9                    colorspace_2.0-3              
 [25] blob_1.2.3                    rappdirs_0.3.3                textshaping_0.3.6             xfun_0.33                     
 [29] crayon_1.5.2                  RCurl_1.98-1.9                graph_1.74.0                  survival_3.3-1               
 [33] VariantAnnotation_1.42.1      glue_1.6.2                    polyclip_1.10-0               gtable_0.3.1                 
 [37] zlibbioc_1.42.0               XVector_0.36.0                DelayedArray_0.22.0           scales_1.2.1                 
 [41] DBI_1.1.3                     GGally_2.1.2                  Rcpp_1.0.9                    xtable_1.8-4                 
 [45] progress_1.2.2                htmlTable_2.4.1               foreign_0.8-82                bit_4.0.4                     
 [49] OrganismDbi_1.38.1            Formula_1.2-4                 htmlwidgets_1.5.4             httr_1.4.4                    
 [53] RColorBrewer_1.1-3            ellipsis_0.3.2                pkgconfig_2.0.3               reshape_0.8.9                 
 [57] XML_3.99-0.11                 farver_2.1.1                  nnet_7.3-17                   deldir_1.0-6                 
 [61] utf8_1.2.2                    RMariaDB_1.2.2                tidyselect_1.2.0              labeling_0.4.2               
 [65] rlang_1.0.6                   reshape2_1.4.4                later_1.3.0                   munsell_0.5.0                 
 [69] BiocVersion_3.15.2            tools_4.2.1                   cachem_1.0.6                  cli_3.4.1                     
 [73] generics_0.1.3                RSQLite_2.2.18                stringr_1.4.1                 fastmap_1.1.0                 
 [77] ragg_1.2.4                    yaml_2.3.5                    knitr_1.40                    bit64_4.0.5                   
 [81] purrr_0.3.5                   KEGGREST_1.36.3               AnnotationFilter_1.20.0       RBGL_1.72.0                   
 [85] nlme_3.1-157                  mime_0.12                     xml2_1.3.3                    biomaRt_2.52.0               
 [89] compiler_4.2.1                rstudioapi_0.14               filelock_1.0.2                curl_4.3.3                    
 [93] png_0.1-7                     interactiveDisplayBase_1.34.0 tweenr_2.0.2                  tibble_3.1.8                 
 [97] stringi_1.7.8                 lattice_0.20-45               ProtGenerics_1.28.0           Matrix_1.4-1                 
[101] vctrs_0.5.2                   pillar_1.8.1                  lifecycle_1.0.3               BiocManager_1.30.18          
[105] data.table_1.14.2             bitops_1.0-7                  httpuv_1.6.6                  R6_2.5.1                      
[109] BiocIO_1.6.0                  latticeExtra_0.6-30           promises_1.2.0.1              gridExtra_2.3                 
[113] codetools_0.2-18              dichromat_2.0-0.1             MASS_7.3-57                   assertthat_0.2.1              
[117] SummarizedExperiment_1.26.1   rjson_0.2.21                  withr_2.5.0                   regioneR_1.28.0               
[121] GenomicAlignments_1.32.1      Rsamtools_2.12.0              GenomeInfoDbData_1.2.8        mgcv_1.8-40                   
[125] parallel_4.2.1                hms_1.1.2                     grid_4.2.1                    rpart_4.1.16                 
[129] MatrixGenerics_1.8.1          biovizBase_1.44.0             lubridate_1.9.0               shiny_1.7.3                   
[133] base64enc_0.1-3               interp_1.1-3                  restfulr_0.0.15               

解决方案

问题根源

在lapply的匿名函数中,直接调用pdf()+p+dev.off()的方式,ggplot对象不会被正确渲染到PDF设备中——非交互式环境(比如循环、apply函数)里,ggplot需要显式的print()触发绘制。结合你的Windows环境,还可能存在设备切换缓存、路径编码的问题。

可行方案

方案1:修复print()的使用逻辑

确保print(p)在PDF设备打开的范围内执行,同时用invisible()避免lapply返回大量无用的绘图对象:

# 先确保输出文件夹存在
if (!dir.exists("output_data")) dir.create("output_data")

lapply(split(df, df$group), function(d) {
  p <- ggplot(d, aes(x, y)) + geom_point() + ggtitle(paste("Group", d$group[1]))
  pdf_file <- paste0("output_data/", d$group[1], ".pdf")
  pdf(pdf_file)
  print(p)
  dev.off()
  invisible(p)
})

方案2:调整ggsave参数解决适配问题

如果之前ggsave表现不佳,试试指定PDF设备、明确尺寸,同时确保路径合法:

if (!dir.exists("output_data")) dir.create("output_data")

lapply(split(df, df$group), function(d) {
  group_name <- d$group[1]
  p <- ggplot(d, aes(x, y)) + geom_point() + ggtitle(paste("Group", group_name))
  ggsave(
    filename = paste0("output_data/", group_name, ".pdf"),
    plot = p,
    device = "pdf",
    width = 6,
    height = 4,
    dpi = 300
  )
})

方案3:改用purrr::walk替代lapply

walk专门用于执行无返回值的操作,比lapply更适合保存文件的场景,避免不必要的对象缓存:

library(purrr)
library(ggplot2)

if (!dir.exists("output_data")) dir.create("output_data")

split(df, df$group) %>%
  walk(function(d) {
    group_name <- d$group[1]
    p <- ggplot(d, aes(x, y)) + geom_point() + ggtitle(paste("Group", group_name))
    ggsave(paste0("output_data/", group_name, ".pdf"), p)
  })

方案4:处理Windows路径编码问题

Windows下中文或特殊字符路径可能导致文件损坏,用normalizePath标准化路径:

if (!dir.exists("output_data")) dir.create("output_data")

lapply(split(df, df$group), function(d) {
  p <- ggplot(d, aes(x, y)) + geom_point() + ggtitle(paste("Group", d$group[1]))
  pdf_file <- normalizePath(paste0("output_data/", d$group[1], ".pdf"), mustWork = FALSE)
  pdf(pdf_file)
  print(p)
  dev.off()
})

额外排查点

  • 关闭所有可能占用PDF文件的程序(比如Adobe Reader)
  • 尝试更新ggplot2到最新稳定版,或回退到3.3.6版本测试
  • 检查R的工作目录是否正确,用getwd()确认

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 17:14:53