3

I wrote a shiny app which will be used for searching and downloading a quite large dataset. The app works and is nearly done, but some functionalities do not work as I want:

  • I tried several ways of adding a function in order to download the chosen data as .csv-file. All of them failed and I was only able to download all data instead of the displayed ones.
  • I was not able to include a function to round data and show some columns as percentage instead of numbers. The formatRound() function within datatable() works well and I would like to use it, but the problem is that I was not able to include it in the server function. Since the user should get the whole number (with all numbers also behind the comma) for his or her work, the data should only be rounded when displayed. If I would be able to fix the rounding, the percentage problem will also be solved, since I would use the similar function formatPercentage().

I made an example using the mtcars-data and removed all wrong or not-working codes for the download and rounding problem. Any hints how I could solve my problem would be extremely appreciated! Thanks in advance!

EDIT3: Rounding problem solved with the code below thanks to @Claud H. The download function exports an empty file (no file-type) named download. Do you have any idea where the error is?

EDIT4: problems solved thanks to @Claud H. I changed mt_cars_filtered()[, c(input$results_columns_selected)]into mt_cars_filtered()[, input$indicator]. Also, I didn't know first that I had to open the web browser to download the data.

      library(tidyverse)
      library(shiny)
      library(shinythemes)
      library(DT)
      library(ggthemes)

      ui <- fluidPage(

        sidebarLayout(

    sidebarPanel(width=3,
                 h3("title", align = 'center'),

                 checkboxGroupInput("cylinder", "Cylinder", choices = c(4,6), selected = c(4)),

                 checkboxGroupInput('indicator', label = 'Indicators', choices = colnames(mtcars)[1:7],
                                    selected = colnames(mtcars)[c(1:7)]),

                 fluidRow(p(class = 'text-center', downloadButton('download', label = 'Download')))),


    mainPanel(
      tabsetPanel(
        tabPanel('Table',
                 DT::dataTableOutput('results'))

      )
    )
        ))


      server <- function(input, output){

        mtcars_filtered <- reactive({
          mtcars %>%
            filter(cyl %in% input$cylinder)
        })

        # Output Table
        output$results <- DT::renderDataTable({
          columns = input$indicator
          mtcars_filtered()[, columns, drop = FALSE] %>%
      datatable(style = 'bootstrap', selection = list(target = 'column'), options = list(paging = FALSE, dom = 't')) %>%
      formatRound(input$indicator[grep('t', input$indicator)], 2)
        })

        # Download Data
        output$download <- downloadHandler(
          filename = function() { paste('filename', '.csv', sep = '') },
          content = function(file) {
            write.csv(mtcars_filtered()[,input$indicator], file, row.names = FALSE)
    })
      }

      shinyApp(ui = ui, server = server)
huan
  • 308
  • 3
  • 15
  • For the exporting issue you could try using something similar to this: `DT::datatable( mtcars, options = list( dom = 'Bfrtip', buttons = c('copy', 'excel', 'pdf', 'print', 'colvis') ), extensions = 'Buttons' )` Link: https://github.com/rstudio/DT/issues/213 – Barbara Nov 07 '17 at 13:50

1 Answers1

2

Suggest looking at ?"%>%" from magrittr package

Also, check this and this answers on SO.

Your table should be fine with this kind of syntax

output$results <- DT::renderDataTable({
    columns = input$indicator
    mtcars_filtered()[, columns, drop = FALSE] %>% 
      datatable() %>%
      formatCurrency( input your code here) %>%
      formatPercentage( and so on ... )
  }, style = 'bootstrap', options = list(paging = FALSE, dom = 't')) 

Also, I didnt quite get the question about downloading. If you want to download a data FROM server, use downloadHandler() function. Something like:

output$save_data <- downloadHandler(
  filename = function() { paste("filename", '.csv', sep = '') },
  content = function(file) {
    write.csv(mydata(), file, row.names = FALSE)
  })

and downloadButton("save_data", "download") in ui.R

edit: as per your changes, download isn't working because you got wrong columns selected: there is no table called tableId, and you need to take the columns from the table called results:

write.csv(mtcars_filtered()[, c(input$results_columns_selected)], file, row.names = FALSE)

as of rounding problem, you can use your indicator variable to see if column is selected input$indicator %in% c('drat', 'qsec', 'wt') then use subsetting to select only columns with TRUE, if there are any: formatRound(input$indicator[input$indicator %in% c('drat', 'qsec', 'wt')], 2)

edit2 Seems I've understood everything you wanted to do right. To select columns in the downloadHandler function based on your checkboxes , use indicator variable to filter it:

mtcars_filtered()[, input$indicator]

Otherwise, if you want to select them from the table itself with the mouse clicks, use input$results_columns_selected, like this:

mtcars_filtered()[, c(input$results_columns_selected)]
vladli
  • 1,454
  • 2
  • 16
  • 40
  • thank you for your very helpful response. It partially works (code above is updated): - rounding is defined by column names. This leads to the problem that if one of the 3 columns is deselected, there is an error message, - the style argument is overwritten and I get the message Warning in widgetFunc(): renderDataTable ignores ... arguments when expr yields a datatable object - download works, but by now the specifications download all data of mtcars_filtered. I would like to download only the data for the columns which are selected. - exportfile is not defined as .csv. – huan Nov 07 '17 at 16:14
  • 1
    From `DT` user guide: You can turn on column selection using `datatable(..., selection = list(target = 'column'))`. In this case, you can click on any cell to select a column, and the (numeric) indices of the selected columns will be available in `input$tableId_columns_selected`. Then you can use `mydata()[, c(input$tableId_columns_selected)]` to download only selected columns – vladli Nov 08 '17 at 11:33
  • 1
    If you want to round digits in all columns of a dataset and not select them by hand - you could use `colnames(mydata)` or something similar in `formatRound(...)` – vladli Nov 08 '17 at 12:17
  • I think the `selection()`-function is the key to my download problem. But I have problems with the syntax and only get an empty file with my code above (updated). I tried different possibilities and only got empty tables. Regarding the rounding-problem: I have to define manually which columns should be rounded at 2 digits and which should be percentage. Thus, I need to select them by hand, but in a way which avoids the error message. BTW: I tried to vote for your answer yesterday, but I'm not allowed to. I thought an answer should be accepted when the problem is solved? – huan Nov 08 '17 at 12:51
  • Yeah, I didnt know you still got problems with that. I'll look into your code tomorrow and suggest something – vladli Nov 08 '17 at 17:48
  • Your hint to the `indicator`-variable was gold. It led me to solve the problem with the `grep()`-function, which is perfect, since I have to define a large number of columns in the original app. I was not able to solve the download problem though. I got an empty dataset running the updated code above. Any ideas how to solve this? – huan Nov 09 '17 at 14:48
  • Weird, since it worked fine with my additions for me - look carefully what you put in `write.csv()` function - as empty table means you didnt give the function the right data. Oh I get it - you are selecting the columns with checkboxes probably. Then you should use something like `mtcars_filtered()[, input$indicator]` to select them. If you click on the column itself with your mouse - it will be selected and downloaded with `write.csv(mtcars_filtered()[, c(input$results_columns_selected)], file, row.names = FALSE)`. I'll update my answer with 2 choices – vladli Nov 09 '17 at 15:39
  • Perfect, everything works as planned. It took some time until I found out that I cannot download the data in the local application, but I can on a web browser. – huan Nov 09 '17 at 19:28