如何将.Rmd文件中的所有ggplot保存为.rds格式
保存代码块中所有ggplot对象并复用的解决方案
问题背景
我使用R Markdown做分析,通过knitr::opts_chunk$set(dev= c("png", "svg", "pdf"))和rmarkdown::render(... , clean = FALSE)生成三种格式的图表,分别用于Google Slides、PowerPoint和LaTeX报告。现在需要将不同分析中的图表组合成分面图,且希望无需重新运行所有分析就能修改图表尺寸和宽高比。
目前通过钩子只能保存每个代码块的最后一张ggplot,想解决两个问题:
- 如何保存代码块中的所有图表?
- 是否存在隐藏的
device="rds"参数?
解决方案1:自定义钩子捕获代码块内所有ggplot对象
通过修改knitr钩子,追踪代码块执行过程中生成的所有ggplot对象,而非仅捕获last_plot()。
修改后的example_analysis.Rmd设置代码块
```{r setup, include=FALSE} knitr::opts_chunk$set(dev = c("png", "svg", "pdf")) # 自定义钩子:捕获代码块内所有ggplot并保存为rds knitr::knit_hooks$set(save_all_ggplots = function(before, options, envir) { if (before) { # 初始化存储列表 envir$.ggplots <- list() # 替换print.ggplot函数,捕获所有被打印的ggplot original_print_ggplot <- getS3method("print", "ggplot") assignInNamespace( "print.ggplot", function(x, ...) { envir$.ggplots <- c(envir$.ggplots, list(x)) original_print_ggplot(x, ...) }, ns = "ggplot2" ) } else { # 恢复原print.ggplot函数 assignInNamespace( "print.ggplot", getS3method("print", "ggplot", envir = asNamespace("ggplot2")), ns = "ggplot2" ) # 保存所有捕获到的ggplot if (length(envir$.ggplots) > 0) { chunk_label <- options$label fig_dir <- knitr::opts_chunk$get("fig.path") %||% "figure/" dir.create(fig_dir, recursive = TRUE, showWarnings = FALSE) for (i in seq_along(envir$.ggplots)) { saveRDS( envir$.ggplots[[i]], file = paste0(fig_dir, chunk_label, "-", i, ".rds") ) } } } }) # 全局启用该钩子 knitr::opts_chunk$set(save_all_ggplots = TRUE)
#### 测试多图表代码块 ```r ```{r multi-plots} # 第一张图 ggplot(iris, aes(Sepal.Width, Sepal.Length)) + geom_point() # 第二张图 ggplot(iris, aes(Petal.Width, Petal.Length)) + geom_point() # 第三张图 ggplot(iris, aes(Species, Sepal.Length)) + geom_boxplot()
#### 组合图表的脚本 ```r library(patchwork) get_ggplot <- function(chunk_label, plot_num) { fig_dir <- "example_analysis_files/figure-html/" # 对应render后的输出路径 readRDS(paste0(fig_dir, chunk_label, "-", plot_num, ".rds")) } # 自由组合分面图 get_ggplot("multi-plots", 1) | get_ggplot("multi-plots", 2) / get_ggplot("multi-plots", 3) + plot_annotation(tag_levels = "A")
解决方案2:自定义knitr设备保存rds
knitr没有内置device="rds",但可以自定义设备函数,让knitr在生成png/svg/pdf的同时,自动保存ggplot对象为rds文件。
实现代码(添加到setup代码块)
```{r setup, include=FALSE} knitr::opts_chunk$set(dev = c("png", "svg", "pdf", "rds")) # 自定义rds设备,整合进knitr工作流 knitr::knit_print.ggplot <- function(x, options, ...) { # 执行原ggplot打印逻辑,生成常规格式图表 res <- NextMethod() # 保存当前ggplot为rds if ("rds" %in% options$dev) { fig_path <- knitr::fig_chunk(options$label, ext = "rds") # 给多图添加序号后缀 if (!is.null(options$fig.cur)) { fig_path <- sub("\\.rds$", paste0("-", options$fig.cur, ".rds"), fig_path) } saveRDS(x, fig_path) } res }
这种方法的优势是完全贴合knitr的设备系统,无需修改print函数,代码块中每一张ggplot都会生成对应序号的rds文件,命名规则和其他格式图表保持一致(如`multi-plots-1.rds`、`multi-plots-2.rds`)。 --- ### 注意事项 - 两种方法都需要确保使用`rmarkdown::render(..., clean = FALSE)`,避免生成的rds文件被自动清理。 - 如果代码块包含base绘图(非ggplot),方法1只会捕获ggplot对象;方法2可通过扩展`knit_print.default`来适配base图的保存。 - 方法2更符合knitr原生工作流,推荐优先使用。 内容的提问来源于stack exchange,提问作者jan-glx
相关产品推荐
相关产品推荐

