Get names of the multiple uploaded files using Shiny's 'fileInput' ?

I have a Shiny app that uses fileInput to take in a file and make several different plots.
I'm trying to modify the app to now intake multiple files, and make the same plots eventually.

I can use multiple=TRUE in my code, but I'm having a hard time of actually getting them back out. Can I put them all into a list and reference them later in the app? I'm especially needing to pay attention to varying numbers of files (user 1 uploads 3 files, user#2 uploads 10 files).

Thank you!

EDIT:

Here's some code I adapted. I wanted to simply input multiple files, put them in a list, and get the names of that list. I think where I'm going wrong is that the elements of the list are not being set to the names of the uploaded CSV files. @FJCC any idea?

library(shiny)
library(data.table)

ui <- fluidPage(
  titlePanel("Multiple file uploads"),
  sidebarLayout(
    sidebarPanel(
      fileInput("csvs",
                label="Upload CSVs here",
                multiple = TRUE)
    ),
    mainPanel(
     textOutput("count")
   
    )
  )
)

server <- function(input, output) {
  mycsvs<-reactive({
   mylist<- list( rbindlist(lapply(input$csvs$datapath, fread),
              use.names = TRUE, fill = TRUE))
  })
  output$count <- renderText(names(mylist))
}

shinyApp(ui = ui, server = server)

Is this the sort of thing you want to do? It throws an error when first started because I didn't bother to make it elegant. If I pick three files, mycsvs() returns a list with three elements, each element being the contents of a selected file, the names of mycsvs() are the names of the files in the browser, not the tmp file names stored in input$csvs$datapath.

library(shiny)
library(data.table)

ui <- fluidPage(
  titlePanel("Multiple file uploads"),
  sidebarLayout(
    sidebarPanel(
      fileInput("csvs",
                label="Upload CSVs here",
                multiple = TRUE)
    ),
    mainPanel(
      textOutput("count"),
      textOutput(("Listnames")),
      tableOutput("FirstDF")
      
    )
  )
)

server <- function(input, output) {
  mycsvs<-reactive({
   # list( rbindlist(lapply(input$csvs$datapath, fread),
  #                           use.names = TRUE, fill = TRUE))
    tmp <- lapply(input$csvs$datapath, fread)
    names(tmp) <- input$csvs$name
    tmp
  
  })
  output$count <- renderText(length(mycsvs()))
  output$Listnames <- renderText(names(mycsvs()))
  output$FirstDF <- renderTable(mycsvs()[[1]])
}

shinyApp(ui = ui, server = server)

1 Like

YES!! The output$Listnames is answering the question, "what are the names of the uploaded files"

But for how to access them, let's say I wanted to plot each uploaded file (all of which happen to be a single column). Won't I need some way to put them in a list? And do something like

for(i in 1:seq_along(mylist)){
plot(mylist[[i]]
}

?

I think maybe this is how I should start (modified your example). But I'm not sure how to make all 3 plots, it can only plot 1 of the uploaded files:

library(shiny)
library(data.table)

ui <- fluidPage(
  titlePanel("Multiple file uploads"),
  sidebarLayout(
    sidebarPanel(
      fileInput("csvs",
                label="Upload CSVs here",
                multiple = TRUE)
    ),
    mainPanel(
      textOutput("count"),
      textOutput(("Listnames")),
      tableOutput("FirstDF"),
      plotOutput("myplot")
      
    )
  )
)

server <- function(input, output) {
  mycsvs<-reactive({
    # list( rbindlist(lapply(input$csvs$datapath, fread),
    #                           use.names = TRUE, fill = TRUE))
    tmp <- lapply(input$csvs$datapath, fread)
    names(tmp) <- input$csvs$name
    tmp
    
  })
  output$count <- renderText(length(mycsvs()))
  output$Listnames <- renderText(names(mycsvs()))
  output$FirstDF <- renderTable(mycsvs()[[1]], rownames = FALSE)
  output$myplot <- renderPlot(
    for(i in 1:seq_along(mycsvs)){
      x <- plot(mycsvs()[[1]])
      x
    }
  )
}

shinyApp(ui = ui, server = server)

I am not sure how to use the base plot() function within shiny to layout a variable number of plots. I expect it can be done. I would use ggplot to make a faceted plot with one plot for every csv file. If your data have only one column, you might need to add a column of x values. This is what I did in the following code. The files are read in with one column and then I use functions from dplyr to add a column that just numbers the rows. Before that step, I used the bind_rows() function to make a single data frame containing all of the data with a column named SourceFile that labels each row with its original file name. The faceted plots can then be labeled with the file names.

library(shiny)
library(data.table)
library(ggplot2)
library(dplyr)
ui <- fluidPage(
  titlePanel("Multiple file uploads"),
  sidebarLayout(
    sidebarPanel(
      fileInput("csvs",
                label="Upload CSVs here",
                multiple = TRUE)
    ),
    mainPanel(
      #textOutput("count"),
      #textOutput(("Listnames")),
      #tableOutput("FirstDF")
      plotOutput("Plot")
      
    )
  )
)

server <- function(input, output) {
  mycsvs<-reactive({
   # list( rbindlist(lapply(input$csvs$datapath, fread),
  #                           use.names = TRUE, fill = TRUE))
    tmp <- lapply(input$csvs$datapath, fread)
    names(tmp) <- input$csvs$name
    bind_rows(tmp, .id = "SourceFile") %>% 
      group_by(SourceFile) %>% 
      mutate(Xval = row_number())
    
    #tmp
  
  })
  #output$count <- renderText(length(mycsvs()))
  #output$Listnames <- renderText(names(mycsvs()))
  #output$FirstDF <- renderTable(mycsvs()[[1]])
  output$Plot <- renderPlot({
    ggplot(mycsvs(), aes(x = Xval, y = Val)) + geom_point() +
      facet_wrap(~SourceFile)
  })
}

shinyApp(ui = ui, server = server)
1 Like

This is really cool.

I think instead of trying to make it on one plot though, I'm trying to make all plots. So if 3 files are uploaded, can I make 3 plots? This is already working with counting the number of input files, and it is also working with displaying the input file names.

I'm pretty sure I just don't know how to right for loops correctly - for example I currently have:

for(i in 1:seq_along(mycsvs)){
      x <- plot(mycsvs()[[i]])
      x

That will only make one plot , the last one that was uploaded. How can I say "plot this same plot but for ALL uploaded files?"

Thanks so much!

I can't come any closer to making a variable number of independent plots than using ggplot's facet_wrap. However, I am no shiny expert and others probably do know how to do that. The problem I see, though I could be wrong, is that each plot would need its own plotOutput function in the UI section. You would have to create those on-the-fly and I do not know how to do that.
I suggest you start a new topic with a title that mentions making a variable number of plots in shiny. That will be more likely to attract the attention of the correct person.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.