Ketty
Ketty

Reputation: 851

How to save current workspace in R Shiny

I would like to allow my users to save their current workspace to a directory of their choosing. I am not able to make it work.

Below is my code. Any suggestions? Thanks in advance.

ui.R:

shinyUI(fluidPage(
  titlePanel("Save RData"),
  sidebarLayout(
    sidebarPanel(
    ),
    mainPanel(
      downloadButton('download_structure', "Save")
    )
  )
))

server.R

shinyServer(function(input, output) {

  output$download_structure <- downloadHandler(
    filename = function() {paste("Test.RData")},
    content  = function(file) {
      list = ls(all.names = TRUE)
    }
  )

})

EDIT:

I also tried the following codes.

I entered "C:/Users/MyName/Desktop/" or "C://Users//MyName//Desktop//" as the input$RDdata_dir_save. Both are not working.

Any suggestions would be really appreciated!

snippets of my ui.R:

textInput("RData_name_save", "RData name"),
textInput("RData_dir_save", "Save directory"),

snippets of my server.R:

tempdir  <- paste0(input$RData_dir_save,input$RData_name_save,'.RData"')
save.image(file=eval(parse(text=tempdir)))          

Upvotes: 1

Views: 1239

Answers (2)

Julien Colomb
Julien Colomb

Reputation: 563

the problem is that objects are not in the shiny environment and save.image() does not save anything interesting.

maybe this is of interest, copied from https://groups.google.com/forum/#!topic/shiny-discuss/_iLbT3Aaz3I

I often wish that I could interactively work within my shiny application interactively, similar to using browse()in a function., and sometimes I use a shiny GUI to get to a state where I just want to save things.

So, I wrote something that can save all the shiny application objects,which uses Hadley's pryr package to recursively list the objects. So you need this somewhere (I think it belongs in global.R or server.R) library(pryr)

In ui.R you need an action button. You could add this to one of the existing shiny examples. actionButton("save_objs", "Save Objects")

In server.R I have this code, which listens to save_objs:

observeEvent(input$save_objs, {
    # Run whenever save_objs button is pressed

    print("** saving objects! **")

    ## Print the objects being saved
    print(rls())
    # ## Put  objects into current environment
    for(obj in unlist(rls())) {
        if(class(get(obj, pos =  -1))[1] == "reactive"){
            ## execute the reactive objects and put them in to this 
            ## environment i.e. into the environment of this function
            assign(obj, value = eval(call(obj)))
        } else {
            ## grab the global variables and put them into this 
            ## environment
            assign(obj, value = get(obj, pos =  -1))
        }
    }

    input_copy <- list()
    for(nm in names(input)){
        # assign(paste0("input_copy$", nm), value <- input[[nm]])
        input_copy[[nm]] <- input[[nm]]
    }

    ## save objects in current environment
    save(list = ls(), file = "shiny_env.Rdata", envir = environment())

    print("** done saving     **")
})

I use print statements liberally during development, feel free to omit them.

This took me a while to figure out, so hopefully it will save someone else time (maybe even me later when I forget and google "R how to save objects in shiny").

As a side note, I can't understand how the rls can find the environment with the reactive objects. It's not in my current budget to buy Hadley's Advanced Programming in R, so I'll have to wait to find out. I tried to get the objects directly with various combinations of parent.frame and parent.env, but I could only find Shiny internal objects and objects in my normal search path. So... there's some clever stuff in that pryr package.

Upvotes: 1

parth
parth

Reputation: 1631

I've tried a workaround using directoryInput and taking file name from user. This solution doesn't use downloadHandler functionality, it's just a temporary workaround. For the selection of directory, i've used directoryInput as configured here.

ui.R

library(shiny)

shinyUI(fluidPage(
  fluidRow(
    column(
      width = 10,
      titlePanel("Save RData"),
      directoryInput('directory', label = 'select directory'),
      hr(),
      textOutput("dir"),
      textInput("file_name","give file name"),
      actionButton("save","Save RData"),
      conditionalPanel( 
        condition="output.saved!=0",
        h4('Saved successfully')
      )
    )
  )
))

Note: conditionalPanel is displayed after actionButton triggers the saving in sever.R

server.R

library(shiny)

shinyServer(function(input, output, session) {

  observeEvent(input$save,{
    SaveRData()
  })

  observeEvent(
    ignoreNULL = TRUE,
    eventExpr = {
      input$directory
    },
    handlerExpr = {
      if (input$directory > 0) {
        # condition prevents handler execution on initial app launch

        path = choose.dir(default = readDirectoryInput(session, 'directory'))
        updateDirectoryInput(session, 'directory', value = path)
      }
    }
  )

  output$directory = renderText({
    readDirectoryInput(session, 'directory')})

    SaveRData <- reactive({
      if(!(is.null(dir) && is.null(input$save) && is.null(input$file_name))){
        dir <- readDirectoryInput(session, 'directory')
        file_name <- paste(input$file_name,".RData", sep="")
        save.image(file = paste(dir,file_name, sep = "\\"))
        }
    })

    output$saved<-reactive({input$save})

    outputOptions(output, 'saved', suspendWhenHidden = FALSE)
  })

As soon as savebutton is pressed, it triggers SaveRData function which basically uses save.image(...) with parameters from input.

Snapshots: 1.UIsnap1-ui

2.output directorysnap2-folder

Upvotes: 0

Related Questions