I have multiple tables in reactive objects in my shiny app (RA_s,Per), and I download each separately. Now, I'm trying to download one zip file containing all of this tables using a download button.
Here is my code, I don't know how to complete downloadHandler function. I want to download a zip file which contain 2 csv files RA_s and Per.
Code
shinyServer(function(input, output) {
RA_s <- reactive({
iris
})
Per <- reactive({
sepal1 <- RA_s()["Sepal_Length"]
sepal2 <- RA_s()["Sepal_Width"]
value = sepal1*sepal2
c = cbind(RA_s(),value)
})
output$downloadData <- downloadHandler(
filename = function() {
paste0("output", ".zip")
},
content = function(file) {
...
})
})
sidebar <- dashboardSidebar(
sidebarMenu(
menuItem("Download", tabName = "d")
)
body<- dashboardBody(
tabItems(
tabItem(tabName = "d",
downloadButton('downloadData', 'Download')
)
)
dashboardPage(
dashboardHeader(title = "Valo"),
sidebar,
body
)
You can first save the zip files, and then zip them, as follows:
library(shiny)
server<- shinyServer(function(input, output) {
RA_s <- reactive({
iris
print(iris)
})
Per <- reactive({
sepal1 <- RA_s()["Sepal.Length"]
sepal2 <- RA_s()["Sepal.Width"]
value = sepal1*sepal2
c = cbind(RA_s(),value)
})
output$downloadData <- downloadHandler(
filename = 'two_csvs.zip',
content = function(fname) {
write.csv(RA_s(), file = "csv1.csv", sep =",")
write.csv(Per(), file = "csv2.csv", sep =",")
zip(zipfile=fname, files=c("csv1.csv","csv2.csv"))
},
contentType = "application/zip"
)
})
ui<- shinyUI(
downloadButton('downloadData', 'Download')
)
shinyApp(ui,server)
You can specify a subdirectory of course, to keep your directory clean. Hope this helps!
Related
I am working on a data cleaning app. The app is supposed to take a file from the user clean it, and be able to download the cleaned data. For some reason my app will only download the html of the app and not a csv. Any Help would be awesome. Here is what I have so far.
The interface is asking me to add more details but this is all I got
ui.R
library(shiny)
library(DT)
###Allows up to 60 mgs of data
options(shiny.maxRequestSize = 60*1024^2)
navbarPage(
"Astute App",
tabPanel(
"Clean Data",
fluidRow(
fileInput('target_upload', 'Choose file to upload',
accept = c(
'text/csv',
'text/comma-separated-values',
'.csv'
)),
radioButtons("separator","Separator: ",choices = c(";",",",":"), selected=",",inline=TRUE),
DT::dataTableOutput("sample_table")),
downloadButton("cleaned_data", label = "Download Data"),
),
tabPanel(
"Time Series Analysis",
fluidPage(
)
),
tabPanel(
"Prediction",
fluidPage(
)
),
collapsible = TRUE
)
The interface is asking me to add more details but this is all I got
server.R
library(shiny)
library(DT)
###Allows up to 60 mgs of data
options(shiny.maxRequestSize = 60*1024^2)
function(input, output, session){
########Reads in uplaoded Data
df_products_upload <- reactive({
inFile <- input$target_upload
if (is.null(inFile))
return(NULL)
df <- read.csv(inFile$datapath, header = TRUE,sep = input$separator)
return(df)
})
######Clean the data#####
Cleaned_data <- df
download_cleaned_data <- downloadHandler(
filename = Cleaned_data,
content = function(file){
file.copy("data/", file)}
)
###Displays Uploaded data unclean
output$sample_table<- DT::renderDataTable({
df <- df_products_upload()
DT::datatable(df)
})
}
Not sure what else to add
A couple of issues in the downloadHandler section. It should look like this:
output$cleaned_data <- downloadHandler(
filename = "mydata.csv",
content = function(file) {write.csv(df_products_upload(), file)}
)
Here is a minimal working example, showing uploading and downloading a file:
library(shiny)
ui <- fluidPage(
#Select file
fileInput('myfileinput', 'Choose file to upload'),
#Download file
downloadButton("myfiledownload", label = "Download file"),
#Data table of loaded file
tableOutput("mydatatable")
)
server <- function(input, output, session) {
#Create a reactive dataframe to hold our loaded file
df_fileuploaded <- reactive({
#If no file selected set the dataframe to null and exit
if (is.null(input$myfileinput)) return(NULL)
#Load the selected file
return(read.csv(input$myfileinput$datapath))
})
#Download handler
output$myfiledownload <- downloadHandler(
filename = "mydata.csv",
content = function(file) {write.csv(df_fileuploaded(), file)}
)
#Data table
output$mydatatable <- renderTable({
df_fileuploaded()
})
}
shinyApp(ui, server)
Here is your full app with those changes:
ui.r
library(shiny)
library(DT)
###Allows up to 60 mgs of data
options(shiny.maxRequestSize = 60*1024^2)
navbarPage(
"Astute App",
tabPanel(
"Clean Data",
fluidRow(
fileInput('target_upload', 'Choose file to upload',
accept = c(
'text/csv',
'text/comma-separated-values',
'.csv'
)),
radioButtons("separator","Separator: ",choices = c(";",",",":"), selected=",",inline=TRUE),
DT::dataTableOutput("sample_table")),
downloadButton("cleaned_data", label = "Download Data"),
),
tabPanel(
"Time Series Analysis",
fluidPage(
)
),
tabPanel(
"Prediction",
fluidPage(
)
),
collapsible = TRUE
)
server.r
library(shiny)
library(DT)
###Allows up to 60 mgs of data
options(shiny.maxRequestSize = 60*1024^2)
function(input, output, session){
########Reads in uplaoded Data
df_products_upload <- reactive({
inFile <- input$target_upload
if (is.null(inFile))
return(NULL)
df <- read.csv(inFile$datapath, header = TRUE,sep = input$separator)
return(df)
})
output$cleaned_data <- downloadHandler(
filename = "mydata.csv",
content = function(file) {write.csv(df_products_upload(), file)}
)
###Displays Uploaded data unclean
output$sample_table<- DT::renderDataTable({
df <- df_products_upload()
DT::datatable(df)
})
}
My shiny app generates a table that I want to make available for download in a csv format.
ui = fluidPage( ...
tableOutput("contents"),
downloadButton("download", "Download results in csv format")
)
server <- function( input, output, session ) {
output$contents <- renderTable( ... )
output$download <- downloadHandler(
filename = function() {
paste(contents, ".csv", sep = "")
},
content = function(file) {
write.csv(contents(), file, row.names = FALSE)
}
)
I understand that I have to create a reactive object, but the renderTable itself uses another reactive object (uploaded dataset), so it looks like I need to nest one reactive object into another, and it does not seem to work. Will appreciate any help. Thank you!
EDIT: Added an example using renderTable instead of renderDataTable, as requested by the question and in the comment section:
Here is an example using the iris dataset. I also added a table from the DT package. You should not paste the data in the filename function, only in the in the write.csv function.
```{r}
library(shinydashboard)
library(dplyr)
library(DT)
```
setosa <- filter(iris, Species == "setosa")
ui = fluidPage(
downloadButton("download", "Download results in csv format") ,
column(12,
DT::dataTableOutput ("content"),
style = " overflow-y: scroll;overflow-x: scroll;")
)
server <- function(input, output, session) {
output$content <-
renderDataTable(head(setosa))
output$download <-
downloadHandler(
filename = function () {
paste("MyData.csv", sep = "")
},
content = function(file) {
write.csv(content, file)
}
)
}
shinyApp(ui, server)
```
Using renderTable instead of renderDataTable
library(shiny)
library(dplyr)
library(DT)
setosa <- filter(iris, Species == "setosa")
ui = fluidPage(
downloadButton("download", "Download results in csv format"),
tableOutput("table")
)
server <- function(input, output, session) {
data <- data.frame(setosa)
output$table <-
renderTable(data)
output$download <-
downloadHandler(
filename = function () {
paste("MyData.csv", sep = "")
},
content = function(file) {
write.csv(data, file)
}
)
}
shinyApp(ui, server)
I wonderif there is a way to download 2 dataframes in the same excel file but in different sheet via shiny app.
library(shiny)
library(xlsx)
ui <- shinyUI(fluidPage(
titlePanel("Testing File upload"),
sidebarLayout(
sidebarPanel(
downloadButton("dl","Export in Excel")
),
mainPanel(
)
)
))
server <- shinyServer(function(input, output) {
output$dl <- downloadHandler(
filename = function() {
paste0("df_dmodel", "_Table", ".xls")
},
content = function(file){
tbl<-iris
tbl2<-mtcars
write.xlsx(tbl,tbl2 file,
sheetName = "Sheet1", row.names = FALSE)
}
)
})
shinyApp(ui = ui, server = server)
try changing your server code to this. Also, remember to open the app in your browser and not just the rstudio viewer (assuming your are using rstudio). Hope this helps!
server <- shinyServer(function(input, output) {
output$dl <- downloadHandler(
filename = function() {
paste0("df_dmodel", "_Table", ".xlsx")
},
content = function(file){
tbl<-iris
tbl2<-mtcars
sheets <- mget(ls(pattern = "tbl")) # getting all objects in your environment with tbl in the name
names(sheets) <- paste0("sheet", seq_len(length(sheets))) # changing the names in your list
writexl::write_xlsx(sheets, path = file) # saving the file
}
)
})
An alternative to Andrew's answer using write.xlsx from openxlsx with a list of dataframes.
library(shiny)
library(openxlsx)
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
downloadButton("dl","Export in Excel")
),
mainPanel(
)
)
))
server <- shinyServer(function(input, output) {
output$dl <- downloadHandler(
filename = function() {
"test.xlsx"
},
content = function(filename){
df_list <- list(iris=iris, mtcars=mtcars)
write.xlsx(x = df_list , file = filename, row.names = FALSE)
}
)
})
shinyApp(ui = ui, server = server)
I am not sure if I am understanding this correctly. Where should the data set that I want to download be in RStudio server? I do not want to deploy yet, so I am not using the Shiny server, but I want to use the download functionality and save the data set as a file in a local directory.
I have uploaded a file using Shiny fileInput and I have saved the file using copy.file(). I was told that the uploaded file is saved to the server. The file is called 0.tsv. Afterwards, I read that file and download it. The GUI works, but the file doe not get written to a file and saved to the local directory. My question is: is there any thing missing in my approach?
library(shiny)
ui <- fluidPage(
titlePanel('File download'),
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("data")),
radioButtons("filetype", "File type:",
choices = c( "tsv")),
downloadButton('downloadData', 'Download')
),
mainPanel(
tableOutput('table')
)
)
)
function(input, output) {
datasetInput <- reactive({
# Fetch the appropriate data object, depending on the value
# of input$dataset.
data <- read.table("home/user/0.tsv")
switch(input$dataset,
"data" = data)
})
output$table <- renderTable({
datasetInput()
})
# downloadHandler() takes two arguments, both functions.
# The content function is passed a filename as an argument, and
# it should write out data to that filename.
output$downloadData <- downloadHandler(
# This function returns a string which tells the client
# browser what name to use when saving the file.
filename = function() {
paste(input$dataset, input$filetype, sep = ".")
},
# This function should write data to a file given to it by
# the argument 'file'.
content = function(file) {
sep <- switch(input$filetype, "tsv" = "\t")
# Write to a file specified by the 'file' argument
write.table(datasetInput(), file, sep = sep,
row.names = FALSE)
}
)
}
shinyApp(ui = ui, server = server)
ui <- fluidPage(
titlePanel('File download'),
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("data")),
radioButtons("filetype", "File type:",
choices = c( "tsv")),
downloadButton('downloadData', 'Download')
),
mainPanel(
tableOutput('table')
)
)
)
function(input, output) {
datasetInput <- reactive({
# Fetch the appropriate data object, depending on the value
# of input$dataset.
data <- read.table("home/user/0.tsv")
switch(input$dataset,
"data" = data)
})
output$table <- renderTable({
datasetInput()
})
# downloadHandler() takes two arguments, both functions.
# The content function is passed a filename as an argument, and
# it should write out data to that filename.
output$downloadData <- downloadHandler(
# This function returns a string which tells the client
# browser what name to use when saving the file.
filename = function() {
paste(input$dataset, input$filetype, sep = ".")
},
# This function should write data to a file given to it by
# the argument 'file'.
content = function(file) {
sep <- switch(input$filetype, "tsv" = "\t")
# Write to a file specified by the 'file' argument
write.table(datasetInput(), file, sep = sep,
row.names = FALSE)
}
)
}
shinyApp(ui = ui, server = server)
Thanks very much for your response. Below is the correct way to do it. This works fine.
server <- function(input, output) {
# Reactive value for selected dataset ----
datasetInput <- reactive({
switch(input$dataset,
"params" = params)
})
# Table of selected dataset ----
output$table <- renderTable({
datasetInput()
})
# Downloadable csv of selected dataset ----
output$downloadData <- downloadHandler(
filename = function() {
paste(input$dataset, ".csv", sep = "")
},
content = function(file) {
write.table(datasetInput(), file, row.names = FALSE)
}
)
}
Does anyone how to fix this error when I'm trying to find the degree of each vertex from the input file? Here's the Pajek file i want to import in and export the degree into CSV.
When I tried using a smaller input file. The renderTable works but when I tried with my file(which is in the link) it somehow keeps showing that error message and does not display on the tab set.
Here's what I've done so far:
ui.R
shinyUI(fluidPage(
titlePanel("Finding most influential vertex in a network"),
sidebarLayout(
sidebarPanel(
fileInput("graph", label = h4("Pajek file")),
downloadButton('downloadData', 'Download')
),
mainPanel( tabsetPanel(type = "tabs",
tabPanel("Table", tableOutput("view"))
)
)
)
))
server.R
library(igraph)
options(shiny.maxRequestSize=-1)
shinyServer(
function(input, output) {
filedata <- reactive({
inFile = input$graph
if (!is.null(inFile))
read.graph(file=inFile$datapath, format="pajek")
})
Data <- reactive({
df <- filedata()
vorder <-order(degree(df), decreasing=TRUE)
DF <- data.frame(ID=as.numeric(V(df)[vorder]), degree=degree(df)[vorder])
})
output$view <- renderTable({
Data()
})
output$downloadData <- downloadHandler(
filename = function() {
paste("degree", '.csv', sep='')
},
content = function(file) {
write.csv(Data(), file)
}
)
})
Also, I'm also not sure how to write to csv file from the data frame I've output.