如何在R中处理forecast包tsdisplay的输出:捕获与修改绘图
问题解决:forecast包中tsdisplay/ggtsdisplay的使用与绘图组合
问题描述
无法理解如何使用forecast包中的tsdisplay函数,生成三个AR(1)时间序列并存储在数据框中:
library(forecast) N <- 200 ar1_processes <- matrix(nrow = 4, ncol = N) ar1_processes[1,] <- 1:N ar1_processes[2,] <- arima.sim(model = list(ar = c(0.1)), n = N) ar1_processes[3,] <- arima.sim(model = list(ar = c(0.5)), n = N) ar1_processes[4,] <- arima.sim(model = list(ar = c(0.9)), n = N) ar1_processes <- as.data.frame(t(ar1_processes)) colnames(ar1_processes) <- c("time", "theta_0.1", "theta_0.5", "theta_0.9")
想要对比每个序列的tsdisplay输出(包含时间序列图、ACF图和PACF图的组合图),但当前代码生成三个独立输出且仅保存PACF图:
# saves only PACF plots for (name in colnames(ar1_processes)[-1]){ ar1_processes[name] %>% ggtsdisplay(main = paste("AR(1) with", name)) # ggtsdisplay ggsave(file.path("ar1_plots", paste(name, ".png", sep = ""))) }
需求:
- 将所有输出展示在一个大图中;
- 像操作ggplot一样修改绘图元素(如添加图层、修改标题);
- 将绘图保存到文件。
已尝试的方法
# doesn't work, only the last figure (ts, ACF, PACF) is displayed par(mrow = c(3,1)) # c(3,3) doesn't change anything for (name in colnames(ar1_processes)[-1]){ ar1_processes[name] %>% tsdisplay(main = paste("AR(1) with", name)) } # attempt to investigate object returned from ggtsdisplay ar1_plots <- list() for (name in colnames(ar1_processes)[-1]){ ar1_plots[[name]] <- ar1_processes[name] %>% ggtsdisplay(main = paste("AR(1) with", name)) ggsave(file.path("ar1_plots", paste(name, ".png", sep = ""))) } ar1_plots[["theta_0.9"]] %>% View() # wasn't useful
解决方案
核心要点
tsdisplayvsggtsdisplay:tsdisplay基于R基础绘图系统,每次调用会自动创建3行1列的布局,无法通过par()合并多个输出;ggtsdisplay基于ggplot2,返回可编辑、可组合的ggplot对象,更适合你的需求。- 组合绘图:使用
patchwork包可以轻松将多个ggtsdisplay生成的组合图合并为一个大图。 - 保存绘图:必须将
ggtsdisplay的结果赋值给变量,再用ggsave()保存该变量,避免只保存最后一个子图的问题。
完整代码示例
library(forecast) library(ggplot2) library(patchwork) # 用于组合ggplot对象 library(dplyr) # 生成数据(复用你的代码) N <- 200 ar1_processes <- matrix(nrow = 4, ncol = N) ar1_processes[1,] <- 1:N ar1_processes[2,] <- arima.sim(model = list(ar = c(0.1)), n = N) ar1_processes[3,] <- arima.sim(model = list(ar = c(0.5)), n = N) ar1_processes[4,] <- arima.sim(model = list(ar = c(0.9)), n = N) ar1_processes <- as.data.frame(t(ar1_processes)) colnames(ar1_processes) <- c("time", "theta_0.1", "theta_0.5", "theta_0.9") # 创建保存目录(如果不存在) dir.create("ar1_plots", showWarnings = FALSE) # 生成每个序列的ggtsdisplay图,并存入列表 plot_list <- lapply(colnames(ar1_processes)[-1], function(name) { # 将数据转换为ts对象(可选,但更符合时间序列分析规范) ts_data <- ts(ar1_processes[[name]], start = 1) # 生成基础组合图 p <- ggtsdisplay(ts_data, main = paste("AR(1) with", name)) # 像操作ggplot一样修改元素:比如更换主题、添加副标题 p <- p + theme_minimal() + labs(subtitle = paste("AR coefficient =", gsub("theta_", "", name))) + theme(plot.title = element_text(size = 12, face = "bold")) return(p) }) # 1. 将所有图组合成一个大图:垂直堆叠(3行1列) combined_plot <- plot_list[[1]] / plot_list[[2]] / plot_list[[3]] # 若要水平堆叠,使用:plot_list[[1]] + plot_list[[2]] + plot_list[[3]] # 添加总标题 combined_plot <- combined_plot + plot_annotation( title = "Comparison of AR(1) Processes with Different Coefficients", theme = theme(plot.title = element_text(hjust = 0.5, size = 16, face = "bold")) ) # 2. 展示组合图 print(combined_plot) # 3. 保存组合图到文件 ggsave( file.path("ar1_plots", "combined_ar1_plots.png"), combined_plot, width = 10, height = 12, dpi = 300 ) # 保存单个图(可选) for (i in seq_along(plot_list)) { name <- colnames(ar1_processes)[-1][i] ggsave( file.path("ar1_plots", paste0(name, ".png")), plot_list[[i]], width = 8, height = 6 ) }
常见问题解释
为什么
par(mrow)不生效?tsdisplay内部会调用layout()函数设置3行1列的绘图布局,循环中每次调用都会重置布局,覆盖par()的设置,因此最后只显示最后一个tsdisplay的输出。为什么之前的代码只保存PACF图?
ggtsdisplay生成的是由三个ggplot子图组合成的gtable对象,如果不将其赋值给变量,R绘图环境中最后残留的是最后绘制的子图(PACF),ggsave()会默认保存这个残留图。赋值给变量后再保存即可得到完整的组合图。
内容的提问来源于stack exchange,提问作者stats_b
相关产品推荐
相关产品推荐

