rshinys

How to use download button in shiny and save results in various formats (csv, texte, pdf, spss...)?


I am currently working on shiny app. And I would like the app allows to download (save) results in various formats : csv, texte, pdf, xlsx, SPSS, SAS and Stata.

Here is my UI :

# Define UI
ui <- fluidPage(

  #Navbar structure for UI
  navbarPage("Selection de modeles", theme = shinytheme("slate"),
             tabPanel("Programme", fluid = TRUE, icon = icon("spinner"),
                      tags$style(button_color_css),
                      # Sidebar layout with a input and output definitions
                      sidebarLayout(
                        sidebarPanel(

                          h3("Chargement des donnees"),

                          fileInput("file", "Charger un jeu de donnees :"),

                          checkboxGroupInput(inputId = "DataExemple",
                                             label = "Utiliser les donnees de base :",
                                             choices = c("Donnees de base" = "D1")),

                          hr(),

                          actionButton(inputId = "DeleteData", label = "Supprimer les donnees", icon = icon("trash-alt")),

                          hr(),

                          h3("Implementation de la procedure de selection"),
                          #shinythemes::themeSelector(),


                          # Select modele
                          checkboxGroupInput(inputId = "ModeleFinder",
                                             label = "Choix des modele(s):",
                                             choices = c("Modele 1" = c(1), "Modele 2 " = c(2),"Modele 3 " = c(3),"Modele 4 " = c(4)),
                                             selected = "M1"),

                          hr(),


                          # Select ratio 1
                          sliderInput(inputId = "SliderRatio1",
                                      label = "Choix ratio 1",
                                      min = 0, max = 100, 30
                          ),

                          # Select ratio 2
                          sliderInput(inputId = "SliderRatio2",
                                      label = "Choix ratio 2",
                                      min = 0, max = 100, 30
                          ),

                          # Select ratio 3
                          sliderInput(inputId = "SliderRatio3",
                                      label = "Choix ratio 3",
                                      min = 0, max = 100, 30
                          ),

                          # Select ratio 4
                          sliderInput(inputId = "SliderRatio4",
                                      label = "Choix ratio 4",
                                      min = 0, max = 100, 30
                          ),

                          # Select ratio 5
                          sliderInput(inputId = "SliderRatio5",
                                      label = "Choix ratio 5",
                                      min = 0, max = 100, 30
                          ),

                          hr(),
                          hr(),

                          # Select alpha 1
                          sliderInput(inputId = "SliderAlpha1",
                                      label = "Importance du ratio",
                                      min = 0, max = 1, 0.3
                          ),

                          # Select alpha 2
                          sliderInput(inputId = "SliderAlpha2",
                                      label = "Importance de l'erreur d'apprentissage",
                                      min = 0, max = 1, 0.3
                          ),

                          # Select alpha 3
                          sliderInput(inputId = "SliderAlpha3",
                                      label = "Importance de l'erreur test",
                                      min = 0, max = 1, 0.3
                          ),

                          # Select alpha 4
                          sliderInput(inputId = "SliderAlpha4",
                                      label = "Importance du temps de calcul",
                                      min = 0, max = 1, 0.3
                          ),

                          # Select alpha 5
                          sliderInput(inputId = "SliderAlpha5",
                                      label = "Importance de la complexite du modele",
                                      min = 0, max = 1, 0.3
                          ),

                          hr(),
                          actionButton(inputId = "calculate", label = "Calculer", icon = icon("check")),
                          hr(),

                          h3("Sauvegarder les resultats"),

                          selectInput(inputId = "Export1",
                                      label = "Choisir le format",
                                      choices = c("csv", "texte","PDF","xlsx","SPSS","SAS","Stata"),
                                      selected = "csv"),


                          downloadButton("downloadData1", "Download")

                        ),

                        mainPanel(

                          ### add your style inline css values here

                          ### added a line of code here too `.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover `###
                          tags$style(HTML("
                                          .dataTables_wrapper .dataTables_length, .dataTables_wrapper .dataTables_filter, .dataTables_wrapper .dataTables_info, .dataTables_wrapper .dataTables_processing, .dataTables_wrapper .dataTables_paginate, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
                                          color: #ffffff;
                                          }
                                          ### ADD THIS HERE ###
                                          .dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#ffffff !important;border:1px solid transparent;border-radius:2px}

                                          ###To change text and background color of the `Select` box ###
                                          .dataTables_length select {
                                          color: #0E334A;
                                          background-color: #0E334A
                                          }

                                          ###To change text and background color of the `Search` box ###
                                          .dataTables_filter input {
                                          color: #0E334A;
                                          background-color: #0E334A
                                          }

                                          thead {
                                          color: #ffffff;
                                          }

                                          tbody {
                                          color: #000000;
                                          }

                                          "


                    )
  ),

                          h4("Tableau de resultats"),
                          dataTableOutput("tab_res"),

                          hr(),


                          h4("Meilleur modele"),
                          dataTableOutput("best_mod")


                        )

                      )
             ),  

             tabPanel("Code & Donnees", fluid = TRUE, icon = icon("database"),
                      sidebarLayout(
                        sidebarPanel(

                          h3("Affichage des donnees"),

                          radioButtons(inputId = "Display1",
                                       label = "",
                                       choices = c("preview", "str","summary"),
                                       selected = "preview"),

                          hr(),

                          h3("Affichage du code"),

                          checkboxGroupInput(inputId = "CodeR",
                                             label = "",
                                             choices = c("Afficher le code R" = "R1"))

                        ),

                        mainPanel()
                      )
             ),

             tabPanel("Graphiques", fluid = TRUE, icon = icon("chart-line"),
                      sidebarLayout(
                        sidebarPanel(

                          h3("Choix du modele"),

                          radioButtons(inputId = "Display2",
                                       label = "",
                                       choices = c("Modele 1", "Modele 2","Modele 3","Modele 4"),
                                       selected = "Modele 1"),

                          hr(),

                          h3("Sauvegarder le graphique"),

                          selectInput(inputId = "ExportGraph",
                                      label = "Choisir le format",
                                      choices = c("PNG", "JPEG","BMP"),
                                      selected = "PNG"),

                          downloadButton("downloadData2", "Download")

                        ),

                        mainPanel()
                      )
             ),

             navbarMenu("Plus d'informations", icon = icon("info-circle"),
                        tabPanel("Étude", fluid = TRUE,
                                 fluidRow(
                                   column(6,
                                          h4(p("Résumé")),
                                          h5(p("Cette étude a été réalisée au cours d'un stage de fin d'études en deuxième année de Master DSMS (Data Science et Modélisation Statistique) à l'Université de Bretagne Sud. Le stage s'est déroulé au sein du LMBA (Laboratoire de Mathématiques de Bretagne Atlantique) sur une période de six mois."),
                                             p("Le sujet du stage était le suivant : « Automatisation d'une procédure de sélection de modèles dans le cadre du Couplage Modèle-Données »."),
                                             p("Au cours d'un projet précédent, un outil avait été contruit afin d'ajuster un modèle (de type Couplage Modèle-Données) sur des données et de collecter certaines informations associées à celui-ci. L'objectif de notre stage était donc d'éprouver l'outil déjà existant, d'augmenter sa robustesse et son niveau de généricité et enfin d'automatiser la procédure complète de sélection de modèles."),
                                             p("Cette interface Shiny est en quelque sorte la mise en forme de nos travaux."),
                                             p("Les détails qui sont propres à notre programme sont référencés dans l'onglet intitulé « Détails ».")
                                          )
                                   ),
                                   column(6,
                                          h4(p("Le Couplage Modèle-Données")),
                                          h5(p("Si l'on se réfère aux travaux effectués par FLOURENT (2019) dans le domaine du Smart Farming (l'agriculture de précision), on peut dire que le Couplage Modèle-Données est une approche qui se situe à mi-chemin entre les approches dîtes « Black Box » et « White Box »."),
                                             p("Le type de modèle appelé « Black Box » fait en grande partie référence aux modèles classiques du Machine Learning (réseaux de neurones .). D'après GORCZYCA et al (2018), VALLETTA et al. (2017), MA et al. (2014) et IP et al. (2018), la popularité de ces modèles peut s'expliquer par leur facilité d'utilisation, ainsi que par la diversité des problèmes pouvant être résolus grâce à de tels algorithmes. Néanmoins ces modèles contiennent peu de connaissances a priori. Par conséquent, les outils basés sur ce type de modèles sont peu informatifs d'un point de vue biologique (TAN et GILBERT (2003), SHAVLIK et al. (1995), HUBBARD et REINHARDT (1998)). Il faut également noter qu'il est nécessaire d'apprendre les paramètres de ces modèles à partir de beaucoup de données et ceci dans le but de pallier l'absence d'expertise biologique (DUMPALA et al. (2017))"),
                                             p("À l'inverse, les modèles « White Box » correspondent à des modèles mécanistes réalistes (VAZQUEZ-CRUZ et al. (2014)). Si l'on se penche sur les travaux de BASTIANELLI et SAUVANT (1997) et MARTIN et SAUVANT (2010), la construction de modèles mécanistes réalistes est une tâche complexe menant généralement à un modèle contenant un grand nombre d'équations et de paramètres à déterminer. Ce type de modèle nécessite d'avoir beaucoup de connaissances concernant le système étudié."),
                                             p("On cite une nouvelle fois les travaux de FLOURENT : « Le Couplage Modèle-Données consiste à intégrer des connaissances concernant la dynamique du système étudié via la construction d'un modèle mathématique et à utiliser ensuite des données pour ajuster les paramètres du modèle construit ». On peut aussi reprendre les travaux de FRENOD (2017), ROUSSEAU et NODET (2013), SACKS et al. (2007) et WANG et al. (2010), et dire que le Couplage Modèles-Données consiste à construire un modèle mathématique parcimonieux, correspondant à une synthèse mathématique du système étudié.")
                                          )
                                   ))

                        ),

                        tabPanel("Détails", fluid = TRUE,
                                 fluidRow(
                                   column(6,
                                          #br(),
                                          h4(p("Modèles")),
                                          h5(p("Notre programme comporte trois types de modèles et quatre modèles différents. Deux modèles de type Couplage Modèle-Données (les modèles 1 et 2), un modèle de type réseau de neurones (le modèle 3) et un modèle de type linéaire (le modèle 4).")),
                                          br(),
                                          h4(p("Paramètres")),
                                          h5(p("Le premier modèle de type Couplage Modèle-Données est composé de trois paramètres ajustés. Le second modèle de type Couplage Modèle-Données est composé de deux paramètres ajustés et d'un paramètre fixe. Le modèle de type réseau de neurones est composé de trois couches cachées (la première et la troisième couches comportent trois neurones, la deuxième couche compte six neurones).")),
                                          br(),
                                          h4(p("Informations")),
                                          h5(p("Notre outil permet de collecter un certain nombre d'informations sur chacun des modèles comme l'erreur d'apprentissage, l'erreur test ou encore le temps de calcul. Certaines de ces informations nous sont utiles pour calculer notre indicateur de comparaison."))

                                          #hr(),

                                   ),
                                   column(6,
                                          #br(),
                                          h4(p("Indicateur")),
                                          h5(p("Notre indicateur de comparaison se base sur cinq informations différentes, à savoir : l'erreur test, l'erreur d'apprentissage, le temps de calcul, la complexité du modèle et la ratio.")),
                                          br(),
                                          h4(p("Programme")),
                                          h5(p("Le programme, sur la base de l'indicateur, renvoie le « meilleur » modèle ainsi qu'un tableau de résultats avec un certain nombre d'infomations. L'utilisateur a la possibilité de sélectionner les modèles qu'il souhaite comparer, de choisir différents ratios (taille des données d'apprentissage et de test) ainsi que les poids associés (alphas) aux paramètres de l'indicateur.")),
                                          br(),
                                          h4(p("Poids associés")),
                                          h5(p("alpha 1 : poids associé au ratio")),
                                          h5(p("alpha 2 : poids associé à l'erreur d'apprentissage")),
                                          h5(p("alpha 3 : poids associé à l'erreur test")),
                                          h5(p("alpha 4 : poids associé au temps de calcul")),
                                          h5(p("alpha 5 : poids associé à la complexité du modèle"))

                                   )
                                 ),
                                 br(),
                                 hr(),
                                 h6(      
                                   p(
                                     a("Université de Bretagne Sud", 
                                       href = "https://www.univ-ubs.fr/fr/index.html"),
                                     br(),
                                     br(),
                                     a("Laboratoire de Mathématiques de Bretagne Atlantique", 
                                       href = "http://www.lmba-math.fr/"))),

                                 h6("Conçu avec",
                                    img(src = "https://www.rstudio.com/wp-content/uploads/2014/04/shiny.png", height = "30px"),
                                    "par",
                                    img(src = "https://www.rstudio.com/wp-content/uploads/2014/07/RStudio-Logo-Blue-Gray.png", height = "30px"),
                                    ".")
                        )
             )
  )
)

