The download handler is a remarkably popular shiny tool - even for local work. However it is quite annoying when it opens up all the time in the R-Studio directory. Here is the current example program from the Shiny documantion.
library(shiny)
## Only run examples in interactive R sessions
if (interactive()) {
ui <- fluidPage(
downloadLink("downloadData", "Download")
)
server <- function(input, output) {
# Our dataset
data <- mtcars
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(data, file)
}
)
}
shinyApp(ui, server)
}
It opens like this:
A few related questions:
Is there anyway to override that directory to something more reasonable?
Can I specify the default name anywhere (the default is a bit bizarrely take from the name of the output list name).
Any insights as to why this is so would be welcome. There seems to be nothing in the docs around this.
Related
I'm building a Shiny App where users complete a survey, and based on their responses, it suggests different templates for them to use. The templates are all excel files that are heavily formatted (e.g., have pictures on them, misaligned headings, etc.), like the screenshot that I've uploaded here. Unfortunately, stackoverflow won't let me upload the excel file to make this fully reproducible, but if you can run it with any non-tabular excel file, it'll work.[![enter image description here][1]][1]
These templates are all uploaded to the server, and the users input does not affect them. I've tried following the example by others, like this [one][2], but I keep getting errors.
How do I get it so when users click the download button, they get the excel file exactly as it appears?
library(readxl)
library(shiny)
library(writexl)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
),
mainPanel(
downloadButton("downloadData", "Download Fancy Excel File")
)))
server <- function(input, output) {
output$downloadData <- downloadHandler(
filename = function() {
paste("file", "xlsx", sep='')
},
content = function(file) {
myfile <- srcpath <- 'Home/Other Layer/Fancy Template.xlsx'
file.copy(myfile, file)
}
)
}
# Run the application
shinyApp(ui = ui, server = server)
~~~~
[1]: https://i.stack.imgur.com/FK034.png
[2]: https://stackoverflow.com/questions/39449544/shiny-download-an-excel-file
You are missing a . in the file name. Also, you can keep all the files you want the users to download in www folder. The following works for me.
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
),
mainPanel(
downloadButton("downloadData", "Download Fancy Excel File")
)))
server <- function(input, output) {
output$downloadData <- downloadHandler(
filename = function() {
paste("testfile", ".xlsx", sep='')
},
content = function(file) {
# myfile <- srcpath <- 'Home/Other Layer/Fancy Template.xlsx'
myfile <- srcpath <- "./www/test141.xlsx"
file.copy(myfile, file)
}
)
}
# Run the application
shinyApp(ui = ui, server = server)
I have met an issue when I try to implement a download button in Shiny App. Every time I run the app, it will only show me an HTML file not the actual content file. Here is my code for both the server and UI parts.
library(shiny)
library(reticulate)
shinyServer(function(input,output){
reticulate::source_python("function.py")
data_xi <- run_xi(26)
output$downloadData <- downloadHandler(
filename = function(){
paste(Sys.time(), 'site_mtx.xlsx')
},
content = function(file){
write_xlsx(data_xi, file)
}
)
})
Here is the UI:
library(shiny)
shinyUI(fluidPage(
downloadButton("downloadData", "Download Metrics Reports")
))
I just tried to use the reticulate function in my python file and save the processed dataframe to Shiny App which can be downloads, thank you very much!
I ran an example out of your code with some adjustions (unfortunately i don't have your file) and it downloads normally a xlsx file. Add the data.frame( run_xi(26))and if this is not the problem maybe the "writexl" library can be the solution.
Hope it will help.
library(shiny)
library(reticulate)
library(writexl)
if (interactive()) {
ui <-fluidPage(
downloadButton("downloadData", "Download Metrics Reports")
)
server <- function(input,output){
data_xi <- data.frame(s = c(1:3),r = c(4:6), x =c(19:21))
output$downloadData <- downloadHandler(
filename = function(){
paste(Sys.time(), 'site_mtx.xlsx')
},
content = function(file){
write_xlsx(data_xi, file)
}
)
}
shinyApp(ui, server)
}
I am not good at English, so sentences may be wrong.
I want to distribute excel files prepared in advance to users. Is it possible to realize such a system with shiny? No problem with .zip.
Thank you
ui.R
shinyUI(
fluidPage(
downloadButton('downloadData', 'Excel Download')
)
)
server.R
shinyServer(function(input, output) {
output$downloadData <- downloadHandler(
filename = "distribution.xlsx",
content = "distribution_excel"
)
})
Yes, it is possible and you were nearly there. Below is a minimal working example. I assume that your .xlsx file is located in the same folder as your app.R. Notice that I have created the app in a single R file as opposed to two separate files.
The trick to getting the file to download is to use a function for the content inside of downloadHandler(). Specifically we are using the base function file.copy(). Clicking the button should now download the file: distribution.xlsx. This file can obviously be exchanged with a zip file.
If you want different users to access different Excel files, you can write an additional function inside of your server function that passes the file argument to the downloadHandler().
# Load packages ----
pkgs <- c("shiny")
invisible(lapply(pkgs, require, character.only = TRUE))
# Set up the UI ----
ui <- fluidPage(
# Define your download button
downloadButton(
outputId = "downloadData",
label = "Excel Download"
)
)
# Set up the server side ----
server <- function(input, output, session) {
# Define the download handler with function() for content.
output$downloadData <- downloadHandler(
filename = "distribution.xlsx",
content = function(file) {
file.copy("distribution.xlsx", file)
}
)
}
# Combine into an app ----
shinyApp(ui = ui, server = server)
I'm building an app that operates regularly when nothing is given in a url query, however if a certain string is given there it should download the file immediately. The download works fine, but when it is run at start up it return a 'download.htm' file instead of the .csv. The reproducible example is not querying the url, but triggers in an observe:
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs()
,downloadButton("downloadData", "Download")
)
server <- function(input, output) {
data <- mtcars
observe({
print("click MacClickFace")
runjs("document.getElementById('downloadData').click();")
})
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(data, file)
}
)
}
shinyApp(ui, server)
How can you trigger the download at launch or are there some security things going on here?
Probably the downloadHandler is not ready. You can use a setTimeout(..., 0):
runjs("setTimeout(function(){document.getElementById('downloadData').click();},0);")
My "download" button does not work as expectation. It opens a new app window every time I click on it. I am wondering why it functions in this way?
download function in server.R:
output$down_load <- downloadHandler(
# specify the file name
filename = function() {
paste('cls_result_export', Sys.Data(),'.csv', sep='')
},
# Write the plot back
content = function(file){
write.csv(cls_output()$raw_data, file)
}
)
download function in ui.R:
downloadButton(outputId = "down_load", label = "Download the CLS Raw Data")
Try using an actionButton wired to an observe clause like this:
library(shiny)
ui <- fluidPage( actionButton("dodo", "Download" ) )
server <- function(input, output)
{
observe({
if (input$dodo>0){
fname <- paste0('cls_result_export', Sys.Date(),'.csv')
write.csv(mtcars,fname)
}
})
}
shinyApp(ui = ui, server = server)
Another possible way to try to fix this issue, is to include this line in your server.R script:
outputOptions(output, 'down_load', suspendWhenHidden=FALSE)