How to exit downloadHandler when file doesn't exist - r

I have a Shiny app with a downloadButton, which enables the user to download some log files.
As the logfiles are also handled by logrotate, it might be that at a certain time no logfile exists, which currently breaks the app when trying to download it.
How can I prevent that? Or how can I display a modalDialog with the information, that no log-file currently exists?
I tried to include req(F) or return(FALSE) but they don't work.
The current approach works, as I create an empty data.frame which is then exported, but it's not a very nice solution.
library(shiny)
library(data.table)
## Write random log file. Uncomment the next line to make the example work.
#fwrite(x = iris, file = "logs.log")
ui <- fluidPage(
downloadButton("showLogs", label="", title="Logs herunterladen", icon = icon("book-open"))
)
server <- function(input, output, session) {
output$showLogs <- downloadHandler(
filename = function() {
paste('logs-', Sys.Date(), '.csv', sep='')
},
content = function(file) {
logfile <- list.files(path = ".", pattern = basename("logs.log"))
if (length(logfile) != 0) {
logfile <- fread(logfile, sep = ";", header = F)
fwrite(logfile, file, sep = ";", row.names = FALSE)
} else {
## Problem is in here
# req(F)
# return(FALSE)
fwrite(data.frame("No log-Files"), file, sep = ";", row.names = FALSE)
}
}
)
}
shinyApp(ui, server)

Here is a solution without reactiveTimer.
library(shiny)
library(data.table)
library(shinyjs)
## Write random log file. Uncomment the next line to make the example work.
#fwrite(x = iris, file = "logs.log")
ui <- fluidPage(
useShinyjs(),
downloadButton("showLogs", label="", style = "display:none;"),
actionButton("btn", "Download")
)
server <- function(input, output, session) {
observeEvent(input$btn, {
logfile <- list.files(path = ".", pattern = basename("logs.log"))
if(length(logfile)){
runjs("$('#showLogs').click();")
}
})
output$showLogs <- downloadHandler(
filename = function() {
paste('logs-', Sys.Date(), '.csv', sep='')
},
content = function(file) {
logfile <- list.files(path = ".", pattern = basename("logs.log"))
logfile <- fread(logfile, sep = ";", header = F)
fwrite(logfile, file, sep = ";", row.names = FALSE)
}
)
}
shinyApp(ui, server)

This app throws an alert if you click the button while no log file exists, and there's no download.
library(shiny)
library(data.table)
library(shinyjs)
## Write random log file. Uncomment the next line to make the example work.
#fwrite(x = iris, file = "logs.log")
ui <- fluidPage(
useShinyjs(),
downloadButton("showLogs", label="", title="Logs herunterladen", icon = icon("book-open"))
)
server <- function(input, output, session) {
autoInvalidate <- reactiveTimer(1000)
observe({
autoInvalidate()
logfile <- list.files(path = ".", pattern = basename("logs.log"))
if(length(logfile)){
runjs("$('#showLogs').off('click.x')")
}else{
runjs("$('#showLogs').off('click.x').on('click.x', function(e){alert('No log file'); e.preventDefault();})")
}
})
output$showLogs <- downloadHandler(
filename = function() {
paste('logs-', Sys.Date(), '.csv', sep='')
},
content = function(file) {
logfile <- list.files(path = ".", pattern = basename("logs.log"))
logfile <- fread(logfile, sep = ";", header = F)
fwrite(logfile, file, sep = ";", row.names = FALSE)
}
)
}
shinyApp(ui, server)

Related

Having Trouble Getting Download Handler in Shiny to Work

