0
votes

I have a small shiny program below which reads in an .Rdata file using Shiny. The code below works as expected, but there is behavior that I desire that I cannot quite figure out how to implement from within Shiny.

To frame the first problem, suppose I have a file called tmp.Rdata and when that .Rdata is loaded into the R workspace it contains a data frame called "foo". My objective is to load the .Rdata using shiny and then access the data frame within it (foo) and do R things to it.

For example, if I was working within R proper, my actions would be something like:

> load('tmp.Rdata')
> str(foo)

And supposing foo is a data frame with K columns, the result of str(foo) would show the typical behavior of str() on the object.

When implementing the code below, the Shiny program runs and I can see the .Rdata loads successfully and that "foo" is in the workspace. However, the resulting action from str() in this instance is to show that the object foo is in the workspace, not the structure of the object foo itself, which is the behavior I want to implement.

chr "foo"

Now, if I know ahead of time that the .Rdata will always have in it a frame called "foo" I could hard code this into the server.R code and all is well. But, the more challenging problem is that my users will save an .Rdata file that contains within it a data frame with an unknown name.

I have searched SO and found similar questions, but not exactly tackling the same problem as far as I can tell, such as the one at the link below

Loading User input .Rdata on Shiny App

Thank you for any suggestions.

ui.R

shinyUI(fluidPage(
  titlePanel("Uploading Files"),
  sidebarLayout(
    sidebarPanel(
     h4("Uploading Files"),
     fileInput('f1', 'Choose RData File', accept=c('.RData, .Rds'))
    ),
    mainPanel(
     h4("Data Structure"),
     verbatimTextOutput("datastr")
    )
  )
))

server.R

shinyServer(function(input, output) {
dataInput <- reactive({
  sessionEnvir <- sys.frame()
    if (!is.null(input$f1)) load(input$f1$datapath, sessionEnvir)
  })
  output$datastr <- renderPrint({
  ff <- dataInput()
    if (is.null(dataInput()))  return()  else str(ff)
  })
})
1
Try using get() to retrieve objects from string literals (as dataInput() may be returning a character value): str(get(ff)). - Parfait
If you are trying to find the name of the dataframe in the .RData you could compare the output of ls() before and after loading (this assumes there is only one dataframe in the data) - NicE
You could improve on @NicE's suggestion by creating an environment, loading the R DATA file into that environmeNT. And then using ls to get the contents of the environment. Then you can use get to retrieve the data frame from the environment. - Benjamin
Extremely helpful, thank you. - doran
When you have a solution you like, I'd be interested in seeing how you implemented it. And hearing how satisfied you are with the approach. It might be something useful for me down the road. - Benjamin

1 Answers

2
votes

You could use eval() and parse(). The updated server.R code below shows how:

shinyServer(function(input, output) {

  dataInput <- reactive({

    sessionEnvir <- sys.frame()

    if (!is.null(input$f1)) eval(parse(text = load(input$f1$datapath, sessionEnvir)))

  })

  output$datastr <- renderPrint({

    ff <- dataInput()
    if (is.null(dataInput()))  return()  else str(ff)

  })
})

This will only work for RData files. Your ui.R appears to show a desire to accept Rds files too. You'll need to load them with readRDS. The good news is that readRDS will work just fine without eval() and parse(). Perhaps you could add radio buttons to the UI for the user to choose the file type.