Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

r - It is possible to restore a session, locally, in a Shiny app if the inputs have been previously written in a RDS file?

I am developing a shiny app to be used locally. I am trying to develop a system for the user to be able to restore a former session.

For that, I took the code from this entrance: Saving state of Shiny app to be restored later , and it did work, however I wanted to be able to restore the inputs within a different session, so that I added a fileInput (Restore Session) and a downloadButton (Save Session) to the code, but unfortunately I could not make it work.

My code is as follows:

library(shiny)  

ui <- fluidPage(
  textInput("control_label",
            "This controls some of the labels:",
            "LABEL TEXT"),
  numericInput("inNumber", "Number input:", min = 1, max = 20, value = 5, step = 0.5),
  radioButtons("inRadio", "Radio buttons:",
               c("label 1" = "option1",
                 "label 2" = "option2",
                 "label 3" = "option3")),
  fileInput("load_inputs", "Restore Session", multiple = FALSE),
  downloadButton("save_inputs", 'Save Session')
)

server <-  function(input, output,session) { 

  # SAVE SESSION
  output$save_inputs <- downloadHandler(
    filename = function() {
      paste("session", ".RDS", sep = "")
    },
    content = function(file) {
      saveRDS( reactiveValuesToList(input), file)
    })

  # LOAD SESSION
  load_sesion <- reactive({
    req(input$load_inputs)
    load_session <- readRDS( input$load_inputs$datapath )
  })

  observeEvent(input$load_inputs,{       
    if(is.null(input$load_inputs)) {return(NULL)}

    savedInputs <- load_sesion()
    inputIDs      <- names(savedInputs) 
    inputvalues   <- unlist(savedInputs) 

    for (i in 1:length(inputvalues)) { 
      session$sendInputMessage(inputIDs[i], list(value=inputvalues[[i]]) )
    }
  })}

shinyApp(ui, server)

With this code I can save the inputs of the session and I can read them in the following session, however I am not able to use those values stored on the RDS as inputs in another session.

Thanks a lot,

Rachael

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

As suggested in my above comments the following app uses shiny's built-in capabilities to create bookmarks instead of using a custom function to save the current state of the inputs.

After the download button is clicked a bookmark is stored on the server side, renamed and copied to the downloadHandler.

If the user uploads a bookmark file, the needed path is created based on the filename and the user gets redirected to the earlier session. (Also see the commented out alternative, which requires the user to actively switch sessions).

Of course you could implement a modal to have the user input a name for the session to avoid using the rather cryptic bookmark hash as the filename.

Edit: Implemented a modal to let the user provide a custom session name (limited to alphanumeric characters)

library(shiny)
library(shinyjs)
library(utils)
library(tools)
library(stringi)

ui <- function(request) {
    fluidPage(
        useShinyjs(),
        textInput("control_label", "This controls some of the labels:", "LABEL TEXT"),
        numericInput("inNumber", "Number input:", min = 1, max = 20, value = 5, step = 0.5 ),
        radioButtons("inRadio", "Radio buttons:", c("label 1" = "option1", "label 2" = "option2", "label 3" = "option3")),
        fileInput("restore_bookmark", "Restore Session", multiple = FALSE, accept = ".rds"),
        actionButton("save_inputs", 'Save Session', icon = icon("download"))
    )
}

server <-  function(input, output, session) {
    latestBookmarkURL <- reactiveVal()
    
    onBookmarked(
        fun = function(url) {
            latestBookmarkURL(parseQueryString(url))
        }
    )
    
    onRestored(function(state) {
        showNotification(paste("Restored session:", basename(state$dir)), duration = 10, type = "message")
    })
    
    observeEvent(input$save_inputs, {
        showModal(modalDialog(
            title = "Session Name",
            textInput("session_name", "Please enter a session name (optional):"),
            footer = tagList(
                modalButton("Cancel"),
                downloadButton("download_inputs", "OK")
            )
        ))
    }, ignoreInit = TRUE)
    
    # SAVE SESSION
    output$download_inputs <- downloadHandler(
        filename = function() {
            removeModal()
            session$doBookmark()
            if (input$session_name != "") {
                
                tmp_session_name <- sub("\.rds$", "", input$session_name)
                
                # "Error: Invalid state id" when using special characters - removing them:
                tmp_session_name <- stri_replace_all(tmp_session_name, "", regex = "[^[:alnum:]]")
                # TODO: check if a valid filename is provided (e.g. via library(shinyvalidate)) for better user feedback
                
                tmp_session_name <- paste0(tmp_session_name, ".rds")
                
            } else {
                paste(req(latestBookmarkURL()), "rds", sep = ".")
            }
        },
        content = function(file) {
            file.copy(from = file.path(
                ".",
                "shiny_bookmarks",
                req(latestBookmarkURL()),
                "input.rds"
            ),
            to = file)
        }
    )
    
    # LOAD SESSION
    observeEvent(input$restore_bookmark, {
        
        sessionName <- file_path_sans_ext(input$restore_bookmark$name)
        targetPath <- file.path(".", "shiny_bookmarks", sessionName, "input.rds")
        
        if (!dir.exists(dirname(targetPath))) {
            dir.create(dirname(targetPath), recursive = TRUE)
        }
        
        file.copy(
            from = input$restore_bookmark$datapath,
            to = targetPath,
            overwrite = TRUE
        )
        
        restoreURL <- paste0(session$clientData$url_protocol, "//", session$clientData$url_hostname, ":", session$clientData$url_port, "/?_state_id_=", sessionName)
        
        # redirect user to restoreURL
        runjs(sprintf("window.location = '%s';", restoreURL))
        
        # showModal instead of redirecting the user
        # showModal(modalDialog(
        #     title = "Restore Session",
        #     "The session data was uploaded to the server. Please visit:",
        #     tags$a(restoreURL),
        #     "to restore the session"
        # ))
    })
    
}

shinyApp(ui, server, enableBookmarking = "server")

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...