I'm new to shiny and I would like your advice on a requirement that I have at my office. I apologize in advance for not providing more information or code at the moment.
I have currently coded a R script that does the following:
Import 7 excel files with read_excel:
File 1 will go to dataset 1
File 2 will go to dataset 2
File 3,4,5,6,7 will go to dataset 3 by using lapply
Does a whole lot of data cleaning, formatting, parsing and ordering
Merges everything together and creates a final excel and txt files with specific formatting
Im requiring a shiny web app that:
Provides 3 different upload boxes for the user. One for each type of file (1 / 2 / 3,4,5,6,7)
Internally saves the uploaded files so the code i already have can use them for its processing
Lets the user download the 2 output files made by my code to the computer
If possible, show a log window on the app so the user can know if something goes wrong with the code execution
Datasets visualization is not required
I might be asking a lot. I will appreciate if you just can give me some lights in how i can start working on this. I would like not to modify my current code, if possible (can i have shiny acquire the files, and call my code so it can process them?)
Here is a minimal example showing uploading files, processing them, and downloading them.
For simplicity I've used 3 inputs and a single output.
If you want to notify a user that something has happened, you can use showNotification()
library(shiny)
ui <- fluidPage(
#File Upload Boxes
fileInput("myfileinput_1", label = "Upload File 1", accept = ".csv"),
fileInput("myfileinput_2", label = "Upload File 2", accept = ".csv"),
fileInput("myfileinput_3", label = "Upload File 3", accept = ".csv"),
#Button
actionButton("mybutton", label = "Process Uploaded Files"),
#Table Showing Processed Data
tableOutput("mytable"),
#Download Buttons
downloadButton("myfiledownload", label = "Download Processed File")
)
server <- function(input, output, session) {
#A reactive dataframe to store our outputfile
reactives <- reactiveValues(
df_output = NULL
)
#Runs when button is pressed
observeEvent(input$mybutton, {
#Check that all 3 files are selected before loading
if(!is.null(input$myfileinput_1) & !is.null(input$myfileinput_2) & !is.null(input$myfileinput_3)) {
#Load input files
df_input_1 <- read.csv(input$myfileinput_1$datapath)
df_input_2 <- read.csv(input$myfileinput_2$datapath)
df_input_3 <- read.csv(input$myfileinput_3$datapath)
#Use input to create an output (we're just using a simple example)
reactives$df_output <- data.frame(
input = c("Input 1", "Input 2", "Input 3"),
rows = c(nrow(df_input_1), nrow(df_input_2), nrow(df_input_3))
)
showNotification("Files Successfully Processed", type = "message")
} else {
showNotification("Ensure all three files are selected before loading", type = "error")
}
})
#Table Output
output$mytable <- renderTable({
reactives$df_output
})
#Download handler
output$myfiledownload <- downloadHandler(
filename = "mydata.csv",
content = function(file) {write.csv(reactives$df_output, file, row.names = FALSE)}
)
}
shinyApp(ui, server)
Related
So I have a shiny app and a text input that receives a single word which serves as input for a function, it looks like this in the UI:
textInputAddon(inputId="taxa",addon=icon("search"),
label=tags$h4(tags$strong("Enter the name of the taxonomic group:")),placeholder="Example: Cetacea")
Then in the server the word submited in the input is used to download a tsv file, and I render it like this:
taxaInput <- reactive({grades(input$taxa)})
output$downloadData <- downloadHandler(
filename = function() {
paste(input$taxa, ".tsv")
},
content = function(file) {
shiny::withProgress(
message=paste0("Downloading and annotating dataset for ",input$taxa), detail='This may take several minutes',
value=0,
{
shiny::incProgress(1/10)
Sys.sleep(1)
shiny::incProgress(4/10)
write_tsv(taxaInput(), file)
}
)
}
)
The "grades()" function is my user made function and I can onlye use it to download the file searching for one single word. What I want is to be able to search to put something like this in the input:
Word1,Word2,Word3
In a simples R script I used to replace the word for a vector:
group<-c(Word1,Word2,Word3)
But in the shiny app I'm not being able to
Thanks for any response in advance
You can use unlist(strsplit(input$taxa, ",")). However you are better off using selectInput() with multiple = T if the taxa choices are exhaustive. That way you'll won't need strsplit and also you have complete control on what words are entered.
Anyways, here's the way with strsplit -
library(shiny)
shinyApp(
ui = fluidPage(
textInput("words", "Enter Words"),
verbatimTextOutput("test")
),
server = function(input, output, session) {
output$test <- renderPrint({
words <- unlist(strsplit(input$words, ",")) # get words separated by ','
paste0(words, "_", seq_along(words)) # some random function
})
}
)
App snapshot -
I want to select some files in the browser like with fileInput in Shiny but I only need their paths as a character and nothing else. I do not want to upload them (but it's no problem if it is done anyway). When I use fileInput the result is a data.frame containing the paths of the files in a temporary folder with the names i.e. 0.csv, 1.txt, 2.pdf ... But I need the original filenames (with or without the full path). Is there any way to achieve this in a fast and 'non-hacky' way?
There is a very important reason why this is not possible: Security
JavaScript has no accress to the file System, so you will not to able to get the full paths of the user. One option is your force your user to use a path, but well... he can lie there of course. Maybe do it like this
You could only use it like this:
library(shiny)
ui <- fluidPage(
tags$h1("Test"),
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
textInput("path", "Please enter the full path of your file"),
tableOutput("pathtable")
)
server <- function(input, output, session) {
testdf <- reactive({
data.frame(
ID = 1,
file = input$path
)
})
output$pathtable <- renderTable({
if(input$path == "") {
return(NULL)
} else {
testdf()
}
})
}
shinyApp(ui = ui, server = server)
The original names are saved in the variable
input$file1$name
However the "real" data (which is renamed as OP correctly pointed out) can be accessed via
input$file1$datapath
where file1 is the InputId of the function fileInput()
I am setting up a shiny application that asks for a dataset, asks for information about said data set, and then runs a series of analytic models on said data set, taking into account information about the dataset (for example, the names of variables to adjust for in a regression). The app starts with a simple UI with a data upload input. Once the user has uploaded their data, I would like the UI to dynamically add a new section that asks the user to select a subset of variables from the column labels of their dataset.
I am working with RStudio Server via a Linux AWS machine.
My app is generated as an add-on to another R package that serves as a wrapper for most of the statistical functions I require. Since the app is quite large, the UI is composed of some standard text and a series of functions that call tabItems for the UI.
In the example below, the UI has a standard data upload user input. In addition to this I have attempted to use shiny::renderUI on the server side to take the user-provided dataset, read the columns, and return the set of columns via shiny::varSelectInput(). Unfortunately, my app does not provide this new input after uploading the data.
ui_data_1 <- function(){
y<-tabItem(tabName = "load_dat",
shiny::tabsetPanel(type = "tabs",
# Data upload ---- -
h2("Data"),
p("Please upload your data file"),
shiny::fileInput(
inputId = "data_file", label = "Upload patient data file (.csv Only)",
accept = c(".csv")
),
h2("Treatment"),
p("Instructions for treatment"),
shiny::uiOutput("variables"))
)
)
return(y)
}
server_data_1 <- function(){
y <- shiny::renderUI({
inFile <- input$data_file
# Load data
if (is.null(inFile)) {
df <- shiny::reactive({NULL})
} else {
df <- shiny::reactive({read.csv(inFile$datapath, header = input$header)})
}
varnames <- colnames(df())
shiny::varSelectInput(
inputId = "treat",
label = "Treatment Variable",
data = c(varnames)
)
})
return(y)
}
#UI.R
body <- shinydashboard::dashboardBody(
ui_data_1()
)
ui <- shinydashboard::dashboardPage(header, sidebar, body, skin = "black")
#Server.R
server <- function(input, output) {
output$variables <- server_data_1()
}
shiny::shinyApp(ui, server)
The app loads properly, as does the data upload menu. When I upload the data, I receive a notification indicating that the upload was successful. The label associated with inputId = "treat" is visible the entire time. However, the variable selection menu does not populate after uploading the data as expected. Perhaps I've done something wrong. Thanks in advance for any advice.
I've been trying to write my first small shiny app that takes two .xlsx files and do inner_join (like SQL would do) and then let's you download the result .xlsx. But when I try to download the file, I get error message that says:
Error in path.expand(file) : invalid 'path' argument
Warning: Error in path.expand: invalid 'path' argument
Here is my ui.R:
shinyUI(pageWithSidebar(
headerPanel('A linker'),
sidebarPanel(
fileInput("data","Choose file"),
textInput('d_sheet','Write the name of the sheet to be modified',
value = "", placeholder = "e.g. List 1"),
textInput('d_col','Write the ID-number of column that contains the ID'),
fileInput("libr","Choose library"),
textInput("l_sheet","Write the name of sheet that contains the data",
value="",placeholder="e.g. List 1"),
textInput("l_col","write the ID-number of column that contains the ID"),
textInput("l_join","Write the ID-number of columns to be linked to the
file")
),
mainPanel(
p('This application allows you to link data from the LIBRARY to
the data of the FILE. FILE is the table to be enhanced by the new data,
LIBRARY is the source of the data.'),
downloadButton("dwnld_data",label ="Download"))))
and server.R:
shinyServer( function(input, output){
options(shiny.maxRequestSize = 9*1024^2)
res_file<-reactive({
input_File <- input$data#
file_sheet<-input$d_sheet#
file_col<-as.vector(input$d_col)#
lib_File<-input$libr#
lib_sheet<-input$l_sheet#
lib_col<-as.vector(input$l_col)#
lib_data<-as.vector(input$l_join)#
a_file<-read.xlsx(input_File,sheetName = file_sheet)
colnames(a_file)[1:file_col]<-"a"
colnames(a_file)[file_col:ncol(a_file)]<-"b"
colnames(a_file)[file_col]<-"ID"
l_file<-read.xlsx(lib_File,sheetName=lib_sheet)
tab_l<-l_file[,c(lib_col,lib_data)]
colnames(l_file)<-"ID"
r_file<-inner_join(a_file,l_file,by="ID")
r_file})
output$dwnld_data <- downloadHandler(
filename = function() {paste("result.xlsx")},
content = function(file) {
write.xlsx(res_file(),file, sheetName="List 1")
})})
It's nothing fancy, more like my first experiment. I have tried to find solution to this error for several hours and red a lot of articles, so I am very sorry, if I ask you something, that has been already answered, I haven't found it.
All I have found and tried:
update R Studio (no effect)
try to first write the file into some temporary dir and then load it back (no effect)
Thank you for your help!
I am trying to create a UI on which I can upload a file and also there is a text input where I can write the product name which I want to search in the uploaded file. I am doing that using the Levenshtein Distance function (adist() function). Now, once i get the results for which the edit distance is 0, I want to display those rows in the Table on the Main Panel. Whatever input is given in the Text input on the UI is searched against the items column in the file uploaded. A sample image of the CSV file which is uploaded is this-
Sample image of the CSV file which is input by the user
Once I run the code and find the edit distance for all the words, I store them in a vector and then use this to print the rows from the file which have edit distance equal to 0. The problem is that when I click on submit, the result is not displayed on the UI but it is displayed on the R-studio console. How do I fix this?
Please help me with the code.
library(shiny)
ui = shinyUI(fluidPage(
titlePanel("LEVENSHTEIN DISTANCE function trial"),
sidebarLayout(
sidebarPanel(
numericInput("rows","Enter the number of rows",value=NULL),
textInput("product", "input product name"),
br(),
br(),
fileInput("file", "Input the file"),
submitButton("Find!")),
mainPanel(
tableOutput("result")
)
)
))
server = shinyServer(function(input,output) {
output$result <- renderPrint({ if (is.null(input$file)) return( );
trial = read.csv(input$file$datapath)
ls = vector('list', length = input$rows)
for(i in 1:input$rows) {
edit = adist("earbuds", trial$items[i])
new_edit = as.numeric(edit)
ls[i] = edit
if(ls[i]==0) print(trial[i, ])
}
})
})
shinyApp(ui=ui,server=server)
Thank You!
It is very hard to provide working code without sample input date. But, here is my attempt at giving you what I think should work.
server = shinyServer(function(input,output) {
output$result <- renderTable({
if (!is.null(input$file)) {
trial = read.csv(input$file)
trial <- trial[adist('earbuds', trial$items) == 0), ]
}
})
})
If you provide input data and expected output table, I can edit the answer to be more precise.