R Shiny request user to choose directory - r

I am new to R and R Shiny.
For the code i have at the moment i need to manually input the file name, i would like to generalize the case and let the user to pick working directory and corresponding file name.
1, user choose working directory
then shiny able to store all the file names under the selected working directory. similar to list.files()
2, then the box list files will list all file names under the selected wd
and user able to check which dataset should be shown
3, in the mainpanel
top 10 instances of the dataset with the header will be shown
What i have tried is
server.R
library(shiny)
setwd("C:/Users/HKGGAIT001/Google Drive/GA Project/Cargo/Cargo.Statistics/data/Hactl")
data1 <- read.csv(list.files()[1])
data2 <- read.csv(list.files()[2])
# Define server logic required to summarize and view the selected
# dataset
shinyServer(function(input, output) {
# Return the requested dataset
datasetInput <- reactive({
switch(input$dataset,
"data1" = data1,
"data2" = data2)
})
# Generate a summary of the dataset
output$summary <- renderPrint({
dataset <- datasetInput()
summary(dataset)
})
# Show the first "n" observations
output$view <- renderTable({
head(datasetInput(), n = input$obs)
})
})
ui.R
library(shiny)
# Define UI for dataset viewer application
shinyUI(fluidPage(
# Application title
titlePanel("Shiny Text"),
# Sidebar with controls to select a dataset and specify the
# number of observations to view
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("data1", "data2")),
numericInput("obs", "Number of observations to view:", 10)
),
# Show a summary of the dataset and an HTML table with the
# requested number of observations
mainPanel(
verbatimTextOutput("summary"),
tableOutput("view")
)
)
))
The situation is similar to This website while my case is request user to pick local working directory.
Thanks for your gentle help

First, create the .csv files to reproducibility:
write.csv(x = data.frame(V1 = 1:13, V2 = letters[1:13]),
file = "teste1.csv", row.names = FALSE)
write.csv(x = data.frame(V1 = 14:26, V2 = letters[14:26]),
file = "teste2.csv", row.names = FALSE)
write.csv(x = data.frame(V1 = rnorm(15), V2 = runif(15)),
file = "teste3.csv", row.names = FALSE)
Add a global.R script in your app might be useful. In this script you would be able to:
i. let the user select the working directory,
ii. read the .csv files in that folder,
iii. create a list of files that could be used by ui.R and server.R
# global.R
library(shiny)
wd <<- choose.dir()
setwd(wd)
csv <<- list.files(pattern = ".csv")
files <<- vector("list", length(csv))
for (i in seq_along(files)) {
files[[i]] <- read.csv(csv[i], stringsAsFactors = FALSE)
}
list_of_datasets <<- seq_along(files)
names(list_of_datasets) <- gsub(pattern = ".csv", replacement = "", x = csv)
Then you just have to make a few changes in the original scripts you provided us. In ui.R I would redefine the selectInput function so that displays the name of the files to the users. Also, you can't be sure that the selected folder would have 2 files.
selectInput("dataset", "Choose a dataset:",
choices = list_of_datasets)
In server.R you should i) remove the 2nd, 3rd and 4th lines (already handled by global.R) and ii) change datasetInput function:
datasetInput <- reactive({
files[[as.numeric(input$dataset)]]
})

Related

R Shiny: 'file' must be a character string or connection when using read.csv()

I'm having an issue which I thought would have been very simple to solve, but I cannot figure it out.
I simply want to pass an uploaded csv file to a custom function in Shiny and output the result which is a ggplot graph. Here is my code for doing so
# Getting the file names
rdsfiles <- list.files(pattern = "\\.Rds$")
# --- Front End ---
ui <- shinyUI(fluidPage(theme = shinytheme("cerulean"), pageWithSidebar(
# Title
headerPanel("Title"),
# Sidebar to select a dataset
sidebarPanel(
selectInput("obj", "Choose a dataset:",
choices = rdsfiles),
fileInput("tissue_csv",
"Load tissue positions .csv file",
accept = c("text/csv", "text/comma-separated-values,text/plain",".csv")
),
textInput("feature", label = "Gene"),
),
# Different analyses available
mainPanel(
tabsetPanel(
tabPanel('UMAP', plotOutput("umap")),
tabPanel('Tissue', plotOutput("tissue")),
tabPanel('Gene Expression', plotOutput("genex")),
))
)))
# --- Back end ---
server <- shinyServer(function(input, output) {
# Return the requested datasets
datasetInput <- reactive({
df <- readRDS(input$obj, input$obj)
return(df)
})
tissueInput <- reactive({
inFile <- req(input$tissue_csv)
read.csv(inFile$datapath)
})
### HERE IS WHERE THE ERROR LIES ###
output$tissue <- renderPlot({
obj <- datasetInput()
tiss <- tissueInput()
custom_function(obj, tiss)
})
# Retrieve the UMAP projection
output$umap <- renderPlot({
obj <- datasetInput()
DimPlot(obj, reduction = "umap")
})
})
shinyApp(ui, server)
Whenever I use the app and upload my .csv file, it always gives me an error message that says 'file' must be a character string or connection. Why is this? Any suggestions?

