I am trying to save the uploaded files (within my shiny app) to a remote dropBox. I have been trying to implement what I learned here: [https://shiny.rstudio.com/articles/persistent-data-storage.html ](Permanent Storage) but so far no luck.
What I need is to save and store these data files in a dropBox, and then (when needed) to show the datasets on the dashboard.
It looks a tricky task (at least for me, as I am new to shiny). Any support is very welcome!
Here it's a snippet of my code (on server):
#### To upload file and generate a Table ####
data <- reactive({
req(input$file)
ext <- tools::file_ext(input$file$name)
switch(ext,
csv = vroom::vroom(input$file$datapath, delim = ","),
tsv = vroom::vroom(input$file$datapath, delim = "\t"),
xlsx = read_excel(input$file$datapath, sheet = 1),
validate("Invalid file; Please upload a .csv, .tsv or excel file")
)
})
# When the Upload a File button is clicked, save the data
observeEvent(input$file, {
saveData(data())
})
# Show the table results on dashboard
output$table <- renderDataTable({
input$file
data()
# DropBox
loadData()
})
The functions loadData() and saveData() (they were taken from the link above) are defined before the ui and server pieces.
Related
ref: How to download workbook via downloadHandler on Shiny?
** Workbook is already held in the app's directory**
Does anyone have experience with putting in a download link into a shiny app for an excel file held in the app's directory? I have an excel form that I need users to be able to download and use (it is specifically NOT a dataframe).
The following code worked for when I put in a powerpoint file in the downloadHandler function:
output$downloadinflationguidance <- downloadHandler(
filename = function() {
paste("www/inflation-guidance - ", Sys.Date(), '.pptx', sep='')
},
content = function(con) {
pptx <- read_pptx("www/inflation-guidance.pptx")
print(pptx, target = con)
}
)
But when I swap out the powerpoint stuff for the excel form (see below) it doesn't work. When I run the app and click on the download link, the user gets an error saying "file not found". The excel file is held locally on the app in a folder titled "www". Am I missing a trick here?
shinyUI(
downloadLink("dl_excel_calc", label = "Excel Version")
)
shinyServer(function(input, output, session) {
output$dl_excel_calc <- downloadHandler(
filename = function() {
paste0("indexation_tool_excel -", Sys.Date(), ".xlsx", sep='')
},
content = function(con) {
xlsx <- read_excel('indexation_tool_excel.xlsx')
print(xlsx, target = con)
}
)
}
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)
What is the best way to only render a data table in shiny if data exists? Right now, I am getting the following error because I am telling shiny to render a data table, even when it is NULL.
Warning in file(file, "rt") :
cannot open file '\': No such file or directory
Warning: Error in file: cannot open the connection
My code is split like this, where I read the data once the user chooses a csv file. After a user chooses a csv file, the error goes away and everything works fine. How do I tell Shiny to not display a data table until a valid file is chosen?
filedata <- reactive({
if (is.null(input$file_selector)){
# User has not uploaded a file yet
return(NULL)
} else {
read.csv(paste0(parseDirPath(c(home = 'C:\\Users\\Ruben'), file_dir()),'\\',input$file_selector),skip=1)}
})
output$filetable <- renderDataTable({
filedata()
})
I've tried putting the output$filetable <- .... code after the read.csv... line in the filedata <- ... function, but that doesn't work either. What else should I be doing here?
You can use req() function, this will check whether the file the file is present or not then it will go to the proceding code
filedata <- reactive({
file <-input$file_selector
req(file)
read.csv(paste0(parseDirPath(c(home = 'C:\\Users\\Ruben'), file_dir()),'\\',file),skip=1)}
})
Please use req(), as shown below
filedata <- reactive({
req(input$file_selector)
read.csv(paste0(parseDirPath(c(home = 'C:\\Users\\Ruben'), file_dir()),'\\',input$file_selector),skip=1)
})
I'm trying to work on a project in shiny to compare images uploaded by user and that saved in my amazon s3 server.
while downloading from s3, I am using this:
save_object(object=xyz ,bucket = "xyz", file = paste0("www/",xyz,".jpg"))
I'm taking input as:
fileInput("image","upload the image")
My dataframe is like this:
a$name<- xyz
a$server_image<- paste0("<img src=",'"',"xyz.jpg",'"'," ","height=",'"',"300",'"',"></img>")
a$uploaded_image<- paste0("<img src=",'"',input$image$datapath,'"'," ","height=",'"',"300",'"',"></img>")
I'm trying to get output like below.
output$output_table<-DT::renderDataTable({DT::datatable(a,escape = FALSE)})
In this case, the image downloaded from aws s3 into "www/" directory is correctly showed in the table, but there is problem with viewing uploaded image.
I also tried to use file.copy on input$image to copy it to a folder "www", but it also doesn't work when I deploy the app.
How can I view an image taken using fileInput and View without using renderImage?
I'm suspecting that your app renders <img src=... before the file is copied in www.
A solution is to convert the image in its base64 encoding and then to render the table including the image from its base64 string.
library(shiny)
library(DT)
ui <- shinyUI(
fluidPage(
fileInput("image", "upload image"),
DT::dataTableOutput("table")
)
)
server <- shinyServer(function(input, output) {
base64 <- eventReactive(input$image, {
base64enc::dataURI(file=input$image$datapath, mime=input$image$type)
})
output$table <- DT::renderDataTable({
req(input$image)
dat <- data.frame(image = sprintf('<img src=%s height="300"></img>', base64()))
datatable(dat, escape=FALSE)
})
})
I am following the simple file upload example from shiny gallery, but with a slight modification. I am required to modify the csv files locally, and see the changes reflected on the UI. However, I believe that this is not possible unless we poll for any changes in the source.
Therefore, I simplify the problem, by allowing re-uploading of the file. But, this is also not happening in Shiny. Once a file "file1.csv" is uploaded, i cannot upload the same file again. I have to upload a different file "file2.csv" and then once again the original file "file1.csv".
This is just time consuming, and I am wondering if anyone has come across such an issue, and possibly found a solution for it.
Adding a jquery to clear the value of the fileInput does the trick.
...
fileInput("csvInput", "Upload CSV file", multiple = TRUE,
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
tags$script('$( "#csvInput" ).on( "click", function() { this.value = null; });'),
...
Actually it is one of the shortcomings of Shiny's fileInput module: it stays still if the same file was selected again, and there is no force-upload option built-in.
To enforce re-uploading, the basic idea is:
After each time uploading, keep the uploaded data in a reactiveValues as storage.
Apply a new fileInput to replace original one
Show a successfully upload message under new fileInput for a better user experience.
In ui.R,using
uiOutput('fileImport')
In server.R:
# reactive storage
v <- reactiveValues()
# fileInput index
v$fileInputIndex <- 1
updateFileInput <- function (name = NULL){
# update output with a new fileInput module
output$fileImport <- renderUI({
index <- isolate(v$fileInputIndex)
result <- div()
result <- tagAppendChild(
result,
fileInput(paste0('file', index), 'Choose CSV File',accept=c('text/csv','text/comma-separated-values,text/plain','.csv'))
)
# show a message of successful uploading
if(!is.null(name)){
result <- tagAppendChild(
result,
div(name," upload complete")
)
}
result
})
}
dataInputRaw <- reactive({
# equals to `input$file1` when initialized
inFile <- input[[paste0('file', v$fileInputIndex)]]
# TICKY PART:
# 1. If initialized, `inFile` and `v$data` are both `NULL`
# 2. After each uploading, new `fileInput` is applied and
# we want to keep previous updated data.
# It also prevent recursive creation of new `fileInput`s.
if (is.null(inFile)){
return(v$data)
}
# load as data frame
v$data <- data.frame(read.csv(inFile$datapath))
# if file successfuly uploaded, increate the index
# then upload `fileInput` with successful message
if (!is.null(v$data)){
v$fileInputIndex <- v$fileInputIndex + 1
updateFileInput(name = inFile$name)
}
# return data
v$data
})
# init
updateFileInput()
I have tested this snippet and it works.