1

How do you locally save a reactive data frame that is modified during an R session, for use in your next R session? Whether that next R session involves restarting R, logging off/on your computer, etc. Without prompting the user to download and save a .csv or other file; I assume the best way to do this is to save the data frame to some type of temporary or archive folder on the user’s computer but I don't know how to set it this up. The user simply clicks the "Save" action button (a placeholder in the below MWE code) and the saved data frame becomes available for the next session. If the user doesn't click "Save", then the last saved data frame is retrieved when restarting the session, or if there is no archived data frame, then the session simply starts with the default data frame data.frame(x = c(1, 2, 3)) per the below MWE code.

The data will not be the same for all sessions and all connections: if one user updates the data, it would only affect the data that the user sees and no other user.

From researching this I understand there are many options, but I am looking for something simple for a relative newcomer like me to get started. Saving can be made more sophisticated later if advisable.

I'll add a "Reset" button later so the user can revert back to the original data frame in this example of data.frame(x = c(1, 2, 3)).

MWE code:

library(rhandsontable)
library(shiny)

myDF <- data.frame(x = c(1, 2, 3))

ui <- fluidPage(
  br(),
  fluidRow(
    column(6,
      actionButton('addCol','Add'),
      actionButton('savTbl','Save')
    )
  ),
  br(),
  rHandsontableOutput('hottable')
)

server <- function(input, output, session) {
  EmptyTbl <- reactiveVal(myDF)
  
  observeEvent(input$hottable, {
    EmptyTbl(hot_to_r(input$hottable))
  })
  
  output$hottable <- renderRHandsontable({
    rhandsontable(EmptyTbl(),useTypes = FALSE)
  })
  
  observeEvent(input$addCol, {
    newCol <- data.frame(c(1, 2, 3))
    names(newCol) <- paste("Col", ncol(hot_to_r(input$hottable)) + 1)
    EmptyTbl(cbind(EmptyTbl(), newCol))
    
  })
  
}

shinyApp(ui, server)
Vivek Lele
  • 109
  • 4
  • It depends. Is the app deployed in a container? For example, on shinyapps.io? If so, then you probably can't. Files *created* by the app are volatile in that case. If the app is running locally, then simply `saveRDS`/`readRDS` should be sufficient. If you are in a container, then you need to use some remote service, such as AWS, and design an interface between the container and the storage service. – Limey Oct 27 '22 at 06:55
  • 1
    I'd recommend to check shiny's [bookmarking capabilities](https://shiny.rstudio.com/articles/bookmarking-state.html) and library([shinyStore](https://github.com/trestletech/shinyStore)) also please see my related answers [here](https://stackoverflow.com/questions/72715897/shiny-how-to-remember-user-input-after-click-on-refresh/72716172#72716172), [here](https://stackoverflow.com/a/68253464/9841389) and [here](https://stackoverflow.com/questions/68371723/how-to-use-the-localstorage-option-for-dt-in-r-shiny/68409477#68409477). – ismirsehregal Oct 27 '22 at 07:05
  • Furthermore, I just saw: [shinyStorePlus](https://github.com/oobianom/shinyStorePlus). – ismirsehregal Oct 27 '22 at 07:19
  • Hi ismirsehregal, I am reviewing the materials for shinyStorePlus and it seems more robust and secure than shinyStore. In running their examples it seems to provide exactly what I need. Also since it's on CRAN I assume it's been more thoroughly vetted than shinyStore which is a development version I believe. – Curious Jorge - user9788072 Oct 28 '22 at 06:03
  • 1
    Yes - as shinyStore wasn't touched on github since 2014, I'd also check shinyStorePlus first. Cheers – ismirsehregal Oct 28 '22 at 06:47

1 Answers1

0

Here is ismirsehregal's generous solution in post How to implement shinyStore when using a table generated by the rhandsontable R package?:

Code:

# If not installed already, un-comment and run the below 3 lines to install shinyStore package:
# install.packages("devtools")
# library(devtools)
# install_github("trestletech/shinyStore")

library(rhandsontable)
library(shiny)
library(shinyStore)

myDF <- data.frame(x = c(1, 2, 3))

ui <- fluidPage(
  initStore("store", "shinyStore-ex1"),
  br(),
  fluidRow(column(
    6,
    actionButton('addCol', 'Add column'),
    actionButton("save", "Save", icon("save")),
    actionButton("clear", "Clear", icon("stop")) # add
  )),
  br(),
  rHandsontableOutput('hottable')
)

server <- function(input, output, session) {
  uiTable <- reactiveVal(myDF)
  
  output$hottable <- renderRHandsontable({
    rhandsontable(uiTable(), useTypes = FALSE)
  })
  
  observeEvent(input$hottable, {
    uiTable(hot_to_r(input$hottable))
  })
  
  observeEvent(input$addCol, {
    newCol <- data.frame(c(1, 2, 3))
    names(newCol) <-
      paste("Col", ncol(hot_to_r(input$hottable)) + 1)
    uiTable(cbind(uiTable(), newCol))
  })
  
  observeEvent(input$save, {
    updateStore(session, name = "uiTable", uiTable())
  }, ignoreInit = TRUE)
  
  observeEvent(input$clear, {
    # clear tracking table:
    uiTable(myDF)
    
    # clear shinyStore:
    updateStore(session, name = "uiTable", myDF)
  }, ignoreInit = TRUE)
  
  observeEvent(input$store$uiTable, {
    uiTable(as.data.frame(input$store$uiTable))
  })
}

shinyApp(ui, server)