and here is server part :


server <- function(input, output, session) {
  results <- eventReactive(input$calculate, {
    procedure_finale_shiny(
      input$SliderAlpha1, input$SliderAlpha2, input$SliderAlpha3, input$SliderAlpha4, input$SliderAlpha5,
      c(input$SliderRatio1, input$SliderRatio2,input$SliderRatio3, input$SliderRatio4, input$SliderRatio5),
      as.numeric(input$ModeleFinder))
  })

  output$tab_res <- renderDataTable({ results()[[1]] })
  output$best_mod <- renderDataTable({ results()[[2]] })
}

The results I want to download (save) is output$tab_res or results()[[1]]. The downloadButton is called downloadData1 and the selectInput is called Export1. The last one contains the list : c("csv", "texte","PDF","xlsx","SPSS","SAS","Stata").

If you have any solutions ?

Thank you in advance !


Solution

  • It looks like your app is using a number of files/functions that are only available on your local computer, so I was unable to test this code fully. That said, this should help you get started.

    server <- function(input, output, session) {
        results <- eventReactive(input$calculate, {
            procedure_finale_shiny(
                input$SliderAlpha1, input$SliderAlpha2, input$SliderAlpha3, input$SliderAlpha4, input$SliderAlpha5,
                c(input$SliderRatio1, input$SliderRatio2,input$SliderRatio3, input$SliderRatio4, input$SliderRatio5),
                as.numeric(input$ModeleFinder))
        })
    
        output$tab_res <- renderDataTable({ results()[[1]] })
        output$best_mod <- renderDataTable({ results()[[2]] })
    
        ## Here's the new code to help users download data
        output$downloadData1 <- downloadHandler(
          # supply input$Export1 as an argument to customize the filename
          filename = function(file.type = input$Export1){
            if (file.type == "csv"){
              str <- "my_data.csv"
            }else if (file.type == "texte"){
              str <- "my_data.txt"
            }
            #else if()...etc
            return(str)
          },
          content = function(con){
    
            #my_data <- results()[[1]]
            my_data <- data.frame(animal = c("cat", "dog", "fish"), avg_age = c(15, 12, 2))
    
            # input$Export1 is again used in this if-else block to use the 
            # correct function to write the data
            if (input$Export1 == "csv"){
              write.csv(my_data, con, row.names=FALSE)
            }else if (input$Export1 == "texte"){
              write.table(my_data, con)
            }
            #else if...etc
    
          }
        )
    }
    

    I'd recommend testing/debugging this in a browser like Google Chrome.

    You'll also need to find specific libraries to write to some of the less common formats (eg. maybe use gridExtra for pdf like they do in this question; xlsx for writing to xlsx; Check out this website for SPSS, STATA, and SAS).