Upload a user picked directory in R Shiny - r

I have an R shiny app that requires multiple files (all found within the same folder) to be uploaded. I also know the names of the files to look for.
Is there any way to upload these files other than via fileInput(..., multiple = TRUE)? Ideally, I would have the user upload the whole directory.

You can use the library shinyFiles to let the user pic a folder somewhere on their local disk. Then in the server you can use the user input to load all the files that you need from this folder.
Example
library(shiny)
library(shinyFiles)
### UI
ui <- fluidPage(
shinyDirButton('directory_select', 'Select a directory', title='Select a directory'),
textOutput('directory_name')
)
### Server
server <- function(input, output, session) {
volumes <- getVolumes()
shinyDirChoose(input, 'directory_select', roots=volumes, session=session)
dirname <- reactive({parseDirPath(volumes, input$directory_select)})
## Observe input dir. changes
observe({
if(!is.null(dirname)){
print(dirname())
output$directory_name <- renderText(dirname())
## Load files here
# csv <- read.csv(paste0(dirname(), '/filename1.csv'))
# rdata <- load(paste0(dirname(), '/filename2.Rdata'))
# etc.
}
})
}
shinyApp(ui = ui, server = server)

Related

Shiny method to browse and pass filename

I am trying to build a front end using Shiny to pass some parameters to a markdown document. One parameter I want to pass is a user selected file name, including the path. I would like to use a file open type dialogue box for the user to navigate through directories and select the file. I do not need/want to actually open the file, that happens in the markdown file, I just want to pass the path and file name of the selected file out of the shiny app. I have this set up using fileInput() but of course this opens the file and makes a copy in a temp directory and the associated path is to the temp directory not the original directory. There have been some related questions about this and the only answers are that this is a security issue related to the server-based nature of shiny. Again, I don't want to open the file, just grab the original path and name. Any thoughts on how to achieve this? Here's the code stripped down to just this issue ...
library(shiny)
ui <- fluidPage(
titlePanel("Input"),
mainPanel(
fileInput(inputId = "rtffile", "Choose RTF File", accept = ".rtf", ),
)
server <- function(input, output, session) {
observe({
filename <<- input$rtffile
})
}
shinyApp(ui = ui, server = server)
In general, you can’t get a web browser to give you the path to a file on the
user’s local machine.
However, it’s possible to get a path to a file on the server.
If the server and the local machine happen to be the same, you can use e.g. shinyFiles to
pick a path:
library(shiny)
library(shinyFiles)
ui <- fluidPage(
titlePanel("Input"),
mainPanel(
shinyFilesButton("file", "Choose File", "Choose a file", multiple = FALSE),
verbatimTextOutput("file")
)
)
server <- function(input, output, session) {
roots <- getVolumes()
shinyFileChoose(input, "file", roots = roots)
file <- reactive(parseFilePaths(roots, input$file))
output$file <- renderPrint(file())
}
shinyApp(ui = ui, server = server)

Copying file on upload and paste it to www folder location

I want to upload a file in Shiny and copy it to a WWW folder. My code is uploading file, but it is not copying file to WWW folder location. How can I do this? Am I doing wrong? Thanks.
Following file "ui.R" is also in www folder:
library(shiny)
shinyApp(
ui=shinyUI(bootstrapPage(
fileInput("upload", "Upload", multiple = FALSE)
)),
server=shinyServer(function(input, output, session){
observe({
if (is.null(input$upload)) return()
file.copy(input$upload$datapath, "\\C:\\Users\\'XXX XXX'\\Documents\\R\\win-library\\3.4\\shiny\\www\\")
})
})
)
Believe it's a simple issue with the string mentioned in the output path. I was able to get the code below working without issues.
If I try to upload a file called temp.R using the app, then it is being renamed to 0.R as the complete file name has not been specified in file.copy. Provide the complete file name if you want it to work irrespective of the name in the user's system, e.g file.copy(input$upload$datapath, "C:\\NotBackedUp\\user_upload.R", overwrite = TRUE).
You can retrieve the original name using input$upload$name.
library(shiny)
shinyApp(
ui=shinyUI(bootstrapPage(
fileInput("upload", "Upload", multiple = FALSE)
)),
server=shinyServer(function(input, output, session){
observe({
if (is.null(input$upload)) return()
file.copy(input$upload$datapath,
"C:\\NotBackedUp", overwrite = TRUE)
})
})
)

Choose folder or folder directory inside shiny app

I have a problem using shiny. I want to choose the folder where all the files I want to use in my app are saved either 1) by setting the working directory to that folderpath or 2) by uploading all csv data inside this folder to my app for further processing. for 1) I found the shinyFiles package but it is very very slow -not due to my PC- as well as giving me the error:
Warning: Error in dir.create: invalid 'path' argument
Stack trace (innermost first):
59: dir.create
58: dirCreate
57: observerFunc
2: runApp
1: shinyFilesExample
when I selected a folder and the create folder button becomes clickable and I am putting a name of the new folder into it and clicking on the "+" beneath that panel. Anybody knows why? Despite that this method works but is very very slow. code below:
library(shiny)
library(shinyFiles)
ui<-fluidPage(sidebarLayout(
sidebarPanel(
shinyDirButton("dir", "Chose directory", "Upload")
),
mainPanel(
h4("output$dir"),
verbatimTextOutput("dir"), br()
)
))
server <- function(input,output,session){
# dir
shinyDirChoose(input, 'dir', roots = getVolumes())
dir <- reactive(input$dir)
output$dir <- renderPrint(dir())
}
shinyApp(ui = ui, server = server)
Is there another option? Maybe to upload all csv data via the fileInput function? Or another way? It should not work only locally but on a server so choose.dir might be not the right way.
Many thanks
so far, shinyfiles is the only way to input folders, as far as I know. It cannot work on a server, because browsers are not allowed to select folders (for security reasons).
The zipping way might be the only way to go if you want it to be working on a server (but I have no clue if it can actually be done)
The funktion getwd() gets your current working directory.
server <- function(input,output,session){
# dir
shinyDirChoose(input, 'dir', roots = c(name=getwd()))
dir <- reactive(input$dir)
output$dir <- renderPrint(dir())
}
If there are not too many files in your directory, you can just use fileInput with multiple=T. You can also filter them by extension.
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
# ?fileInput
fileInput("file1", "Choose HTML File(s)", multiple=T, accept = ".html")
),
mainPanel(
verbatimTextOutput("out.print")
)
)
)
server <- function(input, output) {
output$out.print <- renderPrint({
file <- input$file1
ext <- tools::file_ext(file$datapath)
req(file)
validate(need(ext == "html", "Please upload html file(s)"))
file
})
}
shinyApp(ui, server)
However, if you have too many files, it seems like library(shinyFiles) remains to be your option

