Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RShiny Download Button Within RMarkdown

I can't seem to get the shiny downloadButton to work in an rmarkdown document with runtime: shiny. Here is an example similar to what I am doing.

 ---
 title: "R Document"
 runtime: shiny
 ---

 ```{r, echo = FALSE}
 numericInput("SS", "Selecr SS", min = 1, max = 100, value = 1)

 RandomSample <- reactive({
   data.frame(X = rnorm(100), Y = rnorm(100))
 })

 downloadButton("download", "Download")

 renderPlot({
   plot(RandomSample()[(1:input$SS), "X"], RandomSample()[(1:input$SS), "Y"])
 })

 renderTable({
   RandomSample()[(1:input$SS),]
 })
 ```

I'd like the download button to download RandomSample(), but I can't even get the downloadButton to show up.

like image 288
ZBauc Avatar asked Mar 10 '23 14:03

ZBauc


2 Answers

I think what you are looking for is downloadHandler.

Here is your example with it working:

---
title: "R Document"
runtime: shiny
output: html_document
---
```{r, echo=FALSE}

 numericInput("SS", "Selecr SS", min = 1, max = 100, value = 1)

 RandomSample <- reactive({
   data.frame(X = rnorm(100), Y = rnorm(100))
 })

 downloadHandler(filename = function() { 
    return(paste('Example', input$SS, '.csv', sep=''))

 }, content = function(file) {
   write.csv(RandomSample(), file)
 })

 renderPlot({
   plot(RandomSample()[(1:input$SS), "X"], RandomSample()[(1:input$SS), "Y"])
 })

 renderTable({
   RandomSample()[(1:input$SS),]
 })
 ```

Note that your filename will not be respected while testing in RStudio, but when running in a browser it will.

like image 51
Jeremy Farrell Avatar answered Mar 20 '23 20:03

Jeremy Farrell


There's something a bit weird with downloadButton. If you look at the function it's:

function (outputId, label = "Download", class = NULL, ...)  {
aTag <- tags$a(id = outputId, class = paste("btn btn-default shiny-download-link", 
    class), href = "", target = "_blank", download = NA, 
    icon("download"), label, ...)
}

whereas downloadLink is:

function (outputId, label = "Download", class = NULL, ...) {
    tags$a(id = outputId, class = paste(c("shiny-download-link", 
        class), collapse = " "), href = "", target = "_blank", 
        download = NA, label, ...)
}

What that means is the return value of downloadButton is invisible, so it won't produce the html to work in markdown (I'm sure that's probably by design for shiny, but if someone can explain why I'd like to know). You can change this behaviour by writing a new function:

downloadButtonRmd <- function (outputId, label = "Download", class = NULL, ...)  {
     tags$a(id = outputId, class = paste("btn btn-default shiny-download-link", 
        class), href = "", target = "_blank", download = NA, 
        icon("download"), label, ...)
 }

Which has visible output. This might be useful in the case where you have multiple downloads from one document (which is what led me here)

---
title: "R Document"
runtime: shiny
output: html_document
---


```{r}
downloadButtonRmd <- function (outputId, label = "Download", class = NULL, ...)  {
     tags$a(id = outputId, class = paste("btn btn-default shiny-download-link", 
        class), href = "", target = "_blank", download = NA, 
        icon("download"), label, ...)
 }
```



```{r, echo=FALSE}

numericInput("SS1", "Select SS1", min = 1, max = 100, value = 1)
numericInput("SS2", "Select SS2", min = 1, max = 100, value = 1)

downloadButtonRmd("down1", label = "Download1")
downloadLink("down2", label = "Download2")


RandomSample <- reactive({
   data.frame(X = rnorm(100), Y = rnorm(100))
 })

output$down1 <- downloadHandler(filename = function() { 
    return(paste('Example', input$SS1, '.csv', sep=''))

 }, content = function(file) {
   write.csv(RandomSample(), file)
 })

output$down2 <- downloadHandler(filename = function() { 
    return(paste('Example', input$SS2, '.csv', sep=''))

 }, content = function(file) {
   write.csv(RandomSample(), file)
 })

renderPlot({
   plot(RandomSample()[(1:input$SS1), "X"], RandomSample()[(1:input$SS1), "Y"])
 })

renderPlot({
   plot(RandomSample()[(1:input$SS2), "X"], RandomSample()[(1:input$SS2), "Y"])
 })

renderTable({
   RandomSample()[(1:input$SS1),]
 })

renderTable({
   RandomSample()[(1:input$SS2),]
 })


 ```
like image 26
Tom Greenwood Avatar answered Mar 20 '23 20:03

Tom Greenwood