I need to display selected folder for Shiny users, and I asked here how to do this (Display selected folder path in Shiny). It works but now I can't figure out how to show the default folder (for example, current directory) before the selection was made.
library(shiny)
library(shinyFiles)
ui <- fluidPage( # Application title
mainPanel(
shinyDirButton("dir", "Input directory", "Upload"),
verbatimTextOutput("dir", placeholder = TRUE)
))
server <- function(input, output) {
shinyDirChoose(
input,
'dir',
roots = c(home = '~'),
filetypes = c('', 'txt', 'bigWig', "tsv", "csv", "bw")
)
dir <- reactive(input$dir)
output$dir <- renderText({
parseDirPath(c(home = '~'), dir())
})
## change smth here... if output$dir is null, display getwd() but it doesn't work
observeEvent(ignoreNULL = TRUE,
eventExpr = {
input$dir
},
handlerExpr = {
home <- normalizePath("~")
datapath <<-
file.path(home, paste(unlist(dir()$path[-1]), collapse = .Platform$file.sep))
})
}
# Run the application
shinyApp(ui = ui, server = server)
I can think only of a conditional panel displaying some text if the folder wasn't selected. But I guess there should a better way to do this. Thank you!
Concerning "beyond" displaying you could save the datapath variable in a reactiveValue and set the working directory as the default:
global <- reactiveValues(datapath = getwd())
And the app:
library(shiny)
library(shinyFiles)
ui <- fluidPage( # Application title
mainPanel(
shinyDirButton("dir", "Input directory", "Upload"),
verbatimTextOutput("dir", placeholder = TRUE)
))
server <- function(input, output) {
shinyDirChoose(
input,
'dir',
roots = c(home = '~'),
filetypes = c('', 'txt', 'bigWig', "tsv", "csv", "bw")
)
global <- reactiveValues(datapath = getwd())
dir <- reactive(input$dir)
output$dir <- renderText({
global$datapath
})
observeEvent(ignoreNULL = TRUE,
eventExpr = {
input$dir
},
handlerExpr = {
home <- normalizePath("~")
global$datapath <-
file.path(home, paste(unlist(dir()$path[-1]), collapse = .Platform$file.sep))
})
}
# Run the application
shinyApp(ui = ui, server = server)
Related
I'm trying to write a small shiny app where the user can select multiple folders through a button. The number of folders selected varies according to the needs of the user. The selection of one folder works. If I set "multiple = TRUE", then also only one folder is selected. Does anyone have an idea how I can select multiple folders with a single button?
Here is my code:
library(shiny)
library(shinydashboard)
library(shinyFiles)
library(shinyWidgets)
ui <- fluidPage(
shinyDirButton("preinfolder", "Choose a folder" ,
title = "Please select a folder:",
buttonType = "default", class = NULL,
icon = icon("folder", lib = "font-awesome"), multiple = TRUE),
textOutput("prein_txt_file")
)
server <- function(input, output, session) {
volumes = getVolumes()()
observe({
shinyDirChoose(input, "preinfolder", roots = volumes, session = session)
if(!is.null(input$preinfolder)){
# browser()
preinfolder_selected<-parseDirPath(volumes, input$preinfolder)
output$prein_txt_file <- renderText(preinfolder_selected)
}})
}
shinyApp(ui, server)
Thanks for any idea
I am still trying to solve the problem. I want a list of selected folders.
For my previous solution, I can select multiple folders but only from one parent folder.
library(shiny)
library(shinydashboard)
library(shinyFiles)
library(shinyWidgets)
ui <- fluidPage(
shinyDirButton("preinfolder", "Choose a folder" ,
title = "Please select a folder:",
buttonType = "default", class = NULL,
icon = icon("folder", lib = "font-awesome"), multiple = TRUE),
uiOutput(outputId = "sel_subfolder"),
textOutput("prein_txt_file")
)
server <- function(input, output, session){
volumes = getVolumes()()
observe({
shinyDirChoose(input, "preinfolder", roots = volumes, session = session)
if(!is.null(input$preinfolder)){
# browser()
preinfolder_selected<-parseDirPath(volumes, input$preinfolder)
output$prein_txt_file <- renderText(preinfolder_selected)
}})
df <- reactive({
if(is.null(input$preinfolder)) {
return(NULL)
} else {
fol <- parseDirPath(volumes, input$preinfolder)
return(fol)
}
})
output$sel_subfolder <- renderUI({
if(is.null(df())) {
return(NULL)
} else if(!is.null(df())) {
return(tags$div(align = "left",
class = "multicol",
checkboxGroupInput(inputId = "sel_subfolder",
label = "Select subfolder",
choices = unlist(list.files(parseDirPath(volumes, input$preinfolder))))))
}
})
}
shinyApp(ui, server)
I am still looking for a solution how to create a list of multiple folders with one input button.
This is the solution I found (a bit convoluted but it works).
You basically pass the selected folder to a updateCheckboxGroupInput function that appends the folder to a list of previously chosen ones
library(shiny)
library(shinyFiles)
ui <- fluidPage(
titlePanel("Test"),
sidebarLayout(
sidebarPanel(
shinyDirButton('fld','Choose...','Choose a folder'),
actionButton("submitbutton", "Add folder", class = "btn btn-primary"),
checkboxGroupInput('chosenfolders','Chosen folders...')
),
mainPanel(
verbatimTextOutput("selected")
)
)
)
server <- function(input, output, session) {
volumes <- c(Home = fs::path_home(), "R Installation" = R.home(), getVolumes()())
shinyDirChoose(input, 'fld', session=session,
root=volumes, filetypes=c('txt'))
datasetInput <- reactive({
inputfolders <- c(input$chosenfolders,
parseDirPath(volumes, input$fld))
updateCheckboxGroupInput(session, 'chosenfolders',
choices = inputfolders,
selected = inputfolders)
print(list('Input folders' = inputfolders))
})
output$selected <- renderPrint({
if (input$submitbutton>0) {
isolate(datasetInput())
} else {
return("Server is ready for calculation.")
}
})
}
shinyApp(ui = ui, server = server)
The code below works if the user chooses several images. How can I implement this with shinyDirChoose, so that the user only chooses the folder where the images are located.
Problem: I don't know how to get the local datapath which is stored in the files() object. This path is needed for rendering the images.
Couldn't find any good answers in the web so far.
library(shiny)
ui <- shinyUI(fluidPage(
tags$script('
$(document).on("keydown", function (e) {
Shiny.onInputChange("rightCursor", [e.which,e.timeStamp]);
});
'),
sidebarLayout(
sidebarPanel(
fileInput(inputId = 'files',
label = 'Select an image or several images',
multiple = TRUE,
accept=c('image/png', 'image/jpeg'))
),
mainPanel(
uiOutput('images'),
tableOutput('files')
)
)
))
server <- shinyServer(function(input, output) {
rv <- reactiveValues(page = 1)
output$files <- renderTable(input$files)
files <- reactive({
files <- input$files
files$datapath <- gsub("\\\\", "/", files$datapath)
files
})
output$images <- renderUI({
if(is.null(input$files)) return(NULL)
imagename = paste0("image", rv$page)
image_output <- imageOutput(imagename)
})
observe({
if(is.null(input$files)) return(NULL)
for (i in 1:nrow(files()))
{
print(i)
local({
my_i <- i
imagename = paste0("image", my_i)
output[[imagename]] <-
renderImage({
list(src = files()$datapath[my_i], width = 400, height = 400,
alt = "Image failed to render")
}, deleteFile = FALSE)
})
}
})
navPage <- function(direction) {
rv$page <- rv$page + direction
}
observeEvent(input$rightCursor,{
navPage(1)
print(rv$page)
})
})
shinyApp(ui=ui,server=server)
The user only chooses the folder where the images are located, instead of one or several files.
Here is a way.
library(shiny)
library(shinyFiles)
ui <- fluidPage(
tags$head(
tags$script('
$(document).on("keydown", function (e) {
Shiny.onInputChange("rightCursor", [e.which,e.timeStamp]);
});
')
),
mainPanel(
shinyDirButton("dir", "Input directory", "Upload"),
verbatimTextOutput("dir", placeholder = TRUE),
uiOutput('images')
))
server <- function(input, output) {
shinyDirChoose(
input, "dir", roots = c(home = "~"), filetypes = c("png", "jpg")
)
folder <- reactiveVal()
output$dir <- renderText({
folder()
})
observeEvent(input$dir, {
if (!"path" %in% names(input$dir)) return()
home <- normalizePath("~")
folder(
file.path(
home,
paste(unlist(input$dir$path[-1]), collapse = .Platform$file.sep)
)
)
})
files <- eventReactive(folder(), {
list.files(folder(), full.names = TRUE)
})
page <- reactiveVal(1)
output$images <- renderUI({
req(files())
imagename = paste0("image", page())
imageOutput(imagename)
})
observeEvent(files(), {
for (i in 1:length(files()))
{
print(i)
local({
my_i <- i
imagename = paste0("image", my_i)
output[[imagename]] <-
renderImage({
list(src = files()[my_i], width = 400, height = 400,
alt = "Image failed to render")
}, deleteFile = FALSE)
})
}
})
observeEvent(input$rightCursor,{
page(page()+1)
})
}
# Run the application
shinyApp(ui = ui, server = server)
I would like the user to be able to choose a folder (Ill retrieve the path for this later).
At the moment this works for selection of a file but not a folder. I cant explain why. And the directory does have files in it (tested on windows and mac).
Any ideas?
library(shiny)
library(shinyFiles)
ui <- fluidPage(
shinyFilesButton("Btn_GetFile", "Choose a file" ,
title = "Please select a file:", multiple = FALSE,
buttonType = "default", class = NULL),
shinyDirButton('folder', 'Folder select', 'Please select a folder', FALSE),
textOutput("txt_file")
)
server <- function(input,output,session){
volumes = getVolumes()
observe({
shinyFileChoose(input, "Btn_GetFile", roots=volumes, session = session)
if(!is.null(input$Btn_GetFile)){
# browser()
file_selected<-parseFilePaths(volumes, input$Btn_GetFile)
output$txt_file <- renderText(as.character(file_selected$datapath))
}
})
observe({
if(!is.null(input$Btn_Folder)){
# browser()
shinyDirChoose(input, 'folder', roots=volumes)
dir <- reactive(input$folder)
output$dir <- renderText(as.character(dir()))
}
})
}
shinyApp(ui = ui, server = server)
That's because you wrote Btn_Folder instead of folder here:
observe({
if(!is.null(input$Btn_Folder)){
shinyDirChoose(input, 'folder', roots=volumes)
dir <- reactive(input$folder)
output$dir <- renderText(as.character(dir()))
}
})
Replace with:
observe({
if(!is.null(input$folder)){
shinyDirChoose(input, 'folder', roots=volumes)
dir <- reactive(input$folder)
output$dir <- renderText(as.character(dir()))
}
})
As a side note, you don't need to define this reactive conductor inside the observer, simply do:
observe({
if(!is.null(input$folder)){
shinyDirChoose(input, 'folder', roots=volumes)
output$dir <- renderText(as.character(input$folder))
}
})
I want my Shiny app to allow user specify a path to a folder (locally) and display the selected path. The following code works but I can't figure out how to hide "character(0)" in verbatimTextOutput until the folder was selected. I tried conditional panel (see commented out in my code) but can't figure out what to use as a condition here (because shinyDirButton is not a standard action button...). Thank you!
library(shiny)
library(shinyFiles)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
mainPanel(
shinyDirButton("dir", "Input directory", "Upload"),
#conditionalPanel(
#condition = "???",
verbatimTextOutput('dir')
#)
)
)
server <- function(input, output) {
shinyDirChoose(input, 'dir', roots = c(home = '~'), filetypes = c('', 'txt','bigWig',"tsv","csv","bw"))
dir <- reactive(input$dir)
output$dir <- renderPrint({parseDirPath(c(home = '~'), dir())})
observeEvent(
ignoreNULL = TRUE,
eventExpr = {
input$dir
},
handlerExpr = {
home <- normalizePath("~")
datapath <<- file.path(home, paste(unlist(dir()$path[-1]), collapse = .Platform$file.sep))
}
)
}
# Run the application
shinyApp(ui = ui, server = server)
The closest question I was able to find is this but it doesn't solve my problem: R conditionalPanel reacts to output
In the server function, use renderText instead of renderPrint:
library(shiny)
library(shinyFiles)
# Define UI for application that draws a histogram
ui <- fluidPage( # Application title
mainPanel(
shinyDirButton("dir", "Input directory", "Upload"),
verbatimTextOutput("dir", placeholder = TRUE) # added a placeholder
))
server <- function(input, output) {
shinyDirChoose(
input,
'dir',
roots = c(home = '~'),
filetypes = c('', 'txt', 'bigWig', "tsv", "csv", "bw")
)
dir <- reactive(input$dir)
output$dir <- renderText({ # use renderText instead of renderPrint
parseDirPath(c(home = '~'), dir())
})
observeEvent(ignoreNULL = TRUE,
eventExpr = {
input$dir
},
handlerExpr = {
home <- normalizePath("~")
datapath <<-
file.path(home, paste(unlist(dir()$path[-1]), collapse = .Platform$file.sep))
})
}
# Run the application
shinyApp(ui = ui, server = server)
I saved the path of a user-defined folder with shinyDirChoose. Now I want to upload files from that user's folder, but I cannot figure out how to do it.
1) All on the server end?
2) Feeding the file paths to fileInput somehow?
This is how I construct the file paths for the three files that should be uploaded.
### ui end, to browse to desired folder
ui = fluidPage(shinyDirButton('directory', 'Folder select', 'Please select a folder'))
### extracting the folder path
server = function(input, output, session) {
volumes <- getVolumes()
shinyDirChoose(input, 'directory', roots=volumes, session=session)
path1 <- reactive({
return(print(parseDirPath(volumes, input$directory)))
})
### constructing the 3 file paths
datpat <- renderText({
req(nchar(path1())>0)
datpat <- paste0(path1(),"/data.csv")
})
vispat <- renderText({
req(nchar(path1())>0)
vispat <- paste0(path1(),"/visit.csv")
})
statpat <- renderText({
req(nchar(path1())>0)
statpat <- paste0(path1(),"/statvisit.csv")
})
So now I have these paths, but how can I use them to upload the related content to the server? A simple read.csv unfortunately does not do the trick.
EDIT - but not there yet...
Working further with the great help #SBista provided, I think I'm approaching my goal, but see below code...
volumes <- getVolumes()
shinyDirChoose(input, 'directory', roots=volumes, session=session)
path1 <- reactive({
return(print(parseDirPath(volumes, input$directory)))
})
observe({
if(!is.null(path1)){
### vis1
vis1 <- reactive({
datpat <- paste0(path1(),"/visit.csv")
vis <- read.csv(datpat, header = input$header, sep = input$sep, quote = input$quote,
stringsAsFactors = FALSE)
vis
})
### dataruw1
dataruw1 <- reactive({
datpat <- paste0(path1(),"/data.csv")
dataruw <- read.csv(datpat, header = input$header, sep = input$sep, quote = input$quote,
stringsAsFactors = FALSE)
dataruw
})
}
})
Unfortunately, dataruw1 and vis1 do not seem to be generated, as I get a 'could not find function' error when trying to use the actual data with dataruw1() and vis1(). What am I missing? Any idea? Thanks a lot in advance!
I have modified your app to demonstrate that you can use read.csv to upload the file. For demonstration I am reading only one file from the folder and displaying the read data frame in a datatable.
library(shiny)
library(shinyFiles)
### ui end, to browse to desired folder
ui = fluidPage(shinyDirButton('directory', 'Folder select', 'Please select a folder'),
tableOutput(outputId = "datpat")
)
### extracting the folder path
server = function(input, output, session) {
volumes <- getVolumes()
shinyDirChoose(input, 'directory', roots=volumes, session=session)
path1 <- reactive({
return(print(parseDirPath(volumes, input$directory)))
})
### constructing the 3 file paths
observe({
if(!is.null(path1)){
output$datpat <- renderTable({
req(nchar(path1())>0)
datpat <- paste0(path1(),"/data.csv")
dat <- read.csv(datpat)
dat
})
}
})
}
shinyApp(ui = ui, server = server)
Hope it helps!
Happy to have found a solution! Big thanks to SBista once more, even though I did it a bit differently. The below code is not just a chunk (as in my original post) but fully functional, provided you browse to a folder that contains a data.csv file.
library(shiny)
library(shinyFiles)
library(htmltools)
##############################################################################
ui = navbarPage(
HTML("Title"),
tabPanel(HTML("<font size=3>Start</font>"),
sidebarPanel(width = 2,
shinyDirButton('directory', 'Folder select', 'Please select a folder'),
checkboxInput('header', 'Header', TRUE),
radioButtons('sep', 'Separator', c(Comma=',',Semicolon=';',Tab='\t'), selected=';'),
radioButtons('quote', 'Quote', c(None='','Double Quote'='"','Single Quote'="'"), selected='"')),
mainPanel(
fluidRow(
column(6, tags$b(textOutput("text")))),
tags$hr(),
fluidRow(
column(6, dataTableOutput("table"))
)
)
)
)
server = function(input, output, session) {
volumes <- getVolumes()
shinyDirChoose(input, 'directory', roots=volumes, session=session)
path1 <- reactive({
return(print(parseDirPath(volumes, input$directory)))
})
dataruw1 <- eventReactive(input$directory, {
datpat <- paste0(path1(),"/data.csv")
dataruw <- read.csv(datpat, header = input$header, sep = input$sep, quote = input$quote,
stringsAsFactors = FALSE)
dataruw
})
output$text <- renderText({
path1()
})
output$table <- renderDataTable({
dataruw1()
})
}
shinyApp(ui = ui, server = server, options = list(launch.browser=TRUE))