shinyFiles not working with modules

I'm developing a rather large shiny app and used the methods from this talk on shinydevcon to modularize it.
Now I was trying to use the package shinyFiles to get a "Save as" type dialog:
library(shiny)
library(shinyFiles)
# Dummy module for MCVE
saveModule <- function(input, output, session) {
# Taken straight from shinyFilesExample()
volumes <- getVolumes()
shinyFileSave(input, NS("test")("save"), roots = volumes, session = session)
}
server <- function(input, output, session) {
callModule(saveModule, "test")
}
ui <- shinyUI(fluidPage(
# Taken straight from shinyFilesExample()
shinySaveButton(NS("test")("save"), 'Save file', 'Save file as...', filetype=list(text='txt', picture=c('jpeg', 'jpg'))))
)
runGadget(app = ui, server = server, viewer = dialogViewer(title = "test"))
This doesn't work correctly when trying to navigate folders or switch roots.
When pulling the code out of the callModule, it does work, but as I said, the actual use case has a rather large app and I don't want to clutter the app.R with code from a single module.
Is there any way to get shinyFiles to work correctly in a callModule context? Or some other viable work-around?
For reference, here is a working server:
server <- function(input, output, session) {
volumes <- getVolumes()
shinyFileSave(input, NS("test")("save"), roots = volumes, session = session)
}
with ui and runGadget as above.

Storing data uploaded by a user in Shiny app

I am building a Shiny app (R) which allows users to upload their own data (assuming standard file format). The user interface is similar to the example given here. I would like to be able to store that data permanently after user uploads it, so that other users can have access to it as well.
For example, user1 uploads file1.txt and the app allows to analyze this file.
User2 uploads file2.txt. Now any future user of the app will have access to the files uploaded by users 1 and 2 as well as be able to upload more files, which become accessible by other users. Is there a way to do it in Shiny?
You need to copy the uploaded file from the temp directory ($datapath) to a permanent location (i.e. another directory). Then you can use dir() to get a list of user files.
If you need a permanent storage look at http://deanattali.com/blog/shiny-persistent-data-storage/
For local storage, see example below.
library(shiny)
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Select file to upload' )
),
mainPanel(
h4('List of uploaded files:')
,verbatimTextOutput('fileList')
)
))
)
server <- shinyServer(function(input, output) {
observe({
if (is.null(input$file1) ) { return(NULL) }
file.copy(from = input$file1$datapath, to = paste0('userFile_',input$file1$name ) )
})
output$fileList <- renderText({
input$file1
dir(pattern = 'userFile_')
})
})
shinyApp(ui, server)

Resources