Shiny app file upload is substantially slower on different machines

I have a shiny application that takes a file upload, calls a script that processes the uploaded file, and writes 4 csvs as output. The app works but as the title suggests, the file upload takes ~5 seconds on my end, but the intended end user is waiting 40 minutes for the same 32 MB file to upload. How do I reduce this upload time for them?
I am attaching my code, but here are some additional points that may be relevant:
The shiny code, the script it calls, and the file to be uploaded are all on a shared drive.
I am accessing their system through a virtual desktop, while the end user has a company computer.
Thanks in advance.
library(shiny)
source([removed for confidentiality])
# Define UI for dataset viewer app ----
ui <- fluidPage(
# App title ----
titlePanel("DFM File Conversion"),
# Sidebar layout with a input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Selector for choosing dataset ----
textInput(inputId = "exportname1",
label = "Credit Detail [003 Record] Output Name",
value = ""),
textInput(inputId = "exportname2",
label = "Location Bank Deposit [013 Record] Output Name",
value = ""),
textInput(inputId = "exportname3",
label = "Batch Summary [025 Record] Output Name",
value = ""),
textInput(inputId = "exportname4",
label = "Rejected Transactions [029 Record] Output Name",
value = ""),
fileInput("file1", "Please upload a file")
),
# Main panel for displaying outputs ----
mainPanel(
verbatimTextOutput("summary") #shows what files were converted
,h3(textOutput("caption"))
,tableOutput("view") # shows which records are not present in uploaded file
,h3(textOutput("caption2"))
,tableOutput("headdf") #shows first 5 rows of uploaded file
)
)
)
server <- function(input, output) {
options(shiny.maxRequestSize=60*1024^2)
# This reads in the uploaded file from the UI and outputs the first 5 rows
# Then it uses the export name entered by the user to convert the file
# using the conversion script.
output$view <- renderTable({
req(input$file1)
df <- read.delim(input$file1$datapath,header = FALSE, stringsAsFactors = FALSE)
converted <- convertdfm(df, input$exportname1, input$exportname2, input$exportname3, input$exportname4)
# this populates which records are not present in uploaded data
return(converted$output)
})
# this prints the first 4 rows of the file
output$headdf <- renderTable({
req(input$file1)
df1 <- read.delim(input$file1$datapath,header = FALSE, stringsAsFactors = FALSE)
head(df1)})
# this creates the first caption
output$caption <- renderText({
req(input$file1)
print("Checking Input Files for Unavailable Records")
})
# this creates the second caption
output$caption2 <- renderText({
req(input$file1)
print("First 5 Rows of Raw Data")
})
# this shows what files were converted
output$summary <- renderPrint({
req(input$file1)
if (file.exists(input$exportname1))
{print("003 Converted")} else
{print("003 Not Converted")}
if (file.exists(input$exportname2))
{print("013 Converted")} else
{print("013 Not Converted")}
if (file.exists(input$exportname3))
{print("025 Converted")} else
{print("025 Not Converted")}
if (file.exists(input$exportname4))
{print("029 Converted")} else
{print("029 Not Converted")}
}
)
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)

Read zip file containing multiple .csv tables in R shiny app

