I was wondering if there was a way to get Shiny to check something at a specified time each day if it is running. Now I know this is not recommended and I have read through
Schedule task on a shiny application
Schedule R script using cron
call myFunction daily, at specific time, in shiny?
as well as I am aware of the reactiveTimer function in Shiny. However, I have developed and deployed my Shiny App as a desktop app instead of a url and consequently my colleagues like to leave it open. Here is the basic example of what I am trying to:
library(shiny)
ui <- fluidPage()
server <- function(input, output, session) {
test <- reactiveValues(value = format(as.POSIXlt(Sys.time()), "%H:%M"))
observeEvent(test$value == "7:15", {
stopApp()
})
}
shinyApp(ui, server)
The reason I would like the application to stop at a scheduled time is because I want the application to check for an update and re-launch after it updates. I suppose it should only stop if their is something to update but the above is a simpler idea of what I am trying to accomplish.
Is there anyway to get shiny to execute some code at a specific time? I know reactiveTimer is an option but this performs a task after a specified amount of time but not at a specific time each day.
Another option is if I could get a vbs script or even just a different r script to close the Shiny App but I have not been able to figure out how to do that either. Any advice or ideas would be a big help. Thanks!
This does the trick (a little verbose, but works)
You need to set the variable timeStop (HH:MM:SS)
library(shiny)
ui <- fluidPage(
uiOutput("info")
)
server <- function(input, output, session) {
## Variable to set the time when app stops automatically (HH:MM:SS)
timeStop <- "22:47:20"
toStop <- as.POSIXct(timeStop, format="%H:%M:%S")
if (Sys.time() > toStop) {
toStop <- toStop + 86400
}
secsToStop <- round(as.numeric(difftime(toStop, Sys.time(), units = "secs")) * 1000)
timeToStop <- reactiveTimer(secsToStop)
trick <- reactiveValues()
trick$toFire <- FALSE
observeEvent(timeToStop(), {
if (trick$toFire) {
stopApp()
} else {
trick$toFire <- TRUE
}
})
output$info <- renderUI({
h2(paste("App will stop automatically at ", toStop))
})
}
shinyApp(ui, server)
Related
I have a shiny app which will be redeployed roughly each week to shinyapps.io using the rsconnect package.
On the front page of the app I want to display the time the app was last deployed.
I thought this would be possible by doing something along the lines of this:
library(shiny)
deployment_time <- lubridate::now()
ui <- fluidPage(
p(glue::glue("Deployment time {deployment_time}"))
)
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)
The reasoning behind this is that deployment_time is set outwith the server, so should only be run once when the app is deployed and not when users view the app later on.
However, the behaviour I am observing is that after a few times loading the app the deployment time will update to the current time, suggesting that this code is in fact rerun at some point.
Any ideas what's going on and how I can set a deployment time which stays fixed without having to manually set a date in the script?
Thanks in advance :)
I would store the last deployment date in a local file that's uploaded to the your Shiny Server alongside your application code.
Below is a minimally reproducible example.
Deployment Record
First is a function that you will only run when deploying an application. You can take some time to insert this function into your deployment scripts so that it writes the time prior to uploading your files to the server.
#' Record the date of app deployment.
record_deployment_date <-
function(deployment_history_file = "deployment_history.txt") {
# make sure the file exists...
if (!file.exists(deployment_history_file)) {
file.create(deployment_history_file)
}
# record the time
deployment_time <- Sys.time()
cat(paste0(deployment_time, "\n"),
file = deployment_history_file,
append = TRUE)
}
Then, you'll have another function to access the last recorded deployment date.
#' Return the last recorded deployment date of the application.
load_deployment_date <-
function(deployment_history_file = "deployment_history.txt") {
deployment_history <- readLines(deployment_history_file)
# return the most recent line
deployment_history[[length(deployment_history)]]
}
Minimal App Example
Finally, you can call the previous function and insert the loaded text into a renderText function to show your last deployment date.
ui <- fluidPage(mainPanel(tags$h1("My App"),
textOutput("deploymentDate")))
server <- function(input, output, session) {
output$deploymentDate <- renderText({
paste0("Deployment Time: ", load_deployment_date())
})
}
shinyApp(ui, server)
Naturally you will want to change the location of your deployment_history.txt file, customize the formatting of your time, etc. You could take this one step further to also include the deployment version. But, this is the minimal info you need to get started.
I'm trying to write tests in order to check if a shiny function fileInput() is reading files correctly.
My problem is that I don't know what to write in session$setInputs() in order to grab the file from my system.
Here is an example app:
library(shiny)
ui <- fluidPage(
tagList(
fileInput("file", "Please upload a file"),
tableOutput("text")
)
)
server <- function(input, output, session){
file <- reactive({input$file})
output$text <- renderTable({
req(file())
read.csv(file()$datapath)
})
}
shinyApp(ui, server)
Now, I want to be able to use testServer() in order to set a file address and see if my app loads it correctly, but I can't figure out how to do it:
address <- "path/to/text.csv"
testServer(server, {
session$setInputs(file = address)
print(file())
})
I think it has to do with the fact that fileInput() uploads the file to a temp folder and returns to shiny a dataframe where you can get the datapath, but I'm unable to simulate this pass in order to make the test work
I have the same question as you do, I did some investigating and could not find any way of testing fileInput with testServer or testthat. The best solution that I found was testing fileInput by taking a snapshot when recording a test with recordTest() of the shinytest package.
Sorry for answering this late.
I asked the same question at rstudio's forums and got an answer here
The basics of it are setting the file's datapath as a list:
address <- "path/to/text.csv"
testServer(server, { session$setInputs(file= list(datapath = address)) })
I am new to R and certainly very new to RShiny.
I wrote a packages which logs events into a log file. Rstudio is capable of viewing live logging unitl the file is 5MB. So now i am thinking about writing a Rshiny app that views the logs as they are being written to the file.
Which functions would help me to update the viewer?
Thanks!
You can call invalidateLater inside a reactive when you import the data. Data will be refreshed every time invalidateLater will fire (in my case every second).
Here a really silly example (my .csv doesn't update, it just prints that data is being refreshed to console):
library(shiny)
ui <- fluidPage(
tableOutput("data")
)
server <- function(input, output, session) {
# mtcars.csv will be read every second
mtcars_df <- reactive({
invalidateLater(1000, session)
read.csv("mtcars.csv")
})
# mtcars_df is a reactive, hence will force the table to re-render
output$data <- renderTable({
print(paste("Table refreshed at", Sys.time(), collapse = " "))
mtcars_df()
})
}
shinyApp(ui, server)
In my Shiny app users can generate heavy powerpoint report. When it contains a lot of slides it could take > 30 minutes to be done. And therefore I'd like to process those tasks in independent processes/tasks which could work even when app is closed - e.g. user clicks button to generate report, closes app and when report is ready app informs user by email.
Are there any good practices or proven solutions to do this?
My first thought was using future package with plan(multisession) set - but I'm not sure what happens when user closes the app - future session closes too or not?
I was lucky enough to be at London EARL this week and I think one of the best presentations I saw there was about exactly this (by Joe Cheng). You would need the promises package for this to work and as it says on the documentation a special version of shiny devtools::install_github("rstudio/shiny#async") that supports asynchronous programming.
You can find a first documentation here on how this works by using dplyr and promises (future is also compatible).
As a small example (taken from the documentation), running an intensive calculation using the following:
read.csv.async("data.csv") %...>%
filter(state == "NY") %...>%
arrange(median_income) %...>%
head(10) %...>%
View()
would essentially return the console cursor back, allowing you to run any other command you want and would automatically open the View tab once this was finished. I might be able to dig out a shiny example in a bit, but keep in mind this is still under development and will be released before the end of the year (with a more comprehensive documentation I would imagine).
So I made some example workaround using future package. Code executes in separate session (cluster) even when app is closed. I think the next step is just to figure out how app should check if process is still running or is finished. Any ideas?
library(future)
cl <- parallel::makeCluster(2L)
plan(cluster, workers = cl)
server <- function(input, output) {
observeEvent(input$run, {
iteration <- as.numeric(input$iteration)
path <- input$path
future::future({
writeLog <- function(n, path) {
file.remove(path)
for (i in 1:n) {
cat("#", i, "-", as.character(Sys.time()), "\n", file = path, append = TRUE)
Sys.sleep(1)
}
}
writeLog(iteration, path)
}, globals = c("iteration", "path"))
})
}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
tags$div("This app writes to file in cluster which means it is computed in parallel to this session.
It will execute even when app is closed.")
, br()
, shiny::textInput("path", "Path to log file", value = "/src/dev/export_performance/future.log")
, shiny::textInput("iteration", "Iteration number", value = 60)
),
mainPanel(
br()
, actionButton("run", "Run future")
)
)
)
shinyApp(ui = ui, server = server)
I have a shiny app with a number of tabPanels.
In one of these panels I want to write a time signal generated in seewave and tuneR to a www subdirectory.
If I run the commands on the R-promt, everything works, but I can't get it running in my server.R.
I tried observe, but then the input$ variables are not updated:
observeEvent(input$button,{
cat("Writing wav file")
})
eventReactive(input$button,{
"Inbutton"
pi<-4*atan(1)
s5<-synth(44100,5,input$freq1,input$amp1*2000,"sine",shape=NULL,p=0,
am=c(0,0,0),fm=c(0,0,0),harmonics=1,plot=FALSE,output="Wave")
s6<-synth(44100,5,input$freq2,input$amp2*2000,"sine",shape=NULL,
p=input$phase/180*pi,am=c(0,0,0),fm=c(0,0,0),
harmonics=1,plot=FALSE,output="Wave")
s7<-s5+s6
str(s7)
Wobj<-s7
wav_dir<-"./www"
wav_file<-file.path(wav_dir,"howling2.wav")
writeWave(Wobj,filename=wav_file)
play(s7)
})
I've managed somehow to save the file. I defined function that generates the sound and load it beforehand. Then in server function I call it like that:
server <- function(input, output){
observeEvent(input$button, {
sound <- sonify(input$name) # this is already a Wave object
wvname <- paste0("sound", input$button,".wav")
writeWave(sound, paste0("www/", wvname))
})
}
Then to implement it in UI follow this and this