Shiny R renderDataTable with null table - r

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)
})

Related

How to store data files on DropBox

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.

R/Shiny: Download multiple files (zip) from a folder on the server

I would like to create a zip archive (containing several xlsx files) and save it locally. The files are stored in a folder on the server side.
The user selects the files to zip using a checkboxInput.
Here the code for the checkbox:
get.files <- reactive({
list.files("output_file/")
})
obsList <- list()
output$links_list <- renderUI({
lapply(as.list(1:length(get.files())), function(i)
{
btName <- get.files()[i]
# creates an observer only if it doesn't already exists
if (is.null(obsList[[btName]])) {
obsList[[btName]] <<- btName
}
fluidRow(checkboxInput(btName, get.files()[i]) )
})
})
The checkboxes are created dynamically reading the content in the folder ("output_file/"). Near each checkbox there is the name of the file.
The function for the download is:
output$downloadzip<-downloadHandler(
filename = function(){
paste0("Extract.zip")
},
content = function(file){
files <- NULL;
for (i in 1:length(obsList)){
if(input[[obsList[[i]]]])
files <- c(paste("output_file/",obsList[[i]],sep=""),files)
}
#create the zip file
zip(file,files)
},
contentType = "application/zip"
)
The function creates an array of filenames (files) using only the names of files that have been checked.
I have created also a function that allows me to check that only the right files are chosen:
tempText <- eventReactive({input$TempTest},{
l<-c()
for (i in 1:length(obsList)){
if(input[[obsList[[i]]]])
l<-c(l,paste("output_file/",obsList[[i]],sep=""))
}
return(paste(l) )
},
ignoreInit = TRUE)
output$Temp <- renderPrint({ tempText()})
This function renders correctly the strings with the name of the files.
The error that I get when I try to download the zip file is:
sh: : command not found
Can someone help me to fix this?
I have fixed the problem.
The issue is with the zip function that for some reasons doesn't work properly on my server.
The solution is to use directly the system2 function (that is called internally by zip).
Instead of
zip(file,files)
I have to use:
system2("zip", args=(paste(file,files,sep=" ")))

'file' must be a character string or connection

I'm trying to create a shiny app that uploads a table, runs a function, and displays a graph and table. The uploading file works fine, but I am unable to run the function and output the graph and table (We shall only focus on the table for now). I am presented with the error:
Warning: Error in read.table: 'file' must be a character string or connection
I have run the function separately in R, and works fine with the desired output. I have tried different read functions, and different separators/delimiters, and read the function in the reactive renderPlot function (as described in a previous post here). Below is a snippet of the code I've been working on:
ui.R:
fileInput("file1",
"Load Input File",
accept = c("text/csv", "text/comma-separated-values,text/plain",".csv")
)
server.R:
execute = observeEvent(input$runButton, {
output$plot1 = renderPlot({
inFile = input$file1
if (is.null(inFile)) {
print(NULL)
}
podr_fun_graphs(inFile$datapath)
})
}
podr_graphs function:
podr_fun_graphs <- function(p) {
df1 <- read.delim(p, sep = "\t")
... # From here there is some data cleaning and manipulation of df1
}
Code similar to this was working a few weeks ago, I made some small changes and it then broke. Would appreciate any help to fix this.
Thanks
the problem is in your if statement. You have written print(NULL). But it should be:
if (is.null(inFile)) {
return(NULL)
}
R will go on to execute podr_fun_graphs(inFile$datapath) if you don't specify return.

Re-upload same file shiny R

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.

How to upload a file and name the columns in Shiny in R?

Goal
To upload a file in a Shiny app that reads the data, name the variables (columns) and do some data analysis before presenting plot output
Reference Shiny App
I am using this app from Shiny gallery as a reference: enter link description here
What I have tried:
I want to use the uploaded data in many outputs after doing different analyses. So, instead of reading file inside renderTable or renderPlot, I read it in server function:
server <- function(input, output) {
inFile <- reactive({input$file1})
sdf <- reactive({read.csv(inFile()$datapath, header=F)})
colnames(sdf()) <- c('Vehicle.ID', 'Time', 'Vehicle.class.no', 'Vehicle.type2',
'Vehicle.Length', 'Lane', 'Preceding.Vehicle.ID', 'Spacing','Spacing2', 'State',
'svel.mps', 'deltaV.mps', 'sacc', 'lane.change') }
Error
But when I run this app I get:
shiny::runApp('app-CC')
Listening on http://127.0.0.1:7484
Error in colnames(sdf()) <- c("Vehicle.ID", "Time", "Vehicle.class.no", :
invalid (NULL) left side of assignment
Question
How can I fix this error? I don't want to read the same file again in every render* function. Are there any online examples of shiny apps where a new file is read, column names are defined and then some analysis is done before using the render* functions?
You'd be better off assigning the column names during the read.csv
server <- function(input, output) {
inFile <- reactive({input$file1})
sdf <- reactive({
read.csv(inFile()$datapath, header=F, col.names = c('Vehicle.ID', 'Time', 'Vehicle.class.no', 'Vehicle.type2',
'Vehicle.Length', 'Lane', 'Preceding.Vehicle.ID', 'Spacing','Spacing2', 'State',
'svel.mps', 'deltaV.mps', 'sacc', 'lane.change')
)
})
}
Alternatively I believe you can perform multiple operations in the reactive block as long as you return the final object
server <- function(input, output) {
inFile <- reactive({input$file1})
sdf <- reactive({
dd<-read.csv(inFile()$datapath, header=F)
colnames(dd) <- c('Vehicle.ID', 'Time', 'Vehicle.class.no', 'Vehicle.type2',
'Vehicle.Length', 'Lane', 'Preceding.Vehicle.ID', 'Spacing','Spacing2', 'State',
'svel.mps', 'deltaV.mps', 'sacc', 'lane.change')
)
dd
})
}
An alternative is to use an actionButton and then to check for the validity of the files when you upload them. Lots of observeEvent is probably appropriate for firing off when something is "triggered," like a file being uploaded or a button being pressed. In addition, to make a chain of changes, it's probably best to have an "update" reactiveValue() thing to fire based on flags (which, I admit, is kind of messy, but works with Shiny since it doesn't have a proper callback framework like JS.)

Resources