I have a download handler (say 10 times) that needs to be put in shiny as shown below. So instead of writing it 10 times, I have written a function so that after passing 3 parameters, the render functions should get executed
Button 1
output$downloadData_sec1 <- downloadHandler(
filename = function() {
paste(str_replace("title",pattern = " ", "_"), Sys.Date(), ".csv", sep="_")
},
content = function(file) {
write.csv(display_data$asd, file)
}
)
Button 2
output$downloadData_sec2 <- downloadHandler(
filename = function() {
paste(str_replace("title2",pattern = " ", "_"), Sys.Date(), ".csv", sep="_")
},
content = function(file) {
write.csv(display_data$asd2, file)
}
)
function
download_function <- function (id, title, data){
output[["id"]] <- downloadHandler(
filename = function() {
paste(str_replace(title,pattern = " ", "_"), Sys.Date(), ".csv", sep="_")
},
content = function(file) {
write.csv(display_data[["data"]], file)
}
)
}
But looks like there is some error here . I get output not defined
Can anyone help me here?
Here's MWE showing how to implement the your function as a Shiny module. In the interests of brevity, I've limited myself to three instances of the module rather than ten. I've also generated random data within each instance of the module. You can make the obvious changes for your real use case.
Next time, please provide a MRE.
library(shiny)
# Download UI
demoUI <- function(id) {
ns <- NS(id)
wellPanel(
id,
tableOutput(ns("data")),
downloadButton(ns("downloadData"), "Download")
)
}
# Download server
demoServer <- function(id, title) {
moduleServer(
id,
function(input, output, session) {
# Generate some random data
d <- data.frame(X=runif(5), y=rnorm(5))
output$data <- renderTable({ d })
output$downloadData <- downloadHandler(
filename = function() {
paste(stringr::str_replace(title, pattern = " ", "_"), Sys.Date(), ".csv", sep="_")
},
content = function(file) {
write.csv(d, file)
}
)
}
)
}
# Main UI
ui <- function() {
fluidPage(
demoUI("demo1"),
demoUI("demo2"),
demoUI("demo3")
)
}
# Main server
server <- function(input, output, session) {
demoServer("demo1", "Random title")
demoServer("demo2", "Another title")
demoServer("demo3", "Something else")
}
shinyApp(ui, server)
Here's a screenshot of (part of) the app:
And of part of my Downloads folder after clicking each Download button and accepting the default filename:
And, finally, the contents of one of the CSV files:
Related
There is this piece of code in which basically from UI page in which I want to select the file names for through checkbox and after selecting those, then clicking on download button selected files will get downloaded. I am stuck at UI i am unable to get those checkboxes on UI.
its showing the output as
[object] [Object]
the code is below -
ui <- fluidPage(
verbatimTextOutput("links_list")
)
server <- function(input, output, session) {
get.files <- reactive({
list.files("/Users/harshmeetsingh/Downloads/")
})
obsList <- list()
output$links_list <- renderUI({
lapply(as.list(1:length(get.files())), function(i)
{
btName <- get.files()[i]
print(btName)
# creates an observer only if it doesn't already exists
if (is.null(obsList[[btName]])) {
obsList[[btName]] <<- btName
}
fluidRow(checkboxInput(btName, get.files()[i]) )
})
})
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"
)
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()})
}
shinyApp(ui=ui,server=server)
We can use checkboxGroupInput() to select all the files. input$files_chosen will be a list with all the filenames selected.
Notice that this app is showing the files in the home directory. This can be modified changing the path supplied in setwd().
app:
library(shiny)
#to use relative paths inside zip function
setwd('~')
ui <- fluidPage(
downloadButton('downloadzip'),
uiOutput("links_list")
)
server <- function(input, output, session) {
get.files <- reactive({
list.files()
})
output$links_list <- renderUI({checkboxGroupInput(inputId = 'files_chosen',
label = 'Choose Files',
choices = get.files())
})
output$downloadzip <- downloadHandler(
filename = function(){
"Extract.zip"
},
content = function(file){
#create the paths to look for the files.
files <- input$files_chosen
#create the zip file
zip(zipfile = file, files = files)
},
contentType = "application/zip"
)
}
shinyApp(ui=ui,server=server)
So I have this shiny app which includes a checkbox button:
library(bold)
library(stringr)
library(readr)
library(shiny)
library(shinyWidgets)
grades2<-function(groups,inputz,coordz){
taxon<-bold_seqspec(taxon=groups, format = "tsv")
taxon2<-taxon[taxon$species_name!=""|is.na(taxon$species_name),]
taxon2<-taxon2[!(taxon2$bin_uri == "" | is.na(taxon2$bin_uri)), ]
taxon2$base_number=str_count(taxon2$nucleotides, pattern="[A-Z]")
taxon2<-taxon2[taxon2$base_number>=inputz,]
if (coordz==TRUE){
taxon2<-taxon2[!(is.na(taxon2$lat)) | taxon2$country!="",]
}else{
taxon2<-taxon2
}
assign('taxon2',taxon2,envir=.GlobalEnv)
}
ui <- navbarPage(title=tags$h3("APP"),tabPanel(column(12,align="center",tags$h4("Download"),tags$br(),
sliderInput("seqsize", "Mininum number of base pairs for sequences in reference library:",min = 0, max = 1000, value = 500),textOutput("SliderText"),
checkboxInput("rmvpaises", "Remove records without data on country of origin or latitude", TRUE),
textInputAddon(inputId="taxa2",addon=icon("search"),width="500px",label=tags$h5(tags$strong("Enter the name of the taxonomic group or groups separated by commas, without spaces:")),placeholder="Example: Carnivora,Ursidae,Artiodactyla,Soricomorpha"),
downloadButton("downloadData_2","Download"))))
server <- function(input, output){
#sliderValues <- reactive({as.integer(input$seqsize)})
#output$values <- renderText({
# sliderValues()
#})
taxaInput_2 <- reactive({grades2(unlist(strsplit(input$taxa2, ",")),as.integer(input$seqsize),input$rmvpaises)})
output$downloadData_2 <- downloadHandler(
filename = function() {
paste(input$taxa2,sep_out=",", ".tsv")
},
content = function(file) {
shiny::withProgress(
value=10,
{
shiny::incProgress(10/10)
write_tsv(taxaInput_2(), file)
}
)
}
)
output$value <- renderText({ input$rmvpaises })
}
shinyApp(ui=ui,server=server)
For some reason while using the app, the check box is non-responsive. It doesn't change.
The input of the check box is being used in the initial function "grades2" and it is the "coordz" argument.
Thank you so much for any answer
You're missing the non-optional argument title for tabPanel. Consequently, it's using the column UI element as the title for the tab which I'm assuming is doing weird stuff with the z-index.
You need an observer to update the checkboxInput on the server side. The checkbox works fine in this code
grades2<-function(groups,inputz,coordz){
taxon<-bold_seqspec(taxon=groups, format = "tsv")
taxon2<-taxon[taxon$species_name!=""|is.na(taxon$species_name),]
taxon2<-taxon2[!(taxon2$bin_uri == "" | is.na(taxon2$bin_uri)), ]
taxon2$base_number=str_count(taxon2$nucleotides, pattern="[A-Z]")
taxon2<-taxon2[taxon2$base_number>=inputz,]
if (coordz) {
taxon2<-taxon2[!(is.na(taxon2$lat)) | taxon2$country!="",]
}else{
taxon2<-taxon2
}
assign('taxon2',taxon2,envir=.GlobalEnv)
}
ui <- navbarPage(title=tags$h3("APP"),tabPanel(value="Panel1" , column(12,align="center",tags$h4("Download"),tags$br(),
sliderInput("seqsize", "Mininum number of base pairs for sequences in reference library:",min = 0, max = 1000, value = 500),textOutput("SliderText"),
checkboxInput("rmvpaises", "Remove records without data on country of origin or latitude", TRUE),
textInputAddon(inputId="taxa2",addon=icon("search"),width="500px",label=tags$h5(tags$strong("Enter the name of the taxonomic group or groups separated by commas, without spaces:")),placeholder="Example: Carnivora,Ursidae,Artiodactyla,Soricomorpha"),
downloadButton("downloadData_2","Download"))))
server <- function(input, output, session){
#sliderValues <- reactive({as.integer(input$seqsize)})
#output$values <- renderText({
# sliderValues()
#})
observe({
updateCheckboxInput(session, "rmvpaises", value=input$rmvpaises)
})
taxaInput_2 <- reactive({grades2(unlist(strsplit(input$taxa2, ",")),as.integer(input$seqsize),input$rmvpaises)})
output$downloadData_2 <- downloadHandler(
filename = function() {
paste(input$taxa2,sep_out=",", ".tsv")
},
content = function(file) {
shiny::withProgress(
value=10,
{
shiny::incProgress(10/10)
write_tsv(taxaInput_2(), file)
}
)
}
)
output$value <- renderText({ input$rmvpaises })
}
shinyApp(ui=ui,server=server)
I want to initialize the download of a file in R Shiny when a button is pressed and do some checks before generating the file.
I've fooled arround with the downloadHandler (https://shiny.rstudio.com/gallery/file-download.html). But I want to catch the event of another button, do some things and checks with the data and when everything went well generate the file and initialize the download without having to press the download button from downloadHandler.
I've implemented most checks for now in the downloadHandler, but it now generates a failed download when some checks aren't fulfilled. I don't like the behavior.
output$downloadData <- downloadHandler(
filename = function() { paste("DATA_EXPORT-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
withProgress(message = 'Export data', value = 0, {
# Number of steps
n <- 3
incProgress(1/n, detail = "Pre checks and get data")
# checks if inputs for get_data are well defined
dataSet <- get_data(blabla)
incProgress(1/n, detail = "Post Proces and check")
incProgress(1/n, detail = "generate flatfile")
write.csv(dataSet, file, row.names = FALSE)
})
}
)
To elaborate my comment, a minimal example:
library(shiny)
library(shinyjs)
# function which checks the data; returns TRUE or FALSE
checkData <- function(dat){
TRUE
}
# function which transforms the data; returns NULL if check not TRUE
processData <- function(dat){
if(checkData(dat)){
# do something with dat
names(dat) <- toupper(names(dat)) # for our example
return(dat)
}else{
return(NULL)
}
}
ui <- fluidPage(
useShinyjs(),
conditionalPanel(
"false", # always hide the download button
downloadButton("downloadData")
),
actionButton("check", "Download")
)
server <- function(input, output, session){
dat <- mtcars
finalData <- reactiveVal() # to store the processed data
observeEvent(input$check, {
if(!is.null(df <- processData(dat))){
finalData(df)
runjs("$('#downloadData')[0].click();")
}else{
# something which throws an alert message "invalid data"
# (eg with shinyBS::createAlert or shinyWidgets::sendSweetAlert)
}
})
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(finalData(), file)
}
)
}
shinyApp(ui, server)
I'm new to shiny.
I have a very basic question but I can't find a solution here on stackoverflow.
I am using directory Input function created by wleepang (https://github.com/wleepang/shiny-directory-input).
I wrote a function read_files that rbind all files in the directory selected.
I can display this table with renderTable, this works perfectly. But I do not manage to save this table to work with later (check for missing data, add columns, draw ggplots..) and to download is with write.xlsx
ui <- fluidPage(
directoryInput('directory', label = 'select a directory'),
actionButton("upload", label="Hochladen"),
downloadButton("download", label="Runterladen")
)
server <- function(input, output, session) {
#this part is to set the directory
observeEvent(
ignoreNULL = TRUE,
eventExpr = {
input$directory
},
handlerExpr = {
if (input$directory > 0) {
path = choose.dir(default = readDirectoryInput(session, 'directory'))
updateDirectoryInput(session, 'directory', value = path)
}})
#now comes the actual code
observeEvent(input$upload,{
df <- read_files(readDirectoryInput(session, 'directory'))
})
How can I access this df later?
output$downloadData <- downloadHandler(
filename = function() {
paste('tabelle', '.csv', sep="") },
content = function(file) {
write.xlsx(df, file)
}
)
}
And my second question how can I download it as a xlsx file in the set directory?
my global.r with the read_files function
source('directoryInput.R')
read_files = function(inDir, pat="*.csv", readMe=read.csv2){
files = list.files(inDir, pattern=pat)
files = lapply(files, function(x) file.path(inDir, x))
df = do.call(rbind, lapply(files, readMe))
return(df)
}
I have saved the element using a reactive function
upload_data <- eventReactive(input$upload, {
read_files(readDirectoryInput(session, 'directory')) })
and can access it through upload_data() this works for me
I have created a shiny app that uses session$clientData to get parameter values to the server. It works great, however, I would also like to be able to initiate a download through the url, e.g:
localhost:8100/?plot=a&title=mytitle&download=1
and then in server.R, something like:
if(session$clientData$download == "1"){
download()
}
Hence, is it possible to initiate the downloadHandler() in server.R?
Thanks!
I am not sure I have correctly understood what you are trying to do. What I have understood is that you would like a download to be initiated when the query string download=1 is present in the url. You could do this by injecting some javascript to open the link when the required query string is detected. There will be some problems however.
Your browser will most likely block the pop up. You will need to wait a sufficient length of time before you fire the code (I have chosen 5 seconds).
require(shiny)
runApp(list(
ui = bootstrapPage(
tags$head(tags$script(HTML('
Shiny.addCustomMessageHandler("jsCode",
function(message) {
eval(message.value);
}
);
'))),
downloadLink('downloadData', 'Download'),
verbatimTextOutput("summary")
),
server = function(input, output, session) {
data <- seq(100)
output$downloadData <- downloadHandler(
filename = function() {
paste('data-', Sys.Date(), '.csv', sep='')
},
content = function(file) {
write.csv(data, file)
}
)
output$summary <- renderText({
cnames <- names(session$clientData)
allvalues <- lapply(cnames, function(name) {
item <- session$clientData[[name]]
if (is.list(item)) {
list_to_string(item, name)
} else {
paste(name, item, sep=" = ")
}
})
paste(allvalues, collapse = "\n")
})
observe({
query <- parseQueryString(session$clientData$url_search)
if(!is.null(query$download)){
if(query$download == 1){
jsinject <- "setTimeout(function(){window.open($('#downloadData').attr('href'))}, 5000);"
session$sendCustomMessage(type = 'jsCode', list(value = jsinject))
}
}
})
}
))