jmarco10
jmarco10

Reputation: 525

Shiny R - download the result of a table

I am new to Shiny and I have created a really simple shiny app:

library(shiny)

ui <- fluidPage(
  fluidRow(column(7,dataTableOutput('dto')))
)

server <- function(input,output){

  output$dto <- renderDataTable({MYTABLE})


}

runApp(list(ui=ui,server=server))

Is there any way to put an option to download the result of the table (doesn't matter if is CSV, XLSX...)

cheers

Upvotes: 19

Views: 31387

Answers (3)

Fabian Pino
Fabian Pino

Reputation: 86

I have to execute the app in the browser because the filename isn't working. I use

runApp(list(ui=ui,server=server),launch.browser = T)

and it works perfectly for me.

If you don't want to use launch.browser=TRUE you can write the filename and the extension for example .csv at the end of the filename when you use the download button in the shiny app.

Upvotes: 1

Joris Meys
Joris Meys

Reputation: 108543

That's pretty easy with downloadButton() or downloadLink() in combination with downloadHandler if you make the data itself a reactive expression. Then you can download whatever you send to output using the same reactive expression.

A small example:

library(shiny)

ui <- fluidPage(
  # This one is linked by the id 'download'
  downloadButton('download',"Download the data"),
  fluidRow(column(7,dataTableOutput('dto')))
)

server <- function(input,output){
  # Reactive expression with the data, in this case iris
  thedata <- reactive(iris)

  output$dto <- renderDataTable({thedata()})
  output$download <- downloadHandler(
    filename = function(){"thename.csv"}, 
    content = function(fname){
      write.csv(thedata(), fname)
    }
  )

}

runApp(list(ui=ui,server=server))

Keep in mind:

  • the argument content of downloadHandler must be a function producing a file! It should take one argument for the connection/file name. In this example it is a csv file, but for eg images you can use png() and dev.off(), for ggplots you can use ggsave(), ...
  • the argument filename does not have to be a function, but I found it works better that way. Especially when working with reactive expressions for the file name.
  • you link the downloadHandler and the downloadButton through the output list: the id of downloadButton is the name of the output element returned by downloadHandler.

EDIT:

Some people try to use download.file() for this, but that's wrong as well. The function download.file() works when used on the user side, not the server side. It lets you download files from the internet to the computer that is calling the function. If you'd use that in a Shiny application, it would work when run locally. That's because user and server are the same machine. However, when deploying your app on a Shiny Server, download.file() would essentially be downloading files TO the server, not from.

Upvotes: 31

Buggy
Buggy

Reputation: 2100

A slightly alternative solution based directly on the datatable / DT extension buttons.

I am shamelessly borrowing the example data from Joris...

library(shiny)
library(DT)

ui <- fluidPage(
 # This one is linked by the id 'download'
  fluidRow(column(7,dataTableOutput('dto')))
)

server <- function(input,output){
  # Reactive expression with the data, in this case iris
  thedata <- reactive(iris)

#the extensions parameter coupled with the options list does the trick  
output$dto <- renderDataTable(thedata(), extensions = 'Buttons', 
                options = list(dom = 'Bfrtip',
                buttons = c('copy', 'csv', 'excel', 'pdf', 'print'))
  )
}

runApp(list(ui=ui,server=server), launch.browser=TRUE) #now runs by default in the external browser.

This will work with different outputs and personally I like the cleaner look. Just make sure that you are running the demo in the external browser. Otherwise it won't work.

Upvotes: 15

Related Questions