Storing data uploaded by a user in Shiny app - r

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)

Related

Can you exclude certain files from being uploaded in an R shiny app?

I am working on a shiny app where the user uploads a number of csv files based on which some output is created. The files to upload are produced by an external application and all lie in the same folder. I want the user to be able to select all files in the folder for upload and I am currently using
shiny::fileInput() with the option multiple = TRUE in the shiny App.
The problem I have is that the output folder contains a file that can be quite large and that is not required for the analysis in the app. The app works fine if the user just deselects that file in the upload menu. But I was wondering if there is a way that I can tell the app to ignore a certain file (based on the file name), so that even if the user selects all files in the folder for upload, the large file is not uploaded while all the other selected files still are.
I know that you can set a maximum file size in the options (shiny.maxRequestSize) but this does not seem to solve my problem, as the upload then ends with an error if the large file is selected.
Here is a minimal example of the app:
library(shiny)
options(shiny.maxRequestSize = 30*1024^2)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
# Upload menu is created here:
fileInput(
inputId = "upload",
label = "Upload Files",
buttonLabel = "Select files...",
multiple = TRUE
)
),
mainPanel(
tableOutput(outputId = "files")
)
)
)
server <- function(input, output, session) {
output$files <- renderTable(
input$upload[, c("name", "size")]
)
}
shinyApp(ui, server)

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)

How can I store and retrieve files uploaded with fileInput after resetting it Shiny

I would like to create a storage to store and retrieve uploaded files even after fileInput is reset.
Basically every time user uploads a file with fileInput, in the future he is forced to click on doneUpload button which resets the fileInput text area and puts his file in the storage (no alternatives please).
At this point, user can go back and upload another file which will be put in the storage too.
From my point of view, I have all uploaded files which I can easily retrieve and manipulate.
In other words, my question could be translated to:
how can I reset fileInput text area without resetting uploaded files?
I have tried creating a reactive value to store uploaded files, however it does not work as I expected.
Here I show you an example to simplify my situation.
library(shiny)
ui<-fluidPage(
uiOutput("uploadFile"),
actionButton("doneUpload","Done"),
tableOutput("exampleTest"))
server<-function(input, output){
output$uploadFile<-renderUI({
fileInput("uploadFile", "Upload your file", accept = c(".csv"),placeholder="No files selected")
})
observeEvent(input$doneUpload,{
output$uploadFile<-renderUI({
fileInput("uploadFile", "Upload your file", accept = c(".csv"),placeholder="No files selected")
})
})
reactiveFileUploaded<-reactiveValues(fileUploaded=NULL)
observe({
req(input$uploadFile)
reactiveFileUploaded$fileUploaded<-c(reactiveFileUploaded$fileUploaded,input$uploadFile$datapath)
})
#Test to verify if the storage has been created.
#Supposing two files have been uploaded, I retrieve the first one.
output$exampleTest<-renderTable({
read.csv2(reactiveFileUploaded$fileUploaded[1])
})
}
shinyApp(ui=ui,server=server)
Here is a much simpler approach for what you need - Just set multiple = TRUE in fileInput() so that it can accept multiple files at the same time. They can all be read and stored in a reactive in one go using lapply.
library(shiny)
ui <- fluidPage(
fileInput("files", "Upload", multiple = TRUE),
actionButton("done", "Done Upload"),
verbatimTextOutput("test")
)
server <- function(input, output) {
all_data <- eventReactive(input$done, { # stores data in all files as a list of dataframes
req(input$files)
setNames(lapply(input$files$datapath, read.csv), sapply(input$files$name, basename))
})
output$test <- renderPrint({
# all_data()[[1]] # access first file; others can be accessed the same way
lapply(all_data(), head) # shows first 6 rows of all files with their names
})
}
shinyApp(ui, server)
Quite Simple, just read the file before clearing the input, after the User has confirmed the Input.
Currently you are reading (and saving) the file the moment the User has selected it, no matter if he wants to upload it or not. Also it seems like you are somehow triggering a loop after selecting a file constantly adding the file to the reactive value.
Also with the datapath you are saving only the filepath not the filecontent, and the filepath also directs to the temp folder so I would recommend changing that routine as well.
But for the most basic functionalities you described the following code should get the job done. (I also added a simple check for content in the filesUploaded variable, so that the error message doesn't appear on start up)
library(shiny)
ui<-fluidPage(
uiOutput("uploadFile"),
actionButton("doneUpload","Done"),
tableOutput("exampleTest"))
server<-function(input, output){
output$uploadFile<-renderUI({
fileInput("uploadFile", "Upload your file", accept = c(".csv"),placeholder="No files selected")
})
reactiveFileUploaded<-reactiveValues(fileUploaded=c())
observeEvent(input$doneUpload,{
req(input$uploadFile)
reactiveFileUploaded$fileUploaded<-c(reactiveFileUploaded$fileUploaded ,input$uploadFile$datapath)
output$uploadFile<-renderUI({
fileInput("uploadFile", "Upload your file", accept = c(".csv"),placeholder="No files selected")
})
})
#Test to verify if the storage has been created.
#Supposing two files have been uploaded, I retrieve the first one.
output$exampleTest<-renderTable({
if(length(reactiveFileUploaded$fileUploaded)>1)
read.csv2(reactiveFileUploaded$fileUploaded[1])
})
}
shinyApp(ui=ui,server=server)

Upload a user picked directory in R Shiny

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)

Read multiple files in ShinyR and select the required files to read

I haven't found this question anywhere.
I have to read all the files present in a folder and to display them in Shiny application file upload screen. Here, user will be allowed to select one or more than one files by check-box and those files are to be processed.
Is there any example script of sample script relevant to above posted in github or else where?
Dummy example (copy / paste and execute):
This example allows a user to read files in a folder and list them in a selectizeInput.. You can read the files and process in the way you desire.. I know there're no checkboxs but you can use other input but selectizeInput (was easier for me).
library(shiny)
ui <- fluidPage(
selectizeInput(inputId = 'select_input', label = 'Choose your files...', choices = '*', multiple = TRUE),
verbatimTextOutput('debug')
)
server <- function(input, output, session) {
observe({
files <- list.files()
updateSelectizeInput(session = session, inputId = 'select_input', choices = files)
})
output$debug <- renderPrint({input$select_input})
}
shinyApp(ui, server)

Resources