azdatasci
azdatasci

Reputation: 841

Reading an RData file into Shiny Application

I am working on a shiny app that will read a few RData files in and show tables with the contents. These files are generated by scripts that eventually turns the data into a data frame. They are then saved using the save() function.

Within the shiny application I have three files:

ui.R, server.R, and global.R

I want the files to be read on an interval so they are updated when the files are updated, thus I am using:

reactiveFileReader() 

I have followed a few of the instructions I have found online, but I keep getting an error "Error: missing value where TRUE/FALSE is needed". I have tried to simplify this so I am not using:

reactiveFileReader() 

functionality and simply loading the file in the server.R (also tried in the global.R file). Again, the

load()

statement is reading in a data frame. I had this working at one point by loading in the file, then assigning the file to a variable and doing an "as.data.table", but that shouldn't matter, this should read in a data frame format just fine. I think this is a scoping issue, but I am not sure. Any help? My code is at:

http://pastebin.com/V01Uw0se

Thanks so much!

Upvotes: 2

Views: 10639

Answers (2)

azdatasci
azdatasci

Reputation: 841

Ok - I figured out how to do what I need to. For my first issue, I wanted the look and feel of 'renderDataTable', but I wanted to pull in a data frame (renderDataTable / dataTableOutput does not allow this, it must be in a table format). In order to do this, I found a handy usage of ReportingTools (from Bioconductor) and how they do it. This allows you to use a data frame directly and still have the HTML table with the sorts, search, pagination, etc.. The info can be found here:

https://bioconductor.org/packages/release/bioc/html/ReportingTools.html

Now, for my second issue - updating the data and table regularly without restarting the app. This turned out to be simple, it just took me some time to figure it out, being new to Shiny. One thing to point out, to keep this example simple, I used renderTable rather than the solution above with the ReportingTools package. I just wanted to keep this example simple. The first thing I did was wrap all of my server.R code (within the shinyServer() function) in an observe({}). Then I used invalidateLater() to tell it to refresh every 5 seconds. Here is the code:

## server.R ##
library(shiny)
library(shinydashboard)
library(DT)

shinyServer(function(input, output, session) {

  observe({

    invalidateLater(5000,session)

    output$PRI1LastPeriodTable <- renderTable({
      prioirtyOneIncidentsLastPeriod <- updateILP()
    })
  })
})

Now, original for the renderTable() portion, I was just calling the object name of the loaded .Rdata file, but I wanted it to be read each time, so I created a function in my global.R file (this could have been in server.R) to load the file. That code is here:

updateILP <- function() {
  load(file = "W:/Projects/R/Scripts/ITPOD/itpod/data/prioirtyOneIncidentsLastPeriod.RData", envir = .GlobalEnv)
  return(prioirtyOneIncidentsLastPeriod)
}

That's it, nothing else goes in the global.R file. Your ui.R would be however you have it setup, call tableOutout, dataTableOutput, or whatever your rendering method is in the UI. So, what happens is every 5 seconds the renderTable() code is read every 5 seconds, which in turns invokes the function that actually reads the file. I tested this by making changes to the data file, and the shiny app updated without any interaction from me. Works like a charm.

If this is inelegant or is not efficient, please let me know if it can be improved, this was the most straight-forward way I could figure this out. Thanks to everyone for the help and comments!

Upvotes: 2

Xiongbing Jin
Xiongbing Jin

Reputation: 12107

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)

Upvotes: 11

Related Questions