Progress bar while running a bat file through shiny app - r

I am running a lengthy .bat file with an action button in a shiny app. I am able to show the progress bar, however, the progress bar(blue) prints about 10% and sits there for a long time. After the .bat file is finished, then the progress bar quickly moves to 100%. My question is: How can I show the progress bar moving at all times while the .bat file is executing. The code I am using is below but I am not able to provide the .bat file that I am running because it depends on other large files.
library(shiny)
library(shinyWidgets)
library(ggplot2)
library(shinycssloaders)
ui <- fluidPage(titlePanel(h1("Progress Bar Test",align="center")),
mainPanel(
sidebarPanel(
actionButton("buttonId", "Create exe file"))))
server <- function(input, output, session) {
observeEvent(input$buttonId, {
withProgress(message = 'Creating executable',
detail = 'It takes about 30 seconds per year...',{
bat <- shell("mybatchfile.bat,wait=TRUE")
for (i in 1:length(bat)){
incProgress(setProgress(i/length(bat)))
Sys.sleep(2)
}
} )}
)}
# Run the application
shinyApp(ui = ui, server = server)

Related

Is it possible in Shiny to show the log of an external program run with system(wait=T)?

I am writing a graphical wrapper for a (heavy) external program. I want my Shiny program to pause while the program is running; the only thing to be updated should be what the external program sends to stdout and stderr. Is it possible?
Technically, I am calling the external program with processx::run(...), which is similar to system(..., wait=T). I do not want to run the external program in the background, such as when using system(..., wait=F)
I am diverting stdout (and stderr) to a log file, so I tried using a reactiveFileReader to display that file on the screen. However, this way does not work, as reactivity is paused when running the external program.
Unless you allow a second thread to run (which is effectively what wait=F does), it is not possible, for the simple reason that all execution and event processing stops while the program waits for your process to complete. The next event will only process when your program is done, including reacting to log file changes.
As an alternative, you can suspend reactivity of all components except the log output, and then resume once your program is done running.
I think have found a solution (not too elegant). I can create a separate shiny program that would only output the log file, saved in a specific location. This shiny program can be displayed in an iframe.
I have found that an iframe inside a Shiny app can be refreshed even though the application itself waits for system(wait=T) to finish.
You can verify the above statement for yourself with the code below. The code for insterting an iframe to a shiny app is taken from SO
library(shiny)
ui <- fluidPage(titlePanel("Getting Iframe"),
sidebarLayout(
sidebarPanel(
sliderInput("mySlider", "# of observations", 1, 1000, value=500),
plotOutput("myPlot"),
actionButton("sleepBtn", "Sleep"),
),
mainPanel(fluidRow(
htmlOutput("frame")
)
)
))
server <- function(input, output) {
output$frame <- renderUI({
my_test <- tags$iframe(src="http://news.scibite.com/scibites/news.html", height=600, width=535)
print(my_test)
my_test
})
output$myPlot <- renderPlot({ hist(rnorm(input$mySlider)) })
observeEvent(input$sleepBtn, {
system("sleep 60", wait=T)
})
}
shinyApp(ui, server)

Start R Shiny app as a background job programmatically

Dean Attali has provided a wonderful example on how to exit elegantly from a Shiny app using a close button which both closes the browser window and ends the Shiny session. Consider the following example (modification of the original code from Dean):
The ui.r:
library(shiny)
library(shinyjs)
jscode <- "shinyjs.closeWindow = function() { window.close(); }"
ui <- fluidPage(
useShinyjs(),
extendShinyjs(text = jscode, functions = c("closeWindow")),
htmlOutput(outputId = "exitHeading"),
actionButton(inputId = "closeGUI", label = "Exit")
)
The server.r:
library(shiny)
library(shinyjs)
server <- function(input, output, session) {
output$exitHeading <- renderText("Press the button below to exit the app")
observeEvent(input$closeGUI, {
js$closeWindow()
stopApp()
})
}
And running the app:
runApp(appDir = "/tmp")
My question is about how to start a Shiny app as a background job programmatically, so that the RStudio console is free for further use (or even start a second Shiny app in parallel) while the app is still running, and then end the job using the exit button from the app above. I am looking for a solution which can be added to a package which contains a Shiny app, like this one.
I have read this and have tried the provided sample app, but it still requires manual intervention by the user.
Can someone assist with this?
So as I mentioned in the comments you can achieve this by using the system which basically runs a terminal command, with the wait and show.output.on.console flags set to FALSE.
system('Rscript file.r', wait=F, show.output.on.console = F)
# if you want to access a file from in a package u need
# also in the source of the package you need to put the
# folder `directory` in `root.of.package/inst`
p <- system.file(file.path("directory", "myfile.r"), package = "my.package")
system(paste0('Rscript "', p, '"'), wait=F)

