如何循环运行包含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, "的数据处理")) } }
关键修改说明
- 外层while循环:以
!stop为循环条件,控制整个流程的持续运行,直到用户点击「取消」按钮将stop设为TRUE。 - 全局变量维护:将ADI_ID、timepoint、counter等状态变量放在循环外部初始化,确保每次循环能保留上一次的输入状态。
- Shiny App启动逻辑:每次循环重新定义UI和Server并启动App,确保处理完成后能重新加载UI等待新输入。
- 取消按钮逻辑:点击「取消」时同时设置
stop为TRUE并关闭App,外层循环检测到stop为TRUE后终止程序。
内容的提问来源于stack exchange,提问作者Eric G
相关产品推荐
相关产品推荐