I am trying to build a shiny platform that can take in an input file, paste the output into a table on display, and then have a download button to download the results of the file back to your computer. I've tried numerous different ways, and it hasn't worked.
UI Code:
tabItem(tabName = "home",
h2("Cancer Publications Compiler"),
sidebarLayout(position = "left",
# File Upload
sidebarPanel(
radioButtons("data_t", "Select the Data Type Here",
c(Excel = ",", "Text = "\t")),
fileInput("data_f", "Upload Your Data Here")),
# Download Input
mainPanel(width = 8,align = "center",
div(style = "border:1px black solid;width:90%;font-size:10px;",tableOutput("out_chart")),
downloadButton("downloadData", "Download")))
),
Server:
fileext = reactive({
switch(input$data_t,
"Excel" = "csv", "Text" = "txt")
})
## Create Output for file selector ##
data_file <- reactive({
if(is.null(input$data_f)){return()}
else{
file_spec <- input$data_f
aa <- read.table(file_spec$datapath, header = TRUE, sep = input$data_t)
return(aa)
}
})
# Connects the input and output to launch the data table
## Create Output for table from tool ##
output$out_chart <- renderTable({
if(is.null(input$data_f)){return()}
else {
data_file()
}
})
output$donwloadData <- downloadHandler(
filename = function(){
paste("data-", fileext(), sep = ".")
},
content = function(file){
sep <- switch(input$data_t, "Excel" = ",", "Text" = "\t")
write.table(data_file(), file, sep = sep,
row.names = FALSE)
})
Can anyone help me with a fix for this problem so that the download handler will work how I want it to?
UPDATE: I have edited the code and have updated it on here. My problem now is that when I click download to download the outputted table, I am getting a .htm download of a very low rendered and weird looking version of my webpage.
You had some typos, and other issues. Try this
ui <- fluidPage(
tabItem(tabName = "home",
h2("Cancer Publications Compiler"),
sidebarLayout(position = "left",
# File Upload
sidebarPanel(
radioButtons("data_t", "Select the Data Type Here", c("Excel" = "csv", "Text" = "txt")) ,
fileInput("data_f", "Upload Your Data Here")
),
# Download Input
mainPanel(width = 8,align = "center",
div(style = "border:1px black solid;width:90%;font-size:10px;",tableOutput("out_chart")),
downloadButton("downloadData", "Download"))
)
)
)
server<- function (input, output, session) {
sep <- reactive({
req(input$data_t)
switch(input$data_t,
"csv" = ",", "txt" = "\t")
})
## Create Output for file selector ##
data_file <- reactive({
if(is.null(input$data_f)){return()}
else{
file_spec <- input$data_f
aa <- read.table(file_spec$datapath, header = TRUE, sep = sep())
return(aa)
}
})
# Connects the input and output to launch the data table
## Create Output for table from tool ##
output$out_chart <- renderTable({
print(input$data_t)
if(is.null(input$data_f)){return()}
else {
data_file()
}
})
output$downloadData <- downloadHandler(
filename = function(){
paste("data-", input$data_t, sep = ".")
},
content = function(file){
write.table(data_file(), file, sep = sep(), row.names = FALSE)
}
)
}
shinyApp(ui = ui, server = server)

file.copy, loadworkbook not working in R shiny reactive environment but working outside reactive environment

I have created the following app to read an excel file from the temp folder in R. I would like to retain the file format in R shiny
library(XLConnect)
library(shiny)
library(openxlsx)
library(readxl)
ui <- fluidPage(
titlePanel("Writer App"),
sidebarLayout(sidebarPanel(fileInput(inputId = "file", label = "Read File Here", accept = c(".xlsx")), downloadLink("downloadData", "Download")), mainPanel(dataTableOutput(outputId = "table1"))))
server <- function(input, output) {
datasetInput <- reactive({
infile<- input$file
if (is.null(infile))
return(NULL)
#READ .XLSX AND .CSV FILES
if(grepl(infile, pattern = ".xlsx" )==T){data=read_excel(infile$datapath)} else
if(grepl(infile , pattern = ".csv" )==T){data=read.csv(infile$datapath )}
#RENAME DATAFRAME WITH UNDERSCORES
names(data)<-gsub(pattern = " ", replacement = "_", x = names(data))
return(data) })
output$table1 <- renderDataTable({
return(datasetInput())})
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".xlsx", sep="")},
content = function(file) {
tf<-tempdir()
Files=list.files(path=tf, pattern=".xlsx", recursive = TRUE)[1]
file.copy(from =paste0(tf, "/",Files ), to= "temp_1.xlsx")
wb2 <- loadWorkbook(file = "temp_1.xlsx")
df_1<-data.frame("DF"= c(1:3))
addWorksheet(wb = wb2,sheetName = "Parameters1")
writeData(wb2, "Parameters1", df_1, startCol = 1, startRow = 2, rowNames = TRUE)
saveWorkbook(wb2, file)})
}
shinyApp(ui = ui, server = server)
The Download button(output$downloadData) has a command to copy the file including the format from a temporary location to a new file temp.xlsx. this file is next loaded as workbook. a New sheet Parameters1 is added to the workbook wb2. Next, data frame(df_1) is written to sheet Parameters1 and the file is downloaded.
Now, the code within the output$downloadData works in the R console but doesnt work in the reactive environment of R shiny.
There seems to be an error in loadworkbook command. I am able to get the file by means of read_excel and then inserting the data. That however doesnt prserve the format of the loaded excel sheet. I request someone to guide me in this.
This works for me without any error.
library(shiny)
library(openxlsx)
library(readxl)
ui <- fluidPage(
titlePanel("Writer App"),
sidebarLayout(sidebarPanel(fileInput(inputId = "file", label = "Read File Here", accept = c(".xlsx")), downloadLink("downloadData", "Download")),
mainPanel(dataTableOutput(outputId = "table1"))))
server <- function(input, output) {
datasetInput <- reactive({
infile<- input$file
if (is.null(infile))
return(NULL)
#READ .XLSX AND .CSV FILES
if(grepl(infile$datapath, pattern = ".xlsx" )){data=read_excel(infile$datapath)} else
if(grepl(infile$datapath , pattern = ".csv" )){data=read.csv(infile$datapath )}
#RENAME DATAFRAME WITH UNDERSCORES
names(data)<-gsub(pattern = " ", replacement = "_", x = names(data))
return(data)
})
output$table1 <- renderDataTable({
return(datasetInput())})
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".xlsx", sep="")},
content = function(file) {
tf<-tempdir()
Files=list.files(path=tf, pattern=".xlsx", recursive = TRUE)[1]
file.copy(from =paste0(tf, "/",Files ), to= "temp_1.xlsx")
wb2 <- loadWorkbook(file = "temp_1.xlsx")
df_1<-data.frame("DF"= c(1:3))
addWorksheet(wb = wb2,sheetName = "Parameters1")
writeData(wb2, "Parameters1", df_1, startCol = 1, startRow = 2, rowNames = TRUE)
saveWorkbook(wb2, file)
})
}
shinyApp(ui = ui, server = server)
The issue is solved with the use of xlconnect package. Here is the code I employed
library(XLConnect)
library(shiny)
library(readxl)
ui <- fluidPage(
titlePanel("Writer App"),
sidebarLayout(sidebarPanel(fileInput(inputId = "file", label = "Read File
Here", accept =c(".xlsx")), downloadButton("downloadData", "Download")),
mainPanel(dataTableOutput(outputId = "table1"))))
server <- function(input, output) {
datasetInput <- reactive({
infile<- input$file
if (is.null(infile))
return(NULL)
#READ .XLSX AND .CSV FILES
if(grepl(infile, pattern = ".xlsx" )==T){
data=read_excel(infile$datapath)
} else if(grepl(infile , pattern = ".csv" )==T)
{data=read.csv(infile$datapath )}
#RENAME DATAFRAME WITH UNDERSCORES
names(data)<-gsub(pattern = " ", replacement = "_", x = names(data))
return(data) })
output$table1 <- renderDataTable({
return(datasetInput())})
output$downloadData <- downloadHandler(
filename = function() {
"file.xlsx"},
content = function(file) {
wdf<-getwd()
tf<-tempdir()
Files=list.files(path=tf, pattern=".xlsx", recursive = TRUE)[1]
newWB <- loadWorkbook(filename=paste0(tf,"/",Files),create=TRUE)
createSheet(object = newWB,name='Parameters')
writeWorksheet(newWB,data=data.frame("X"=c(1:10),"Y"=
c(1:10)),sheet='Parameters',header=TRUE,rownames=NULL)
saveWorkbook(object = newWB, file = file)})
}
shinyApp(ui = ui, server = server)
Note: I have commented openxlsx to avoid incompatibility between openxlsx and xlconnect. Another change involves the removal of xlsx package as this is also incompatible with xlconnect

R Shiny download xlsx after resolving a promise

Could you please give an insight of why my future-promised data table object causes a failure when trying to save it with downloadHandler and write.xlsx2?
I have working everything else in such fashion:
## Server processing
shinyServer(
function(input, output, session)
{
options(java.parameters = "- Xmx1024m")
library(DT)
library(data.table)
library(magrittr)
library(ggplot2)
library(highcharter)
library(lubridate)
library(future)
library(promises)
library(xlsx)
dt_materials <- eventReactive(
input$run_materials,
{
plan(multiprocess)
## reactive values
dat_func <- function()
{
## Data processing
## Return
list(
output_tbl
, plo1
, paste0('Время обработки: ', round(Sys.time() - start_time), ' сек.')
, output_tbl_private
, dat_full
)
}
## launch future
future({
dat_func()
})
})
## Output
output$downloadDataMaterials <-
downloadHandler(
filename = "tass_ru_materials.xlsx",
content = function(file)
{
dat_full <- dt_materials() %...>% `[[`(5)
write.xlsx2(x = dat_full, file = file, sheetName = 'materials', row.names = FALSE)
}
)
})
I get a server fault:
However, a simple example works fine when I change the content function:
content = function(file)
{
dat_full <- data.table(x=1:10)
write.xlsx2(x = dat_full, file = file, sheetName = 'materials', row.names = FALSE)
}
I made this work using a blocking resolution, looks enough for now.
output$downloadDataMaterials <-
downloadHandler(
filename = "tass_ru_materials.xlsx",
content = function(file)
{
dat_full <- value(dt_materials())[[5]]
write.xlsx2(x = dat_full, file = file, sheetName = 'materials', row.names = FALSE)
}
)

Replace NAs with blank space instead of " " in a downloaded file of a shiny app

I have a simple shiny app from which I download a txt file. The issue is that I want to replace NAs in my dataframe with total blank space instead of "". I use data[is.na(data)] <- ""
d1<-c("a","","b")
d2<-c("a","a","b")
d3<-c("","","b")
d4<-c("a","c","b")
d5<-c("","b","b")
NN2<-data.frame(Name,d1,d2,d3,d4,d5)
app
ui <- fluidPage(
downloadLink("downloadData", "Download")
)
server <- function(input, output) {
# Our dataset
data <- NN2
data[is.na(data)] <- ""
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".txt", sep="")
},
content = function(file) {
write.table(data, file)
}
)
}
shinyApp(ui, server)
Does this help :
write.table(data, file, na = "", quote = FALSE, row.names = FALSE)

