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