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

如何循环运行包含Shiny App的R脚本?

实现Shiny App循环接收输入并处理数据的解决方案

问题背景

现有Shiny脚本点击「Los gehts」按钮后会读取剪贴板数据进行处理,但每次处理新ID都必须重启脚本。需要实现:

  • 仅启动一次脚本,Shiny App持续等待用户输入
  • 点击「Los gehts」完成数据处理后,App自动回到等待状态
  • 点击「Abbrechen」按钮才终止整个程序

尝试用while循环包裹shinyApp(ui, server)及后续代码时,出现UI无法加载、数据处理逻辑自行循环的问题。

解决方案

将Shiny App的启动、数据处理逻辑整体放入while循环中,同时维护全局变量的状态传递,确保每次循环都能正确加载UI并等待输入。以下是修改后的完整代码:

library(shiny)
library(clipr) # 确保加载clipr包用于read_clip

# 初始化全局变量
ADI_ID <- ""
timepoint <- ""
counter <- 1
stop <- FALSE

while (!stop) {
  ui <- fluidPage(
    textInput('adi_id', '输入ADI ID:'),
    textInput('timepoint', '输入时间点:', value = ""),
    actionButton('start_button', '开始'),
    actionButton('last_id_button', '上一个受试者'),
    actionButton('cancel_button', '取消'),
    textOutput('last_id_output'),
    textOutput('counter_output')
  )
  
  server <- function(input, output, session) {
    
    observeEvent(input$start_button, {
      if (input$adi_id == "" || input$timepoint == "") {
        showModal(
          modalDialog(
            title = "错误",
            "请输入有效的ADI ID和时间点后再继续。",
            easyClose = TRUE
          )
        )
      } else {
        # 更新全局变量
        if (ADI_ID == input$adi_id) {
          counter <<- counter + 1
        } else {
          counter <<- 1
        }
        ADI_ID <<- input$adi_id
        timepoint <<- input$timepoint
        stopApp() # 关闭当前App,回到循环继续执行
      }
    })
    
    observeEvent(input$last_id_button, {
      if (counter >= 4) {
        showModal(
          modalDialog(
            title = "警告",
            "计数器已达到3或更高,确定要使用上一个ID吗?",
            footer = tagList(
              modalButton("取消"),
              actionButton("confirm_last_id", "继续")
            ),
            easyClose = TRUE
          )
        )
      } else {
        updateTextInput(session, 'adi_id', value = ADI_ID)
        updateTextInput(session, 'timepoint', value = timepoint)
      }
    })
    
    observeEvent(input$confirm_last_id, {
      updateTextInput(session, 'adi_id', value = ADI_ID)
      updateTextInput(session, 'timepoint', value = timepoint)
      removeModal()
    })
    
    observeEvent(input$cancel_button, {
      stop <<- TRUE # 设置终止标记
      stopApp() # 关闭当前App
    })
    
    output$last_id_output <- renderText({
      paste("上一个ID: ", ADI_ID)
    })
    
    output$counter_output <- renderText({
      paste("计数器: ", counter)
    })
  }
  
  # 启动Shiny App,等待用户操作
  shinyApp(ui, server)
  
  # 如果用户点击取消,退出循环
  if (stop) {
    message("已取消操作")
    break
  }
  
  # 数据处理逻辑
  if (ADI_ID != "" && timepoint != "") {
    my_data <- read_clip()
    ####### 这里放置你的数据处理代码
    message(paste("已完成ADI ID", ADI_ID, "时间点", timepoint, "的数据处理"))
  }
}

关键修改说明

  1. 外层while循环:以!stop为循环条件,控制整个流程的持续运行,直到用户点击「取消」按钮将stop设为TRUE。
  2. 全局变量维护:将ADI_ID、timepoint、counter等状态变量放在循环外部初始化,确保每次循环能保留上一次的输入状态。
  3. Shiny App启动逻辑:每次循环重新定义UI和Server并启动App,确保处理完成后能重新加载UI等待新输入。
  4. 取消按钮逻辑:点击「取消」时同时设置stop为TRUE并关闭App,外层循环检测到stop为TRUE后终止程序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 02:35:07