R闪亮:如何更改响应式值对象中的值

6
我正在开发一些带有各种输入的闪亮应用程序。通常情况下,我需要用户按下按钮以接受输入值,这将创建需要设置的对象。当用户按下动画滑块输入对象上的播放按钮时,模拟应该运行。已创建的对象将在每次迭代时更新。
一个问题是其中一个对象是反应值列表。我希望整个对象集在用户更改设置并单击“接受”并运行它们时被重新创建(擦除先前的值)。相反,反应值列表中的对象没有被覆盖,而是每次都会增加下一个设置。因此,每个对象插槽实际上都保存着多个对象。
为了看到这一点,请尝试将最大迭代设置为一个值,然后点击接受,再更改值并再次点击接受,然后点击播放。你会看到它将打印出不同长度的反应值对象。
我尝试了一些方法,比如rm()尝试删除反应值。我还尝试了这里的解决方案 (shiny: How to update a reactiveValues object?),但它也没有起作用。
library(shiny)

iter_test <- shinyApp(

ui=shinyUI(fluidPage(
  titlePanel("title panel"),

  sidebarLayout(position = "left",
                             sidebarPanel("Simulation parameters",                                
                               sliderInput("iter","Progress of simulation",value=1, min=1, max=30, round=TRUE, step=1,
                                 animate=animationOptions(interval=1, loop=FALSE)),
                                 actionButton('run',"Accept settings, press play above"),
                                 sliderInput('max_iter','Maximum number of iterations',value=20, min=1, max=30, round=TRUE, step=1)
                              ),
                mainPanel(  plotOutput("plots"))
               )#end of layout
  )
)#end of UI definition
,

server=shinyServer(function(input, output, session) 
{

   observeEvent( input$run, { 
        #only set up simulation objects if accept is clicked

    updateSliderInput(session, "iter",  label="Progress of simulation", value=1, min=1, max=input$max_iter, step=1)
    #try(rm(params))
    #set up objects needed for simulation
    params <- reactiveValues(tmp=rep(1, input$max_iter))

    #when the play button is pressed, the following loop should trigger.       

    observeEvent( input$iter, { 
           print(length(params$tmp))

   })
 }) 
}
)
)

我认为我有一些你可以使用的东西,但并不完全确定,因为我不知道你的具体意图。 - Mike Wise
1个回答

5
我认为这可以帮助你达到你想要的效果:
library(shiny)

iter_test <- shinyApp(

  ui=shinyUI(fluidPage(
    titlePanel("title panel"),

    sidebarLayout(position = "left",
                  sidebarPanel("Simulation parameters",                                
                               sliderInput("iter","Progress of simulation",value=1, min=1, max=30, round=TRUE, step=1,
                                           animate=animationOptions(interval=1, loop=FALSE)),
                               actionButton('run',"Accept settings, press play above"),
                               sliderInput('max_iter','Maximum number of iterations',value=20, min=1, max=30, round=TRUE, step=1)
                  ),
                  mainPanel(  plotOutput("plots"))
    )#end of layout
  )),#end of UI definition
  server=shinyServer(function(input, output, session) 
  {
    params <- reactiveValues(tmp=NULL)

    observeEvent( input$run, { 
      req(input$run)          
      updateSliderInput(session, "iter",  label="Progress of simulation", value=1, min=1, max=input$max_iter, step=1)
      #try(rm(params))
      #set up objects needed for simulation
      params$tmp =rep(1, input$max_iter)
    })          
    #when the play button is pressed, the following loop should trigger.       
    observeEvent( input$iter, { 
      req(input$iter)
      print(length(params$tmp))
    })
  })
)

产生以下结果:

enter image description here

在上面的代码中,我将其设置为20,然后运行它,然后将其设置为6,再次运行它。您可以看到它不再重复值,之前它会交替显示20和6。

我所做的更改是:

  • 在循环外初始化param$tmp
  • 删除observeEvent调用的嵌套。

我认为你应该在input$run情况下使用eventReactive,但我不确定你要去哪里,所以我让它保持不变。


嗨Mike,感谢你的反馈。我想你说得对,将参数放在observeEvent里面会导致每次点击运行时都执行,这不是我预期的结果。我希望每次都能覆盖对象的值。回答你的问题,我尝试用eventReactive替换第一个observeEvent,但它不起作用,因为它不能设置params的值。我相信observeEvent用于根据响应式值执行一系列操作,而eventReactive则用于进行计算并返回一个值。 - Sam A.
我认为在第二个observeEvent的开头添加req(input$run)可以解决这个问题,因为如果您没有初始化任何内容,(input$run),我不希望从运行迭代中得到任何结果图或输出。 - Sam A.
你能接受并且点赞吗?我正在努力获得一些徽章... - Mike Wise
只有一件事。我意识到嵌套的observeEvents是必要的,因为在第一个observeEvent中,我需要创建其他对象(非响应式),这些对象在迭代时应该可以在第二个循环中访问。如果它们不是嵌套的,显然无法访问它们。 - Sam A.
你可以将它们作为列表元素放入同一个响应式值中。 - Mike Wise

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接