Update plot within observer loop in shiny application

后端 未结 2 1440
孤城傲影
孤城傲影 2020-12-06 12:08

I have written a simulation in R that I want to visualize with shiny now. I have put the main part of the simulation into an observe block in order to be evaluated.

相关标签:
2条回答
  • 2020-12-06 12:29

    I've been doing a little more thinking about this. I think the proper solution is to use invalidateLater to schedule work to occur in small chunks but allow other reactive dependencies to interrupt our long-running process to do things like updating graphs.

    I put together a quick example at https://gist.github.com/trestletech/8608815 . You can run this with

    runGist(8608815)
    

    The basic premise is that we're doing some long-running iterative computing like what's done in your simulation, but we do it in smaller chunks to allow other reactives to run in between. My code is really simple to execute, so I can handle 100,000 iterations of my loop in ~1 second, which is about how long I'm willing to wait for my app to update interactively. I want to do 5 million iterations, so I schedule 50 chunks to occur.

    Each time I run a chunk of 100,000 iterations, I'm updating a couple of reactive values that spawn some other updates that end up getting sent to my UI in a renderText (though a renderPlot like yours would work the exact same). If you run the app, you'll see that those reactives are updated in between each chunk I run before the next chunk gets scheduled to run.

    There is a bit of overhead with this method, so your computation may slow down just a bit. But on my machine, 5 million iterations took 21 seconds when run all at once on the console, and took 23 seconds in this delayed-dispatch model. You could drive that down further by doing bigger chunks, of course.

    Let me know what you think. I'm thinking it might make sense to wrap this up and either include pieces of it in Shiny or as an extension package.

    0 讨论(0)
  • 2020-12-06 12:33

    Since you have a Sys.sleep() call in your code, I'm assuming you only want to run through one iteration per second. If that's the case, you could set a reactiveTimer that will evaluate code every second. Inside that timer, you'd run the code for the current iteration then bump up the dummy$iter variable.

    0 讨论(0)
提交回复
热议问题