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)
Related
i've built an app that allow users to paste a folder path so that files inside that folder can be listed and selected. The app works when i set the path globally but i really need users to be able to stipulate their path. The path needs to be a network path as we use Azure/Databricks...
library(dplyr)
library(shinyWidgets)
library(shinythemes)
library(DT)
fpath <- '/dbfs/dbfs/Analytics/ShinyApp' #example path
# Define UI
ui <- fluidPage(
theme = shinytheme("spacelab"),
navbarPage(
"App",
tabPanel(
"Setup Project",
sidebarPanel(
textInput("v_inpath", "Specify File Path:", ""),
actionButton("Setpath", "Set Path"),
selectInput("selectfile", "Select File to Analyse",choice = list.files("ppath", pattern = ".csv")) #list of files should show up here
), # sidebarPanel
mainPanel(verbatimTextOutput("ppath")) # mainPanel
) #tabPanel
) # navbarPage
) # fluidPage
# Define server function
server <- function(input, output, session) {
observeEvent(input$Setpath,{
output$ppath <-reactive({paste0(input$v_inpath)})
})
} # server
# Create Shiny object
shinyApp(ui = ui, server = server)
In the mainPanel, i can see the path being pasted correctly as text (as you can see i'm using verbatimTextOutput("ppath")). The list of files contained in the specified folder should show up but it does not work as no list is available... Thank you in advance for your help
You need renderUI
You should avoid to put an output element inside an observer
You could use the shinyFiles package or the jsTreeR package to select the path
Code:
library(shiny)
# Define UI
ui <- fluidPage(
navbarPage(
"App",
tabPanel(
"Setup Project",
sidebarPanel(
textInput("v_inpath", "Specify File Path:", ""),
actionButton("Setpath", "Set Path"),
uiOutput("selectfileUI")
), # sidebarPanel
mainPanel(verbatimTextOutput("ppath")) # mainPanel
) #tabPanel
) # navbarPage
) # fluidPage
# Define server function
server <- function(input, output, session) {
output[["selectfileUI"]] <- renderUI({
req(input[["Setpath"]])
files <- list.files(input[["v_inpath"]], pattern = ".csv")
selectInput("selectfile", "Select File to Analyse", choices = files)
})
output[["ppath"]] <- renderPrint({
input[["v_inpath"]]
})
} # server
# Create Shiny object
shinyApp(ui = ui, server = server)
EDIT: feedback
Also, you can use the shinyFeedback package to print a message when the path is not valid:
library(shiny)
library(shinyFeedback)
# Define UI
ui <- fluidPage(
useShinyFeedback(), # don't forget this line
navbarPage(
"App",
tabPanel(
"Setup Project",
sidebarPanel(
textInput("v_inpath", "Specify File Path:", ""),
actionButton("Setpath", "Set Path"),
uiOutput("selectfileUI")
), # sidebarPanel
mainPanel(verbatimTextOutput("ppath")) # mainPanel
) #tabPanel
) # navbarPage
) # fluidPage
# Define server function
server <- function(input, output, session) {
Check <- eventReactive(input[["Setpath"]], {
dir.exists(input[["v_inpath"]])
})
Files <- reactive({
req(Check())
list.files(input[["v_inpath"]], pattern = ".csv")
})
observeEvent(input[["Setpath"]], {
hideFeedback("v_inpath")
show <- !Check() || length(Files()) == 0
if(show) {
if(Check()) {
text <- "No CSV file in this folder"
} else {
text <- "Invalid path"
}
showFeedbackWarning("v_inpath", text)
} else {
hideFeedback("v_inpath")
}
})
output[["selectfileUI"]] <- renderUI({
req(Files())
selectInput("selectfile", "Select File to Analyse", choices = Files())
})
output[["ppath"]] <- renderPrint({
input[["v_inpath"]]
})
} # server
# Create Shiny object
shinyApp(ui = ui, server = server)
I am trying to dynamically select directory from the computer where files are stored. Currently there is a sas dataset named 'sample' stored under my win10 PC desktop.
I would like to print out the first 10 observations of the sample dataset I read into, but it is not working without showing any error.
library(shiny)
library(shinyFiles)
library(haven)
library(DT)
ui<-fluidPage(sidebarLayout(
sidebarPanel(
shinyDirButton("dir", "Chose directory", "Upload")
),
mainPanel(
DT::dataTableOutput("sasdat")
)
))
server <- function(input,output,session){
dir <- reactive(input$dir)
shinyDirChoose(input, 'dir', roots=c(name=getwd()), session=session)
path1 <- reactive({
return(print(parseDirPath(volumes, input$dir)))
})
data1 <- eventReactive(input$path1, {
sample <- data.frame(read_sas(paste0(path1, "sample.sas7bdat")))
sample
})
output$sasdat = DT::renderDataTable({
head(data1(),10)
})
}
shinyApp(ui = ui, server = server)
Try this
library(shiny)
library(shinyFiles)
library(haven)
library(DT)
ui<-fluidPage(sidebarLayout(
sidebarPanel(
shinyDirButton("dir", "Chose directory", "Upload")
),
mainPanel(
DTOutput("sasdat")
)
))
server <- function(input,output,session){
#dir <- reactive(input$dir)
volumes <- getVolumes()
shinyDirChoose(input=input, 'dir', roots=volumes, session=session)
path1 <- reactive({
parseDirPath(volumes, input$dir)
})
data1 <- eventReactive(path1(), {
sample <- data.frame(haven::read_sas(paste0(path1(), "sample.sas7bdat")))
sample
})
output$sasdat = renderDT({
head(data1(),10)
})
}
shinyApp(ui = ui, server = server)
Or you can use fileInput to choose a file from your pc...
ui<-fluidPage(sidebarLayout(
sidebarPanel(
fileInput("sasdata1", "Choose a SAS dataset", multiple = FALSE, accept = ".sas7bdat"),
),
mainPanel(
DTOutput("sasdat")
)
))
server <- function(input,output,session){
data1 <- reactive({
req(input$sasdata1)
inData1 <- input$sasdata1
if (is.null(inData1)){ return(NULL) }
mydata1 <- haven::read_sas(inData1$datapath)
})
output$sasdat = renderDT({
head(data1(),10)
})
}
shinyApp(ui = ui, server = server)
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)
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 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)