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)
Related
Setting:
I have one Shiny-App (app.r) from which I want a reactive graph of all reactive elements. In my understanding, one must trigger these elements once before they are shown in the graph. Therefore, I created a Start_App.r which runs the app and records reactive elements and a Navigate_through_App.r-Script which navigates via RSelenium through the App. Because R is busy when running a shiny app, both scripts need to run in different R Sessions. Starting them 'by hand' results in the required reactive graph:
In order to automate the process of starting two R Sessions and executing the scripts, I created a simple Batch-file called Start.bat. It starts the shiny app, the RSelenium browser and navigates through the app as intended.
Problem:
When I run the batch-script, the files recorded by the reactlog-command can't be found on my machine:
It looks like there was a try to create this file (because there is this explicit path), but somehow it does not worked. Any ideas what could cause this problem?
Code:
(All files in the same folder)
app.r
library(shiny)
library(shinyjs)
jscode <- "shinyjs.closeWindow = function() { window.close(); }"
ui <- fluidPage(
useShinyjs(),
extendShinyjs(text = jscode, functions = c("closeWindow")),
actionButton("close", "Close window")
)
server <- function(input, output, session) {
observeEvent(input$close, {
js$closeWindow()
stopApp()
})
}
shinyApp(ui, server)
Start_App.r
#Install & load packages
if (!require("shiny")) install.packages("shiny")
library(shiny)
if (!require("reactlog")) install.packages("reactlog")
library(reactlog)
#tell shiny to log reactivity
#reactlog::reactlog_enable()
options(shiny.reactlog = TRUE)
#run App
runApp(getwd(), host = getOption("shiny.host", "127.0.0.1"), port=7777, launch.browser = TRUE)
#once app has closed, display reactlog from shiny
shiny::reactlogShow()
Navigate_through_App.r:
#Install & load packages
if (!require("RSelenium")) install.packages("RSelenium")
library(RSelenium)
#free all ports
system("taskkill /im java.exe /f", intern=FALSE, ignore.stdout=FALSE)
#Start Selenium and access shiny-app
rD <- rsDriver(port = 4564L, browser = "firefox") # "chrome" / "firefox" is possible
#Assign the client to an object
remDr <- rD[["client"]]
#Open Shiny-App
remDr$navigate("http://127.0.0.1:7777")
#Stop App
#Click button "App beenden & Browser schließen"
webElem <- remDr$findElement(using = 'xpath', value = '//*[#id="close"]')
webElem$clickElement()
Start.bat:
START /HIGH R -e "source('Start_App.r')"
Rscript Navigate_through_App.r
pause
I'm trying to deploy a Shiny app that allows the user to upload a pdf document and extract a table from a selected page. For this I'm using the package tabulizer. A basic reproducible example:
library(shiny)
library(tabulizer)
ui <- fluidPage(
fileInput("report", NULL,buttonLabel = "Upload report"),
numericInput("page","Specify page number",value = 1),
actionButton("extract","Extract"),
verbatimTextOutput("data")
)
server <- function(input, output, session) {
generate_data <- reactive({
req(input$report)
# This locate_area function calls runApp() from the tabulizer package
area <- locate_areas(file = input$report$datapath,
pages = input$page,
widget = "reduced")
table <- extract_tables(file = input$report$datapath,
pages = input$page,
area = area)
return(table)
})%>% bindCache(input$page) %>% bindEvent(input$extract)
output$data <- renderPrint({
# Just for the sake of this example to show it works
generate_data()
})
}
shinyApp(ui = ui, server = server)
If I run this locally, the locate_area() will make the pdf page pop-up on my viewer in RStudio and all is well. However, if I publish the app it doesn't run after clicking the action button. I know the problem comes from the locate_area() as it essentially calls another runApp within the shiny app. I have tried using different widgets for locate_area() to no avail. Does anybody know a way to circumvent this issue?
Judging by the relevant issues - issue 15 and issue 53 - it appears that your best way to go is really to copy the functionality from the original tabulizer function into your own app, as currently the package does not provide an easy integration with other Shiny apps.
I'm having an issue with the running of a R shiny app. Here's what I do:
open RStudio
load the shiny code (e.g. app.R)
set the wd
library(shiny)
press on "Run App"
Then nothing happens.
And if I try to terminate the execution, R does not answer anymore and says to force the closing of RStudio.
Here's one of my codes (I tried some, so I don't think this is the issue, but I report one anyway):
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
titlePanel("Un'applicazione con uno slider"),
sidebarLayout(
h1("Sposta lo Slider!"),
sliderInput("slider1", "Spostami!", 0, 100, 0)
),
mainPanel(
h3("Valore dello slider:"),
textOutput("text")
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$text <- renderText(input$slider1)
}
# Run the application
shinyApp(ui = ui, server = server)
Do you have any advice to give me in order to make anything happen? I have no errors shown, so I don't know what to do...
I just see "runApp(...mypath.../app)" and blank space after it.
Thank you in advance.
Edit 1:
I also tried this, but nothing happened (as before):
library(shiny)
runExample("01_hello")
Edit 2: Copy-pasting the code directly in the console doen not work either
I was experiencing the same issue with R 4.1 on Windows 10. Updating all packages seems to have solved it:
update.packages(ask = FALSE, checkBuilt = TRUE)
I want to create a shiny application that has an input for writing some R function or Command, reads it through the ui.R then passes it to the server.R that executes that R command to display the results.
I spent hours searching about some example but couldn't find anything, I already know how to create Shiny apps using ui and server and pass the input values to server and work with them, but I have no idea if it's possible to create a shiny app like R where you can write the commands and return the results, any example or help would be appreciated.
Letting users run code in your app is bad practice, since it comes with great security risks. However, for development you might want to check this function from the shinyjs package by Dean Attali.
Example from the link:
library(shiny)
library(shinyjs)
shinyApp(
ui = fluidPage(
useShinyjs(), # Set up shinyjs
runcodeUI(code = "shinyjs::alert('Hello!')")
),
server = function(input, output) {
runcodeServer()
}
)
Some examples of why it is not such a good idea to include when deploying your app:
Try the input:
shinyjs::alert(ls(globalenv()))
or
shinyjs::alert(list.files())
I was able to find an alternative solution that doesn't require shinyjs -- wanted to restate Florian's concern that in general it is not a good thing (not secure) to let users run code in your Shiny app. Here is the alternative:
library(shiny)
library(dplyr)
ui <- fluidPage(
mainPanel(
h3("Data (mtcars): "), verbatimTextOutput("displayData"),
textInput("testcode", "Try filtering the dataset in different ways: ",
"mtcars %>% filter(cyl>6)", width="600px"),
h3("Results: "), verbatimTextOutput("codeResults"))
)
server <- function(input, output) {
shinyEnv <- environment()
output$displayData <- renderPrint({ head(mtcars) }) # prepare head(mtcars) for display on the UI
# create codeInput variable to capture what the user entered; store results to codeResults
codeInput <- reactive({ input$testcode })
output$codeResults <- renderPrint({
eval(parse(text=codeInput()), envir=shinyEnv)
})
}
shinyApp(ui, server)
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)