6

I am developing some shiny apps with various inputs. In general, I have a setup where I want the user to push a button to accept the input values, which will then create objects that need to be set up. The a simulation should run when the user presses the play button on a animated sliderInput object. The objects that have been created will be updated at each iteration.

One problem is that one of the objects is a reactiveValues list. I would like the whole set of objects to be recreated (erasing earlier values) whenever a user changes a setting and clicks "Accept" and runs them. Instead, the objects in the reactiveValues list are not being overwritten but are being augmented each time with the next settings. So each object slot actually holds several objects.

To see this, try setting the maximum iteration to a value, hit accept, then change the value and accept again, then click play. You will see it will print out different lengths of the reactiveValues object.

I tried a few things like rm() to try to delete the reactiveValues. Also I tried the solution here (shiny: How to update a reactiveValues object?) but it didn't work either.

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))

   })
 }) 
}
)
)
Community
  • 1
  • 1
Sam A.
  • 413
  • 4
  • 13
  • I think I got something you can work with, but not completely sure as I don't really know where you are going with this. – Mike Wise Feb 12 '17 at 04:02

1 Answers1

5

I think this gets you what you want:

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))
    })
  })
)

Yielding this:

enter image description here

In the above I set to 20, ran it, then set to 6, and ran it again. You can see it is no longer repeating the values, before it would have alternated 20 and 6.

The changes I made were:

  • initialized param$tmp outside the loop
  • removed the nesting of the observeEvent calls.

I kind of think you should be using an eventReactive here for the input$run case, but I am not really sure where you are going with this, so I let it be.

Mike Wise
  • 22,131
  • 8
  • 81
  • 104
  • Hi Mike thanks for the input. I guess you are right, by having the params inside the observeEvent like I had, it was running each time I clicked run, which is not what I expected. I expected the objects would be overwritten each time. To answer your question, I tried replacing the first observeEvent with eventReactive but it doesn't work because it doesn't set the values in params. I believe observeEvent is used to perform a bunch of actions in reaction to a reactive value, whereas the eventReactive is supposed to do a calculation and return a value. – Sam A. Feb 13 '17 at 03:19
  • Also I think adding req(input$run) at the beginning of the second observeEvent solves the problem because if you haven't initialized anything, (inpu$run) I don't want any resulting plots or output from running iterations. – Sam A. Feb 13 '17 at 03:21
  • Well could you accept it and maybe upvote it too? Working on some badges... – Mike Wise Feb 13 '17 at 17:33
  • Just one thing. I realized that I think the nested observeEvents are necessary because in the first one I need to create other objects (not reactive) that should be accessible within the second loop when I iterate. It they are not nested apparently they cannot be accessed. – Sam A. Feb 13 '17 at 17:41
  • You can put them into the same reactive value as a list element – Mike Wise Feb 13 '17 at 17:49