Z. Zhang
Z. Zhang

Reputation: 501

R Shiny where to place withProgress

On my Shiny page, there is a step reading a big log file, which takes 25s to load. I would like to show a progress bar after user clicks a button. Otherwise they may think it is not working while they are waiting.

 #ui.R
 #I have an actionButton to activate reading the log file
 actionButton("getLog","Get Log data")

 #server.R
   observeEvent(input$getLog, {
 nL = as.numeric(countLines("/script/cronlog.log"))
 Log = read.table("/script/cronlog.log",sep = ";",skip = nL-1000)
 LogFile = tail(Log,100)
 colnames(LogFile) = "cronlog"
 })

I was trying to use withProgress but I don't know how to use it to wrap the codes. I tried something like this:

  observeEvent(input$getLog, {
withProgress(message = 'Calculation in progress',
                              detail = 'This may take a while...', value = 0, {
                   for (i in 1:60) {
                     incProgress(1/60)
                     Sys.sleep(0.25)
                   }
                 })
nL = as.numeric(countLines("/script/cronlog.log"))
Log = read.table("/script/cronlog.log",sep = ";",skip = nL-1000)
LogFile = tail(Log,100)
colnames(LogFile) = "cronlog"
})

The progress bar did show up but it seems like the loading progress is running after the progress bar, which makes the process even longer. I guess I didn't wrap the code correctly.

Any suggestions?

Thank you in advance!

Upvotes: 4

Views: 2367

Answers (1)

zero323
zero323

Reputation: 330333

If operations you apply are not discrete withProgress won't help you much. You could increment progress bar between individual statements:

nL = as.numeric(countLines("/script/cronlog.log"))
incProgress(1/4)
log = read.table("/script/cronlog.log",sep = ";",skip = nL-1000)
incProgress(1/4)
...

but I doubt it will make a huge difference. Another approach is to split input file into multiple chunks and read these independently incrementing counter after each file.

In practice I would consider dropping following part:

nL = as.numeric(countLines("/script/cronlog.log"))

and use standard system utilities to pipe only required data:

read.table(pipe("tail -n 1000 /script/cronlog.log"), sep = ";")

or directly with data.table::fread:

fread("tail -n 1000 /script/cronlog.log", sep = ";")

Upvotes: 3

Related Questions