Update a data frame in shiny server.R without restarting the App - r

Any ideas on how to update a data frame that shiny is using without stopping and restarting the application?
I tried putting a load(file = "my_data_frame.RData", envir = .GlobalEnv) inside a reactive function but so far no luck. The data frame isn't updated until after the app is stopped.

If you just update regular variables (in the global environment, or otherwise) Shiny doesn't know to react to them. You need to use a reactiveValues object to store your variables instead. You create one using reactiveValues() and it works much like an environment or list--you can store objects by name in it. You can use either $foo or [['foo']] syntax for accessing values.
Once a reactive function reads a value from a reactiveValues object, if that value is overwritten by a different value in the future then the reactive function will know it needs to re-execute.
Here's an example (made more complicated by the fact that you are using load instead of something that returns a single value, like read.table):
values <- reactiveValues()
updateData <- function() {
vars <- load(file = "my_data_frame.RData", envir = .GlobalEnv)
for (var in vars)
values[[var]] <- get(var, .GlobalEnv)
}
updateData() # also call updateData() whenever you want to reload the data
output$foo <- reactivePlot(function() {
# Assuming the .RData file contains a variable named mydata
plot(values$mydata)
}
We should have better documentation on this stuff pretty soon. Thanks for bearing with us in the meantime.

Related

Using reactiveFileReader in Shiny app to update a dataframe upon change to underlying CSV

I'm working on a complex (for me) Shiny app ~2500 lines of code. The basic structure is as follows, though I can't necessarily share a reproducible example since most of the information is confidential.
Right now, I am using df1 <- read.csv() etc to read in several CSV files as dataframes. I want to use reactiveFileReader() to make it such that the dataframes automatically update when the source CSV file is modified. I think my problem may be related to the fact that I am not doing this in a reactive context, but there is a reason for this. I am using the dataframes df1 etc to perform many calculations and to create new variables throughout the app (UI and server sections).
It also might be important to note that I am doing these file imports in the UI part of the Shiny app, since I need to rely on the factor levels of these dataframes to populate drop down selectInput in my UI. This might not be necessary.
Here is what I have tried (although I am pretty lost):
reader <- reactiveFileReader(intervalMillis = 1000, filePath =
"Data_Record.csv", readFunc = read.csv)
data_record <- reactive({
data_df <- reader()
return(data_df)
})
What I was expecting was for data_record to be a dataframe containing the information from the CSV, but it ends up being a "reactive expression". When I try to perform operations on data_record, like subsetting, I receive errors since that variable is not a dataframe.
Is there any way for me to update these dataframes upon modification to the underlying CSV outside of a reactive context? Even a scheduled update like every 10 seconds or so would work as well. My ultimate goal are dataframes that update when a CSV is modified, but scheduled updates are fine as well.
Thanks in advance for all the help and I apologize for not being able to supply a reproducible example! I will try to add more information as needed.
So if you want the data to be reactive, it has to be imported in the server section of the app as a 'reactive'. In shiny, 'reactives' become functions so to do anything with them you have to reference them their name followed by parenthesis inside a reactive function (reactive, observe, render etc).
For example, with your code above, reader becomes a reactive data frame. You can perform normal data manipulation on reader if you follow the rules of reactives outlined above.
# server.R
reader <- reactiveFileReader(intervalMillis = 1000, filePath =
"Data_Record.csv", readFunc = read.csv)
filtered_reader_df <- reactive({
reader() %>% filter(x > 100)
})
Where filtered_reader_df becomes a reactive filtered version of the reactive csv file. Again, to use filtered_reader_df in subsequent reactive function it must be referenced as filtered_reader_df() as it is a reactive function itself.
Finally, you can still use the reactive csv file to populate UI elements with the updateSelectInput() function inside an observer in the server. For example:
ui <- fluidPage(
selectInput("mySelectInput", "Select")
)
server <- function(input, output, session) {
reader <- reactiveFileReader(intervalMillis = 1000, filePath =
"Data_Record.csv", readFunc = read.csv)
observe({
select_input_choices <- unique(reader()$factor_column)
updateSelectInput(session, inputId = "mySelectInput", choices = select_input_choices)
})
}
The code above will update the choices of the select input every time the reader() data frame changes with the reactiveFileReader where unique(reader()$factor_column) are the reactive unique values of the factor column you want to populate the input with.

R Shiny: reactivevalues from function

I stored several tables in .rds files which I would like to import using readRDS in a Shiny session. Therefore I defined the following global function:
get.station <- function(sname){
file.name <- paste(sname".rds", sep="")
return(readRDS(file.name))
}
within the server function I define the reactive value:
st.reactive <- reactiveValues(get.station(input$station.sel))
where input$station.sel comes from the ui using selectInput(...). This results in the following error message:
Operation not allowed without an active reactive context.
(You tried to do something that can only be done from inside
a reactive expression or observer.)
This error message even does not disappear if I define this function using reactive():
get.station <- reactive({
file.name <- paste(input$station.sel".rds", sep="")
return(readRDS(file.name))
})
and within the server:
st.reactive <- reactiveValues(data=get.station())
Do you have any help?
You've got the right idea, just put the function inside a reactive or observe_ function. While you can define reactiveValues in the initial call, its best, in my opinion, to create the reactive values object empty and then do all your assignments with the <- notation.
The confusion comes from the fact that, despite it's name, reactiveValues is not a reactive expression. It generates a reactiveValues object that reactive values can be stored in, but it only runs once and does not check whether its values are invalidated.
In your case, I'd do the following:
rv <- reactiveValues()
rv$st.reactive <- observe({get.station(input$station.sel)})

Making an object available in Shiny outside renderPlot for renderTable

I'm drafting a simple Shiny App that provides access to a dynamic chart and a corresponding table. The relevant part of the server.R code looks like that:
output$some_plot<- renderPlot({
# Subset data on change in the indicator selection
chrt_demo_dta <- subset(x = dta_la_demo,
subset = <<my-conditions>>>)
# Define the demography chart
ggplot(data = chrt_demo_dta, aes(x = variable_a, y = variable_b)) +
geom_line(aes(colour = GEOGRAPHY_NAME), size = 2) +
theme_bw()}, height = 650, width = 800)
# Section generating table
output$chrt_demo_dta_tbl <- renderTable({chrt_demo_dta})
The problem occurs when I try to access the table I get the following error message:
Error in func() : object 'chrt_demo_dta' not found
It appears that the object chrt_demo_dta is created outside the scoping rules of the renderTable. My question is how can I achieve the following:
I want for the chart and the corresponding table to update dynamically upon the selection, hence my idea to embed the subset command in the renderPlot which works
I want to make use of the same subset in a corresponding table. Ideally, I would like to avoid repeating the subset command. As I have the required data frame ready it appears that it is only a matter of accessing it via the renderTable
I'm aware the the code is not fully reproducible but at this stage I'm not necessarily looking for a particular solution but a more generic guidance whether it would be possible to access an object created within one server element from other server element. If the push comes to shove, I could encapsule the subsetting mechanism in a function and call it twice but it seems to be rather messy solution.
In the server function of server.R:
# Create reactive object w/in server func
chrt_demo_dta <- reactiveVal()
output$some_plot<- renderPlot({
chrt_demo_dta.temp <- subset(
x = dta_la_demo,
subset = <<my-conditions>>>)
# Update the obj within scope of nested function
chrt_demo_dta(chrt_demo_dta.temp)
})
# Access of the updated obj is now possible in original scope
output$chrt_demo_dta_tbl <- renderTable({chrt_demo_dta()})
See related: Shiny : How to modify reactive object
The <<- operator may have unwanted consequences. It sends results to the shared environment, where it is visible to all users of the session. Not only will this create a race-condition where they try to over-write each other, it may expose confidential work to others. You have two solutions: 1) repeat the steps in each local environment, 2) write the result to disk with a unique name (e.g. Sys.time() + data hash). Then you can retrieve it when needed elsewhere. Don't forget to delete the saved file though, or your storage will be consumed.