I'm working on a shiny app to manipulate data.
I'd like to read a zip file selectioned in a fileInput. This zip is composed by multiple csv files, and I'd like to save as reactive values all .csv dataframes.
For example, if test.zip contains file ONE.csv, TWO.csv, THREE.csv , i'd like to obtain 3 reactives values (as dataframes) called ONE , TWO, THREE .
I'm abble to do it if I know the name and number of csv files.
But if I don't know the number and names of .csv dataframes, how can I achieve it ?
## Only run examples in interactive R sessions
if (interactive()) {
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("ZIP", "Choose ZIP File",
accept = ".zip"
)
),
mainPanel(
DT::dataTableOutput("ONEtab")
)
)
)
server <- function(input, output) {
ONE <- reactive({
inFile <-req(input$ZIP)
read_csv(unzip(inFile$datapath,"ONE.CSV"))
})
TWO <- reactive({
inFile <-req(input$ZIP)
read_csv(unzip(inFile$datapath,"TWO.CSV"))
})
THREE <- reactive({
inFile <-req(input$ZIP)
read_csv(unzip(inFile$datapath,"THREE.CSV"))
})
output$ONEtab <- DT::renderDataTable({ DT::datatable(ONE(), option=list(scrollX=T),filter = 'top')})
}
shinyApp(ui, server)
}
Thanks for your help !
One option is to read all the dataframes into a single variable and then use a number to select the one of interest. Here's some code that does this. It uses lapply to read the contents of the zip file to create a reactive variable called all. To reference different dataframes, the code required is all()[[index]] and I have added something that shows this.
library(DT)
library(readr)
ui <- fluidPage(sidebarLayout(sidebarPanel(
fileInput("ZIP", "Choose ZIP File", accept = ".zip"),
selectInput("choice", 'Choose', choices = c(1,2,3), selected = 1)
),
mainPanel(DT::dataTableOutput("selectone"))))
server <- function(input, output) {
all <- reactive({
inFile <- req(input$ZIP)
filelist <- unzip(inFile$datapath, list = T)
lapply(filelist$Name, read_csv)
})
output$selectone <-
DT::renderDataTable({
choice = as.integer(input$choice)
DT::datatable(all()[[choice]], option = list(scrollX = T), filter = 'top')
})
}
shinyApp(ui, server)
Without the rest of your code that processes this, it's difficult to know if this will be what you need but perhaps it's a start.

Reactive CSV selection then used in function as df

I am new to shiny and trying to combine a couple features and having some trouble.
I want for the user to be able to select a CSV and then be presented with a random instance (in this case tweet) from that table. The following code worked when "tweetData" was a statically loaded csv using read_csv.
## function to return random row number from data set
getTweet <- function(){
tweetData[sample(nrow(tweetData), 1), ]
}
function(input, output, session) {
## set reactive values, get randomized tweet
appVals <- reactiveValues(
tweet = getTweet(),
ratings = data.frame(tweet = character(), screen_name = character(), rating = character())
)
I want to instead use a dynamically chosen csv for "tweetData", something like adding this??
csvName <- reactive(paste0('../folder_path/', input$file_name))
selectedData <- read.csv(csvName)
How can use reactively chosen csvs to fit into the structure of the first code chunk?
You might be looking for fileInput for giving user an option to upload a dataset.
This is a simple reproducible example -
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File"),
),
mainPanel(
tableOutput("contents")
)
)
)
server <- function(input, output) {
output$contents <- renderTable({
req(input$file1)
read.csv(input$file1$datapath)
})
}
shinyApp(ui, server)

Save the contents of a local csv file as a vector in Shiny

I have a drop-down menu in my UI:
selectInput(inputId = "Header", label = "label",
choices = x,
selected = NULL),
I would like the variable "x" in the above example to be a character vector containing roughly 100 different options. I have these options saved in a .csv file, but I cannot get the data in the .csv file (which I've uploaded to my directory) to save as a vector. How should I go about saving data from local .csv files into R shiny for use as menu options? I've been trying read.csv among other functions, but no luck so far.
Do I simply have to copy them all over manually? I assume there's an easier way.
Example data
write.table(rownames(mtcars), "mtcars.csv",
row.names = FALSE, col.names = FALSE, quote = FALSE)
library(shiny)
# User interface that lets you to select input
ui <- fluidPage(
selectInput("mySelection", "Select input", "")
)
server <- function(input, output, session) {
observe({
# Load your csv file
x <- read.csv("mtcars.csv", header = FALSE)
# Update selection mySelection (passed to UI)
updateSelectInput(session, "mySelection",
label = "Select input",
choices = x[, 1],
selected = x[, 1][1]
)
})
}
shinyApp(ui, server)

Resources