Shiny app does not reflect changes in update RData file
Edit
There is actually a function called reactiveFileReader
in the shiny
package that does exactly what you are looking for: Periodically checking if the files "last modified" time or size changed and rereading accordingly. However, this function can only be used in the server
context, so the file will be read at least once for each user that connects to your app. Options 3 and 4 in my Answer do not have these inefficiencies.
Original Answer from here on
First and foremost, shiny does not have a way to keep track of filechanges AFAIK. Your implementation reloads the .RData
file whenever
shiny-server
gets restarted via bash or- the global variables get reloaded because the app became idle at some point.
There is no way of telling, when the second condition is met. Therefore, I would advocate using one of the following four options. Sorted from easy to you better know your shiny!.
Option 1: Put the load statement in server
Here, the image is reloaded whenever a new user connects with the app. However, this might slow down your app if your .RData
file is huge. If speed is not an issue, I would pick this solution since it is easy and clean.
# server.R
function(input, output, session) {
load("working_dataset.RData")
...
}
The data will also be reread whenever a user refreshes the page (F5)
Option 2: Restart shiny-server whenever you want to re-import your data
(Also see @shosacos answer). This forces the .Rdata
file to be reloaded.
$ sudo systemctl restart shiny-server
Again, this might slow-down your production process depending on the complecity of your app. One advantage of this approach is that you can also use the imported data to build the ui if you load the data in global.R
. (I assume you don't given the code you gave).
Option 3: Import according to "last modified"
The idea here is to check whether the .RData
has changed whenever a user connects to the app. To do this, you will have to use a "global" variable that contains a timestamp of the last imported version. The following code is untested, but should give you an idea on how to implement this feature.
# server.R
last_importet_timestamp <- reactiveVal("")
function(input,output,session){
current_timestamp <- file.info(rdata_path)$mtime
if(last_importet_timestamp() != current_timestamp){
# use parent.frame(2) to make data available in other sessions
load(rdata_path, envir = parent.fame(2))
# update last_importet_timestamp
last_importet_timestamp(current_timestamp)
}
...
}
Speed-wise, this should be more efficient than the first two versions. The data is never imported more than once per timestamp (unless shiny server gets restarted or becomes idle).
Option 4: Import "reactvely"
Basically, the same as option 3 but the file will be checked for changes every 50ms. Here is a full working example of this approach. Note that the data is not loaded unless a change in "last modified" is detected, so the resulting overhead is not too bad.
library(shiny)
globalVars <- reactiveValues()
rdata_path = "working_dataset.RData"
server <- function(input, output, session){
observe({
text = input$text_in
save(text = text, file = rdata_path, compress = TRUE)
})
observe({
invalidateLater(50, session)
req(file.exists(rdata_path))
modified <- file.info(rdata_path)$mtime
imported <- isolate(globalVars$last_imported)
if(!identical(imported, modified)){
tmpenv <- new.env()
load(rdata_path, envir = tmpenv)
globalVars$workspace <- tmpenv
globalVars$last_imported <- modified
}
})
output$text_out <- renderText({
globalVars$workspace$text
})
}
ui <- fluidPage(
textInput("text_in", "enter some text to save in Rdata", "default text"),
textOutput("text_out")
)
shinyApp(ui, server)
If you find it inconvenient to use globalVars$workspace$text
, you can use with
to access the contents of globalVars$workspace
directly.
output$text_out <- renderText({
with(globalVars$workspace, {
paste(text, "suffix")
})
})
How to refresh Rdata objects in shiny app
I changed the initialization of react_data. You should get rid of the load
from your global file. This way the dataset can be garbage collected when you switch. Otherwise, it will exist in .GlobalEnv
forever.
Try this server:
shinyServer(
function(input, output, session) {
react_data <- reactiveVal()
react_data(local({load("DatasetNumber1.Rdata"); data}))
observeEvent(
input$shinyalert,
{
req(input$shinyalert)
load(paste(input$dropdown_dataset,".Rdata",sep=""))
react_data(data)
})
observeEvent(input$button_dataset, {
shinyalert(title = "Are you sure?",
text = "This action can take a while",
type = "warning",
closeOnEsc = TRUE,
closeOnClickOutside = TRUE,
showCancelButton = TRUE,
showConfirmButton = TRUE,
confirmButtonText = "OK",
confirmButtonCol = "#AEDEF4",
cancelButtonText = "Cancel",
inputId = "shinyalert",
callbackR = function(x){
if(x){
showModal(modalDialog("Loading...", footer=NULL))
print(paste(input[["dropdown_dataset"]],sep=""))
removeModal()
}
}
)
})
output$test_text <- renderText(test)
output$test_plot <- renderPlot(plot(react_data()))
}
)
Shiny update data from selectInput
welcome to the site here. This is also a problem I have had recently -- it does not seem to be isolated to selectizeInput
but pertains to any new data that you are trying to get your Shiny app to "see". Here are a couple things to try:
- Delete any
_cache
directories in the root of your shiny server, then try to load again. If there is no difference, touch
the.csv
files (or make an edit if on Windows, to get a new timestamp) and then try to load again. If there is no difference,- Restart the shiny server with
sudo systemctl restart shiny-server
where the last argument is the name of your shiny server (default isshiny-server
)
This last solution is the one that worked most reliably for me -- it is #2 from this document (Shiny app does not reflect changes in update RData file) -- to restart the shiny server from the command line. This worked reliably and routinely. The other ideas in this solution did not work on my machine so must be dependent on your server or client specifications.
The second thing that worked for me was to use reactiveTimer
(https://shiny.rstudio.com/reference/shiny/0.14/reactiveTimer.html).
In any case, if you have been beating your head against a wall with this, it is a tricky issue and is troublesome for many of us. Good luck with picking a best solution for your context.
Reading an RData file into Shiny Application
Here is a possible solution inspired by this post http://www.r-bloggers.com/safe-loading-of-rdata-files/. The Rdata file is loaded into a new environment which ensures that it will not have unexpected side effect (overwriting existing variables etc). When you click the button, a new random data frame will be generated and then saved to a file. The reactiveFileReader then read the file into a new environment. Lastly we access the first item in the new environment (assuming that the Rdata file contains only one variable which is a data frame) and print it to a table.
library(shiny)
# This function, borrowed from http://www.r-bloggers.com/safe-loading-of-rdata-files/, load the Rdata into a new environment to avoid side effects
LoadToEnvironment <- function(RData, env=new.env()) {
load(RData, env)
return(env)
}
ui <- shinyUI(fluidPage(
titlePanel("Example"),
sidebarLayout(
sidebarPanel(
actionButton("generate", "Click to generate an Rdata file")
),
mainPanel(
tableOutput("table")
)
)
))
server <- shinyServer(function(input, output, session) {
# Click the button to generate a new random data frame and write to file
observeEvent(input$generate, {
sample_dataframe <- data.frame(a=runif(10), b=rnorm(10))
save(sample_dataframe, file="test.Rdata")
rm(sample_dataframe)
})
output$table <- renderTable({
# Use a reactiveFileReader to read the file on change, and load the content into a new environment
env <- reactiveFileReader(1000, session, "test.Rdata", LoadToEnvironment)
# Access the first item in the new environment, assuming that the Rdata contains only 1 item which is a data frame
env()[[names(env())[1]]]
})
})
shinyApp(ui = ui, server = server)
Related Topics
Automatically Detect Date Columns When Reading a File into a Data.Frame
How to Add Main Title and Manipulating Axis Labels in Ggplot2 in Rstudio
"Error: Continuous Value Supplied to Discrete Scale" in Default Data Set Example Mtcars and Ggplot2
How to Run a Function Every Second
How Does Settimelimit Work in R
How to Calculate the Median on Grouped Dataset
How to Change Factor Labels into String in a Data Frame
How to Set Axis Ranges in Ggplot2 When Using a Log Scale
Alpha Aesthetic Shows Arrow's Skeleton Instead of Plain Shape - How to Prevent It
Sort Boxplot by Mean (And Not Median) in R
Memory Limits in Data Table: Negative Length Vectors Are Not Allowed
How to Log an R Session to a File
How to Apply Separate Coord_Cartesian() to "Zoom In" into Individual Panels of a Facet_Grid()
Dplyr 0.7 Equivalent for Deprecated Mutate_
How to Reference Column Names That Start with a Number, in Data.Table