using reactive expressions unreactivly in shiny?

I need to use:
session$clientData$url_search
which is a reactive expression but I don't want to use it in a reactive wrapper, i.e.
sessionData <- reactive({
sessionData <- session$clientData$url_search
})
is there a way to now use this session data in a non reactive way? i.e.
url <- paste("http://example.web.ninja/,sessionData,sep="")
URLdata <- fromJSON(file=url,method='C')
without having to use:
URLdata <- reactive({
url <- paste("http://example.web.ninja/,sessionData(),sep="")
URLdata <- fromJSON(file=url,method='C')
})
Thanks
In this case the error:
Error in URLdata$Name : object of type closure is not subsettable
indicates that the object needs to be referenced as
URLdata()$Name
This results in a call to the reactive function. Calling a reactive variable within a reactive environment endows that reactive environment with a dependency on that reactive variable. Quickly things can cascade so there is a handy function isolate which allows one to call a reactive variable in a reactive environment and not bestow that dependency. In your case accessing the required object using
isolate(URLdata()$Name)
may be what you want.

Updating embedded data, for example sysdata.rda

My latest submission to CRAN got bounced back because I have assignments to the global environment which is now frowned upon.
I have an embedded data set (sysdata.rda) that contains configuration parameters based upon state (as in United States) the user resides. I have wanted this embedded data set to be updatable when a new user uses the program. I previously updated this data in the initial function the user uses and made it accessible to the user via global assignment.
I am struggling to figure out how to update this embedded data and make it the default data that the user uses for the remainder of their session.
Previously I housed the data in /data and recently switched it to /R/sysdata.rda as it seemed more suited for that locale. Now I'm not so sure.
Any help greatly appreciated
The key is to do the assignment in an environment other than the global environment. There are two basic techniques, using local() and <<- or explicitly creating a new environment:
Working with an explicit environment is straightforward: create the environment and then assign into it like a list:
my_opts <- new.env(parent = emptyenv())
set_state <- function(value) my_opts$state <- value
get_state <- function() my_opts$state
Using local() is a little more complex, and requires some tricks with <<-
set_state <- NULL
get_state <- NULL
local({
state <- NULL
get_state <<- function() state
set_state <<- function(value) state <<- value
})
For more info on how <<- works see https://github.com/hadley/devtools/wiki/environments, in the "Assignment: binding names to values" section.
Why not have an foo.R file in /data which loads the data and updates it when the user calls data(foo)? This is one of the allowed options for /data, but note the following from Writing R Extensions
Note that R code should be “self-sufficient” and not make use of extra functionality provided by the package, so that the data file can also be used without having to load the package.
If you can live with that restriction then data(foo) could load the data, update it, and ensure that it is in a specific named object, which you then refer to in your functions.

Resources