File selection window opens behind R main window

I saw this question has been asked before but not answered. When using tcltk::tk_choose.files() the first time during an R session it opens behind the R main window. All further times it opens in front of the main window (as it should!). Is there a way to have it always in the very front?
Ultimately I would like to use it via shiny as below. So it should also be in front of the shiny window.
library(shiny)
ui <- fluidPage(
actionButton("do", "Open window")
)
server <- function(input, output, session) {
observeEvent(input$do, {
tcltk::tk_choose.files()
})
}
shinyApp(ui, server)
I am aware of base::file.choose() and utils::choose.files(). However, the first does not allow to select multiple files at once and the second does not allow to copy/paste paths for quicker navigation which drives me crazy,..

Change the file upload progress bar behavior in Shiny

I have a Shiny application that requires the user to upload multiple small text files, I do this with fileInput. When I upload multiple files, the progress bar seems to half reset after each file is uploaded in turn. This looks very messy and I'd prefer it if the bar simply showed how many files had finished uploading rather than the progress of any individual file.
Here is a gif of the behavior:
My question is: Is there a way using base Shiny to change the behavior of the upload progress bar for fileInput? And if not, are there any other packages that could be used?
Here is an example of using fileInput
library(shiny)
ui <- fluidPage(
titlePanel("File Input Progress Bar Demo"),
fileInput(
inputId = "MyFiles",
label = "Upload multiple files",
multiple = T
),
mainPanel()
)
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)

Shiny open multiple browser tabs

In my Shiny app I want to open several URL's with a short delay between opening.
Here is some example code that works just fine when I run the app in my RStudio.
library(shiny)
URLs <- c("http://www.google.com", "http://www.stackoverflow.com")
ui <- fluidPage(
actionButton(
"click",
"Click here to open several browser tabs"
)
)
server <- function(input, output){
observeEvent(input$click, {
for (i in URLs){
browseURL(i)
Sys.sleep(1) #Short delay of 1 second
}
})
}
shinyApp(ui, server)
However, when I run this app on shinyapps.io, browseURL() doesn't work (as mentioned here).
Does anyone know how to open multiple browser tabs with a short delay between opening them, so that it also works when the app is deployed on shinyapps.io?
Would it be possible with R code or is JavaScript necessary?
This is a pretty old question, but answering in case others stumble upon while searching.
As mentioned in the reference you linked, I think you need to use some JS to accomplish this task. Below is an example of using the shinyjs package to define a shiny compatible browseURL function. Once we have the function defined we add a few lines to the ui and then call it in the server as js$browseURL().
Note that a pop-up blocker might block the effects of opening multiple tabs. Check your blocker settings if things don't seem to work.
library(shiny)
library(shinyjs)
# define js function for opening urls in new tab/window
js_code <- "
shinyjs.browseURL = function(url) {
window.open(url,'_blank');
}
"
URLs <- c("http://www.google.com", "http://www.stackoverflow.com")
ui <- fluidPage(
# set up shiny js to be able to call our browseURL function
useShinyjs(),
extendShinyjs(text = js_code, functions = 'browseURL'),
actionButton(
"click",
"Click here to open several browser tabs"
)
)
server <- function(input, output){
observeEvent(input$click, {
for (i in URLs){
js$browseURL(i)
Sys.sleep(1) #Short delay of 1 second
}
})
}
shinyApp(ui, server)

Resources