Equivalent of R base::file.choose() in Shiny

I am creating a Shiny app for a R package of mine.

In my package, I read in a FASTA sequence alignment file using the ape package via

seqs <- ape::read.dna(file = file.choose(), format = "fasta")

This works fine within my app locally since file.choose() is interactive. However, the above code fails on shiny apps.io.

It was suggested to me via Stack Overflow to write a new file.choose() function that incorporates Shiny's syntax, but I haven't a clue where to begin with this, since I am a Shiny novice. See: Popup window not appearing in R Shiny app - Stack Overflow for more details

Does anyone know where to start with coding up such a function? Perhaps someone has already implemented a working version and is willing to share?

Note: I don't want to have to use shiny::fileInput() as this would require me to change my package code, which runs in the background of my app,

Perhaps if Shiny guru Dean Attali is on the forum, he can weigh in?

Just as it was done in the SO post you linked, I would suggest using shinyFiles if you want your users to choose files from (part of) the server file system.

Another option could be to map those file paths into selectInput choices. Here is an example:

library(shiny)

my_files <- vector(mode = "character", length = 10)
for (i in seq_along(my_files)){
  my_files[i] <- tempfile(fileext = ".txt")
}

names(my_files) <- basename(my_files)

ui <- fluidPage(
  selectizeInput("choose_file", "Please choose a file:", choices = my_files),
  textOutput("selected_file")
)

server <- function(input, output, session) {
  output$selected_file <- renderText(paste("Selected file:", input$choose_file))
}

shinyApp(ui, server)

It seems that your second solution merely allows a user to select a file from a dropdown menu. Running shinyFilesExample() instead lets a user press a button that opens a popup window for file selection. To me, these are two different tasks.

I don't explicitly know what a users file path would be, nor what is contained there. Thus, I believe shinyFiles is the correct approach.

Please correct me if I'm missing something.

Absolutely right – both approaches are aiming at a different task. Unfortunately, you didn’t provide us with the needed details regarding your use case. Otherwise, I would not have created the selectizeInput example.

When using library(shinyFiles) know it only allows the user to browse the file system of the shiny host. fileInput is more flexible.

Thanks.

The last point you raise regarding shinyFiles is exactly the issue I'm wanting to get around.

The end user would ideally like to analyze their own data available on their own file system, not Shiny's. This functionality is provided by fileInput, but the issue is that my app basically runs a package through a server.

So, I'm thinking my problem could be solved (not ideally, however) using part of the other solution you provide. The user would need to ensure their file is contained within a temporary directory and then be able to access it to be read into the app. Something like

seqsfile <- tempfile(fileext = ".fas")
ape::read.dna(file = seqsfile, format = "fasta")

I haven't tested it out yet, but what do you think?

How is that an issue regarding fileInput? Can you please elaborate on this?

If you want to deploy your app on shinyapps.io (or allow remote shiny sessions in general) I'd use fileInput.

My phrasing may have not been so clear.

Please allow me to elaborate.

Running a package though the Shiny server should not be an issue in general, nor should fileInputbe problematic.

I think It's just that the solution in my case would entail altering my R package code.

The app runs via the CRAN version of my package, which contains the line

seqs <- ape::read.dna(file = file.choose(), format = "fasta").

The above line of course does not work on the server, but does work locally.

I do intend to include a launchApp() function through my package for users to run the app locally. However, a fully online version is also nice to have.

I could have a shiny = FALSE argument within my package's main function and then simply set this to TRUE for the app. Something like

if (shiny == TRUE) {
    ...
} else {
    seqs <- ape::read.dna(file = file.choose(), format = "fasta")
}

I'll continue to investigate.

I think that's the right way to go. However, I'd check for an interactive R session via interactive() because this is the required condition for file.choose() to work:

if (interactive()) {
seqs <- ape::read.dna(file = file.choose(), format = "fasta")
} else {
seqs <- ape::read.dna(file = some_path, format = "fasta")
}

Thanks again.

What do you think some_path ought to be? I think I'd need yet another function argument allowing a user to indicate their file path.

Yes some_path should be a path provided by the user. Either passed in their custom script or in shiny selected via fileInput.

This topic was automatically closed 54 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.