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

在Shiny中为rmarkdown::render添加进度条显示的问题

解决Shiny中rmarkdown::render进度不被withProgress跟踪的问题

咱们先拆解下你遇到的核心问题:你当前的withProgress只包裹了test_fun()循环,但真正耗时的rmarkdown::render()是在进度条代码块之外执行的——这就导致进度条走完循环后,用户还得默默等待渲染完成,进度提示和实际等待时长完全不匹配。

核心解决方案:把rmarkdown::render()纳入withProgress范围,并利用knitr的进度回调跟踪渲染细节

要让进度条真正反映渲染的耗时,我们需要做两件关键调整:

  1. 将rmarkdown::render()移动到withProgress的代码块内部
  2. 给rmarkdown::render()传入自定义的进度回调函数,让knitr在编译每个Rmd代码块时自动更新Shiny的进度条

修改后的Server脚本示例:

observeEvent(input$nplrhits, { 
  output$nplrwfall <- renderPlotly({ 
    withProgress(
      message = 'Processing your request', 
      detail = 'Initializing...', 
      value = 0, 
      { 
        # 第一步:初始化进度,进入准备阶段
        incProgress(0.1, detail = "Preparing report template...")
        
        # 定义knitr进度回调函数:每个代码块编译完成时更新进度
        knitr_progress <- function(current_chunk, total_chunks) {
          # 把渲染阶段的进度分配为总进度的80%
          progress_step <- (current_chunk / total_chunks) * 0.8
          incProgress(progress_step, detail = paste("Rendering chunk", current_chunk, "/", total_chunks))
        }
        
        # 调用rmarkdown::render,并传入进度回调
        rmarkdown::render(
          input = paste0(dir_path,"/R_scripts/Hits_Waterfall.Rmd"), 
          output_file = paste0(dir_path,"/results/Patient/",input$txt, "/Hits_Waterfall.html"),
          # 通过output_options传递knitr的进度设置
          output_options = list(
            knitr_options = list(
              progress = knitr_progress
            )
          )
        )
        
        # 最后一步:渲染完成,进入图表生成阶段
        incProgress(0.1, detail = "Generating interactive plot...")
        
        # 生成并返回plotly图表
        plotly::ggplotly(pn)
      }
    )
  }) 
})

为什么这样能解决问题?

  • 进度范围全覆盖:现在rmarkdown::render()完全在withProgress块内,整个渲染过程的耗时都会被进度条跟踪
  • 细粒度反馈:利用knitr的progress钩子,每完成一个Rmd里的代码块,就会更新一次进度条,用户能看到具体的渲染阶段(比如"Rendering chunk 3/5"),不会觉得应用卡住
  • 阶段划分清晰:我们把总进度分成了三个部分(准备10% + 渲染80% + 图表生成10%),即使Rmd里的代码块数量少,用户也能看到进度在逐步推进

简化版备选方案(如果Rmd代码块很少)

如果你的Rmd文件没有分多个代码块,或者代码块数量极少,进度条可能会跳得比较快。这种情况下可以简化逻辑,手动划分进度阶段:

observeEvent(input$nplrhits, { 
  output$nplrwfall <- renderPlotly({ 
    withProgress(message = 'Generating report', detail = 'Starting...', value = 0, {
      incProgress(0.2, detail = "Starting render process...")
      # 执行渲染
      rmarkdown::render(
        input = paste0(dir_path,"/R_scripts/Hits_Waterfall.Rmd"), 
        output_file = paste0(dir_path,"/results/Patient/",input$txt, "/Hits_Waterfall.html")
      )
      incProgress(0.8, detail = "Render complete! Generating plot...")
      # 生成图表
      plotly::ggplotly(pn)
    })
  }) 
})

这样至少能让用户明确知道渲染过程正在进行,而不是应用无响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:24:23