'How can I use Shiny as an upload form for an R Script?
I have an R script that loops through a folder of csv files, transforms them, and then writes several csv files once completed.
I want users to be able to use an input form to select various files before the R script runs. I have never used Shiny before, and I cannot figure out the best way to do this. Here is what I have come up with so far:
UI
library(shiny)
library(shinyjs)
fieldsMandatory <- c("calDataImport")
appCSS <- ".mandatory_star { color: red; }"
labelMandatory <- function(label) {
tagList(
label,
span("*", class = "mandatory_star")
)
}
ui <- fluidPage(
shinyjs::useShinyjs(),
shinyjs::inlineCSS(appCSS),
options(shiny.maxRequestSize = 30 * 1024^2),
titlePanel("Setup"),
sidebarLayout(
sidebarPanel(
fileInput("calDataImport", labelMandatory("Choose CSV File for Calibration Data"),
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
tags$hr(),
shinyDirButton("ticLoc", "Choose Sample Folder", "Upload"),
tags$hr(),
# Output: Go and Download----
downloadButton('submit', 'Select Save Location and Go', class= "action"),
# CSS style for the download button ----
tags$style(type='text/css', "#downloadFile { width:100%; margin-top: 35px;}")
),
mainPanel()
)
)
Server
server <- function(input, output) {
observe({
# check if all mandatory fields have a value
mandatoryFilled <-
vapply(fieldsMandatory,
function(x) {
!is.null(input[[x]]) && input[[x]] != ""
},
logical(1))
mandatoryFilled <- all(mandatoryFilled)
# enable/disable the submit button
shinyjs::toggleState(id = "submit", condition = mandatoryFilled)
})
# dir
shinyDirChoose(input, 'ticLoc', roots = c(home = '~'), filetypes = c('xlsx', 'csv'))
ticLoc <- reactive(input$ticLoc)
output$ticLoc <- renderPrint(ticLoc())
# path
path <- reactive({
home <- normalizePath("~")
file.path(home, paste(unlist(ticLoc()$path[-1]), collapse = .Platform$file.sep))
})
# files
calDataImport <- reactive({
inFile <- input$calDataImport
if (is.null(inFile)) return(NULL)
calDataImport <- read.csv(inFile$datapath, header = TRUE)
calDataImport
})
# Download handler in Server
output$submit <- downloadHandler(
filename = function() {
paste('RAPTOR_Output', Sys.Date(), '.zip', sep='')
},
content = function(con) {
owd <- setwd(tempdir())
on.exit(setwd(owd))
outputFiles <- NULL;
################ INSERTING STANDARD R SCRIPT HERE ##########
# [necessary libraries here]
# [functions defined here]
if("CAS#" %in% colnames(calDataImport)){names(calDataImport)[names(calDataImport) == 'CAS#']<-"CAS Number"}
if("Component RT" %in% colnames(calDataImport)){names(calDataImport)[names(calDataImport) == 'Component RT']<-"Ret. Time"}
outputFileName <- paste("calDataImport", "csv", sep = ".")
write.csv(calDataImport, outputFileName, row.names = FALSE)
outputFiles <- c(outputFileName,outputFiles)
setwd(ticLoc)
files <- list.files(pattern = "csv")
filesFull <- list.files(pattern = "csv", full.names = TRUE)
for (i in 1:length(files)) {
fileName <- str_split(files[i], "\\.", n=2)[[1]][1]
rawData <- read.csv(paste(fileName, str_split(files[i], "\\.", n=2)[[1]][2], sep="."), check.names=FALSE)
# [more transforming script here]
outputFileName <- paste(fileName, "_Annotated",".csv", sep = "")
write.csv(annotatedData, outputFileName, row.names = FALSE)
outputFiles <- c(outputFileName,outputFiles)
}
################### END ############
#create the zip file
zip(con,outputFiles)
})
}
# Create Shiny app ----
shinyApp(ui, server)
What I have here doesn't seem to work. I get the following error:
Warning: Error in UseMethod: no applicable method for 'filter' applied to an object of class "c('reactiveExpr', 'reactive', 'function')" [No stack trace available]
So my question is, how can I make this work? My standard R script that I am inserting is nearly 2000 lines, so I would rather not have to go through and adjust the script if possible.
Thank you so much for any insight you can provide!
Solution 1:[1]
This is a shiny app letting the user to upload multiple csv files. Then, the app reads each csv file and then calculates some properties, which will be displayed on the app. Please note the option multiple = TRUE in fileInput:
library(tidyverse)
library(shiny)
ui <- fluidPage(
fileInput(
inputId = "files",
label = "Upload tables",
placeholder = "No files selected.",
multiple = TRUE,
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv"
)
),
tableOutput("table")
)
server <- function(input, output, session) {
output$table <- renderTable({
req(input$files %>% nrow() > 0)
input$files %>%
as_tibble() %>%
mutate(data = datapath %>% map(read_csv)) %>%
transmute(
datapath,
nrow = data %>% map_int(nrow),
colnames = data %>% map_chr(~ .x %>%
colnames() %>%
paste0(collapse = ", "))
)
})
}
shinyApp(ui, server)
Here I uploaded 2 csv files with the content of the R objects iris and mpg:
I do not know how your script is structured, but the uploaded files are in the directory dirname(input$files$datapath[[1]]).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | danlooo |