R Shiny downloadHandler() save nothing

in the ui.R nothing is different
shinyUI(fluidPage(
downloadButton('downloadData','Save Results')
)
)
in the server.R
output$downloadData <- downloadHandler(
filename = function () { paste0("output", ".xlsx", sep='') },
content = function (file) {
fname <- paste(file,"xlsx",sep=".")
write.xlsx2(Correlation.df,fname ,"Correlation",row.names = FALSE)
write.xlsx2(Covariance.df, fname, "Covariance",row.names = FALSE,append = TRUE)
file.rename(fname, file)
}
)
The problem is there can launch a save window with the correct file name, but nothing is saved.
Thanks in advance.
Your downloadHandler does not provide a content function. This works for me:
library(shiny)
library(xlsx)
app <- shinyApp(
ui = fluidPage(
downloadLink('downloadData', 'Download')
),
server = function(input, output) {
df1 <- data.frame(
A = 1:5, Source = "df1",
stringsAsFactors = FALSE
)
df2 <- data.frame(
A = 6:10, Source = "df2",
stringsAsFactors = FALSE
)
output$downloadData <- downloadHandler(
filename = function(file) {
paste0("samplefile", ".xlsx")
},
content = function(con) {
write.xlsx2(df1, con, sheetName = "df1", row.names = FALSE)
write.xlsx2(df2, con, sheetName = "df2", row.names = FALSE, append = TRUE)
}
)
}
)
runApp(app)

Resources