0

I have been trying to make some code in Shiny that allows multiple files to be uploaded and combined into a single dataframe, but the only way I can figure out to make this work is using a reactive() command. However, I need my dataframe to be subsettable because I have lots of further calculations to do on it, and a reactive dataframe keeps giving me the "object of type 'closure' is not subsettable" error.

Is there any way I can either:

a) Read in multiple files to a static dataframe without using reactive() (ie the same way as I would do it for a single file), or

b) Convert a reactive dataframe to a static one?

I am using the fileInput(...multiple = TRUE) command in the UI.

This is the relevant part of my server code (works for single file upload but not multiple):

server <- function(input, output) {
  
  output$contents <- renderTable({

    req(input$file1)
    
    tryCatch(
      {
        df <- read.csv(input$file1$datapath,
                       header = input$header,
                       sep = input$sep,
                       quote = input$quote)
      },
      error = function(e) {
        # return a safeError if a parsing error occurs
        stop(safeError(e))
      }
    )

    #create a subset of all the rows where pred > threshold
    rows_above <- df[rowSums(df[6] > input$predthr) > 0, ]

    #......my code goes on to do more analysis, subsetting and graphing

    return(rows_above)
    
  })
  
}

I have tried this instead of the read.csv, but it gives me an error if I try any kind of subsetting, and I can't figure out how to convert it to a static dataframe:

df<-reactive({
     rbindlist(lapply(input$file1$datapath, fread),
               use.names = TRUE, fill = TRUE)
   })
  • Whenever I get the "object of type 'closure' is not subsettable" error in Shiny it usually means I've forgotten to reference one of my reactive objects as a function instead of as an object - i.e. using `dat` instead of `dat()` where `dat()` is the thing returned by a reactive. In your case it's also worth checking that `df` is defined somewhere, since `df` is also a base function in R and will return the same error if not found in the environment and subset. – Dubukay Jun 30 '22 at 16:38
  • Also, trying to return a data frame (whether reactive or static) from a `renderPrint` *simply won't work*. You are conflating ingestion and display. They need to be separate. Even if you don't subsequently modify the data frame, your object needs to be reactive: before you read the files in, the data frame doesn't exist and can't be further analysed. After the files havebeen read in, it can be. Use an `observeEvent` to populate a `reactiveVal` (or an element of a `reactiveValues` and the pass the `reactiveVal` to the `renderPrint` and other analysis steps. – Limey Jun 30 '22 at 17:33
  • Do you have any examples of how to do this with the functions you describe? Apologies, I am quite new to RShiny! – Emma Zurgit Jul 10 '22 at 15:46
  • Also, would I be able to subset my dataframe (eg using [] and $ to access elements) with this method? It seems to me that reactive dataframes don't let you access elements, not sure if that would apply to reactiveValues too... – Emma Zurgit Jul 10 '22 at 15:52

1 Answers1

0

I think I have found a solution to my issue. Based on information from this answer: How to load a folder of csv files in shiny, I have done this, which seems to work for loading in multiple files:

  server <- function(input, output) {
  
  output$contents <- renderTable({
    # input$file1 will be NULL initially. After the user selects
    # and uploads a file, head of that data file by default,
    # or all rows if selected, will be shown.
    
    inFile <- input$file1
    if (is.null(inFile)) {
      return(NULL)
    } else {
      df <- inFile %>%
        rowwise() %>%
        do({
          read.csv(.$datapath)
        })
    }

#create a subset of all the rows where pred > threshold
    rows_above <- df[(df[6] > input$predthr) > 0, ]

#......my code goes on to do more analysis, subsetting and graphing

    return(rows_above)
    
  })
  
}

I also had to remove the rowSums from my subsetting line but fortunately that doesn't seem to make any difference with my data.

Thanks for pointing out 'df' is not a great variable name - will bear in mind for future.