How to get iterative output from a “for” loop in R shinyapp?

1,652 views
Skip to first unread message

gaurav parmar

unread,
May 4, 2017, 3:03:35 AM5/4/17
to Shiny - Web Framework for R
I am looking for a solution in which we can print single iteration output in R shiny. Right now I got the output (a bunch of text output) when For loop ends its working. Is there any way to print itrative output to R shiny mainpanel from for loop ?

I think the problem is likely to be that Shiny is waiting for the end of the function to check for reactive triggers.

Here is the sample code:-

library(shiny)
library(shinydashboard)
library(shinythemes)
ui <- dashboardPage(
dashboardHeader(title = "LAP"),
dashboardSidebar( 
sidebarMenu(
  #menuItem("Introduction", tabName = "intro", icon = icon("info-circle")),
  menuItem("test", tabName = "FD", icon = icon("info-circle"))

)),

dashboardBody(
tabItems(
  tabItem(tabName = "FD",
          fluidRow(
            box(verbatimTextOutput("loc") )))
  )
 )
)
 server =shinyServer(function(input, output){

 mydata<- reactive({

for(i in 1:100){

  print("For Demo Purpose")

}

})

output$loc<- renderPrint({
mydata()
}) 
})

shinyApp(ui= ui, server = server)

Bárbara Borges

unread,
May 5, 2017, 12:57:34 PM5/5/17
to Shiny - Web Framework for R
Yes, by default Shiny will always wait for any reactive dependencies to finish (re)calculcating before displaying the output that depends on them. Without async reactivity in Shiny (which is not currently available, but it's in the works), it's actually not really possible to make a reactive dependency be available before it finishes computing. But you can redefine your reactive so that its output is broken though.

You can achieve this using reactive values, an observer and invalidateLater(). If this is new for you, I'd recommend, you read the documentation about invalidateLater().

I'll show two simple examples here. For a more elaborate example, see this gist.

The first and probably best approach is to do something like:

library(shiny)

ui <- fluidPage(
  verbatimTextOutput("loc")
)

server <- function(input, output, session) {
  rv <- reactiveValues(lines = character(0), n = 0)
  
  observe({
    # Re-execute this reactive expression immediately after 
    # it finishes (though you can also specify a longer time:
    # e.g. 1000 means re-execute after 1000 milliseconds have
    # passed since it was last executed)
    invalidateLater(0, session)
    isolate({
      if (rv$n >= 100) {
        return()
      } else {
        rv$n <- rv$n + 1
        rv$lines <- c(rv$lines, paste("Loop var =", rv$n))
      }
    })
  })
  
  output$loc <- renderPrint({
    rv$lines
  }) 
}

shinyApp(ui, server)

This will re-execute the observer repeatedly until you've reached rv$n = 100 (actually, it will keep re-executing forever and it always stops because rv$n will never de decremented once it reaches 100). So in the first iteration, rv$lines starts as nothing and then becomes the string "Loop var = 1". It returns that and the renderPrint() call will print that to the screen. However, immediately after the observer finished, it will re-start and the rv$lines object will now have two strings:  "Loop var = 1" and "Loop var = 2". It returns that and the renderPrint() call will print that to the screen. And so on... This happens very fast in the example above, but will be very clear if you change the line invalidateLater(0, session) to something like a 1/4 of a second: invalidateLater(250, session).

This first approach is IMO intuitive and it stays neatly within the reactive framework that Shiny strongly encourages. However, it does have one drawback: the renderPrint() call will always print all the strings, each time that rv$lines changes, even though, you're just adding a line at the end (so ideally you wouldn't have to re-print everything). This isn't an issue for 100 iterations of printing text, but for larger number or heavier objects (images, for example), this can become noticeable.

But there is another option that is fairly new to Shiny, which is to use insertUI(). This option follows imperative, not reactive, logic, so I'd only recommend it if you feel like you understand reactivity AND it makes sense for your use case. In particular, this approach will let you print things one after the other (instead of always printing one big block), but it loses track of them. If these are values that could change later, or that you'd like to read in some other place, you shouldn't use this approach. (There are ways to use insertUI in more complicated ways, but that's another discussion, because I don't think that's what you need in this post.) This has the advantage of being faster and not keeping a possible very large set of strings/objects in memory. If this is new for you, I'd recommend, you read the documentation about insertUI().

library(shiny)

ui <- fluidPage(
  div(id = "placeholder")
)

server <- function(input, output, session) {
  rv <- reactiveValues(n = 0)
  
  observe({
    invalidateLater(0, session)
    isolate({
      if (rv$n >= 100) {
        return()
      } else {
        rv$n <- rv$n + 1
        insertUI("#placeholder", ui = p("Loop var = ", rv$n))
      }
    })
  })
}

shinyApp(ui, server)

Hope this helped!

gaurav parmar

unread,
May 6, 2017, 3:34:15 AM5/6/17
to Shiny - Web Framework for R
Thanks Bárbara Borges It works, This is what I am looking for, I also did some modification with my code.
Thank You once again.
Reply all
Reply to author
Forward
0 new messages