Interactive Directory Input in Shiny App (R)

Interactive directory input in Shiny app (R)

This is a working example based on using the "webkitdirectory" attribute. At the moment the attribute is supported by Chrome, Opera and Safari (mobile and desktop) and it should be supported in Firefox 49 to be released in September.
More about this here. It work with subdirectories also.

It requires using the tags keyword in ui.R. I have tested it by uploading three csv files each contaning three numbers separeted by a coma. Tested locally and on shinyapps.io with Chrome and Opera. This is the code:

ui.R

    library(shiny)
library(DT)

shinyUI(tagList(fluidPage(theme = "bootstrap.css",
includeScript("./www/text.js"),
titlePanel("Folder content upload"),

fluidRow(
column(4,
wellPanel(
tags$div(class="form-group shiny-input-container",
tags$div(tags$label("File input")),
tags$div(tags$label("Choose folder", class="btn btn-primary",
tags$input(id = "fileIn", webkitdirectory = TRUE, type = "file", style="display: none;", onchange="pressed()"))),
tags$label("No folder choosen", id = "noFile"),
tags$div(id="fileIn_progress", class="progress progress-striped active shiny-file-input-progress",
tags$div(class="progress-bar")
)
),
verbatimTextOutput("results")
)
),
column(8,
tabsetPanel(
tabPanel("Files table", dataTableOutput("tbl")),
tabPanel("Files list", dataTableOutput("tbl2"))
)
)
)
),
HTML("<script type='text/javascript' src='getFolders.js'></script>")
)

)

server.R

    library(shiny)
library(ggplot2)
library(DT)

shinyServer(function(input, output, session) {
df <- reactive({
inFiles <- input$fileIn
df <- data.frame()
if (is.null(inFiles))
return(NULL)
for (i in seq_along(inFiles$datapath)) {
tmp <- read.csv(inFiles$datapath[i], header = FALSE)
df <- rbind(df, tmp)
}
df

})
output$tbl <- DT::renderDataTable(
df()
)
output$tbl2 <- DT::renderDataTable(
input$fileIn
)
output$results = renderPrint({
input$mydata
})

})

text.js

window.pressed = function(){
var a = document.getElementById('fileIn');
if(a.value === "")
{
noFile.innerHTML = "No folder choosen";
}
else
{
noFile.innerHTML = "";
}
};

getFolders.js

     document.getElementById("fileIn").addEventListener("change", function(e) {

let files = e.target.files;
var arr = new Array(files.length*2);
for (let i=0; i<files.length; i++) {

//console.log(files[i].webkitRelativePath);
//console.log(files[i].name);
arr[i] = files[i].webkitRelativePath;
arr[i+files.length] = files[i].name;

}

Shiny.onInputChange("mydata", arr);

});

Let me know if this helps.

How can be created an independent directory for each user in Shiny app?

This is the answer that I get in RStudio community and worked for me:

By @pieterjanvc from RStudio community:

Setting the working directory is likely not going to work like that in Shiny. I suggest you generate a folder based off the user's session token, which is generated when a user connects to a Shiny app and located in the session variable.

library(shiny)

ui <- fluidPage(

)

server <- function(input, output, session) {

dir.create(session$token)
file.create(paste0(session$token, "/userFile.txt"))

}

shinyApp(ui, server)

Once you created the directory, you can save any file in that one using again the token which is the name of the base folder for that user. You should remember to erase the folder after the task finished, or you will have a lot of folders soon.

Interactive file input and reactive reading in shinyapp

I came to this solution. Tested modifying the /folder/folder.csv file externally.

library(shiny)
library(shinyFiles)
path1<-"~"
server<- function(input, output, session) {
shinyDirChoose(input, 'dir', roots = c(home = path1) )
reacdir <- reactive(input$dir)
output$dirtext <- renderPrint(c(path(),current() ) )

path <- reactive({
home <- normalizePath(path1)
file.path(home, paste(unlist(reacdir()$path[-1]), collapse = .Platform$file.sep))
})

current<-reactive({
a<-sub('.*\\/', '', path() )
b<-paste("current subdir:",a)
})
reac<-reactiveValues()
observe({
if(file.exists(paste0(path(),"/",sub('.*\\/', '', path() ),".csv")) ){
fileReaderData<-reactiveFileReader(1000, session, paste0(path(),"/",sub('.*\\/', '', path() ),".csv"), read.csv, stringsAsFactors=FALSE)
reac$df<-fileReaderData()
output$fileReaderText <- renderText({
text <- reac$df
length(text) <- 14
text[is.na(text)] <- ""
paste(text, collapse = '\n')
})
}
else{"index file does not exist, create with button 2."}
}
)
}
ui<-fluidPage(
titlePanel("interactive selection of file and reactive reading"),
fluidRow(
column(12,
shinyDirButton("dir", "1. Choose directory", "Upload")
,br(),br(),
p("shinyapp")
)
),
fluidRow(
column(6, wellPanel(
verbatimTextOutput("fileReaderText")
))
)
)

shinyApp(ui, server)

How to select a directory and output the selected directory in R Shiny

You could consider the shinyFiles package.

On server side you use
shinyDirChoose(input, id = 'folder', ...) and then can access the chosen folder via input$folder.

Reproducible example:

library(shiny)
library(shinyFiles)
shinyApp(
shinyUI(bootstrapPage(
shinyDirButton('folder', 'Select a folder', 'Please select a folder', FALSE)
)),

shinyServer(function(input, output) {
shinyDirChoose(input, 'folder', roots=c(wd='.'), filetypes=c('', 'txt'))

observe({
print(input$folder)
})
})
)

Upload a user picked directory in R Shiny

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 Topics



Leave a reply



Submit