web-dev-qa-db-fra.com

Entrée de répertoire interactif dans l'application Shiny (R)

Je crée une application brillante qui nécessite qu'un utilisateur sélectionne un dossier sur la machine locale, qui contient les fichiers à traiter par l'application.

J'utilise une solution proposée ici . Cela fonctionne bien sur une machine locale, mais ne fonctionne pas si l'application est déployée sur un serveur shinyapps. L'auteur de cette solution a confirmé qu'elle était uniquement conçue pour fonctionner avec des applications Shiny locales, car elle effectue des appels OS Shell pour afficher une boîte de dialogue de répertoire.

Je me demande s'il existe une solution différente pour la boîte de dialogue de répertoire, qui fonctionnera sur les applications Shiny déployées (je déploie sur shinyapps.io).

Modifié: notez que je ne peux pas utiliser l'interface fileInput pour deux raisons:

  1. Les utilisateurs de l'application ne sont pas des techniciens et ne savent pas quels fichiers du dossier sont utilisés par l'application.
  2. Le dossier sélectionné peut contenir d'autres dossiers dans lesquels résident les fichiers nécessaires, de sorte qu'il est impossible de sélectionner tous les fichiers à la fois, même si l'interface fileInput a l'option multiple activée.

La structure des dossiers/fichiers n'est pas quelque chose que je peux changer, elle est téléchargée AS IS à partir d'un appareil médical et donc la seule chose que je peux attendre des utilisateurs est de spécifier le dossier parent et le reste devrait être fait à l'intérieur du code R.

14
Sasha

Il s'agit d'un exemple de travail basé sur l'utilisation de l'attribut "webkitdirectory". Pour le moment, l'attribut est pris en charge par Chrome, Opera et Safari (mobile et ordinateur de bureau) et devrait être pris en charge dans Firefox 49 pour être publié en septembre. Pour en savoir plus ici . Il fonctionne également avec les sous-répertoires.

Cela nécessite l'utilisation du mot-clé tags dans ui.R. Je l'ai testé en téléchargeant trois fichiers csv contenant chacun trois nombres séparés par un coma. Testé localement et sur shinyapps.io avec Chrome et Opera. Voici le code:

ui.R

    library(shiny)
    library(DT)

    shinyUI(tagList(fluidPage(theme = "bootstrap.css",
                      includeScript("./www/text.js"),
                      titlePanel("Folder content upload"),

                      fluidRow(
                              column(4,
                                     wellPanel(
                                             tags$div(class="form-group shiny-input-container", 
                                                      tags$div(tags$label("File input")),
                                                      tags$div(tags$label("Choose folder", class="btn btn-primary",
                                                                          tags$input(id = "fileIn", webkitdirectory = TRUE, type = "file", style="display: none;", onchange="pressed()"))),
                                                      tags$label("No folder choosen", id = "noFile"),
                                                      tags$div(id="fileIn_progress", class="progress progress-striped active shiny-file-input-progress",
                                                               tags$div(class="progress-bar")
                                                      )     
                                             ),
                                             verbatimTextOutput("results")
                                     )
                              ),
                              column(8,
                                     tabsetPanel(
                                             tabPanel("Files table", dataTableOutput("tbl")),
                                             tabPanel("Files list", dataTableOutput("tbl2"))
                                     )
                              )
                      )
    ),
    HTML("<script type='text/javascript' src='getFolders.js'></script>")
    )

    )          

server.R

    library(shiny)
    library(ggplot2)
    library(DT)

    shinyServer(function(input, output, session) {
            df <- reactive({
                    inFiles <- input$fileIn
                    df <- data.frame()
                    if (is.null(inFiles))
                            return(NULL)
                    for (i in seq_along(inFiles$datapath)) {
                            tmp <- read.csv(inFiles$datapath[i], header = FALSE)  
                            df <- rbind(df, tmp)
                    }
                    df

            })
            output$tbl <- DT::renderDataTable(
                    df()
            )
            output$tbl2 <- DT::renderDataTable(
                    input$fileIn
            )
            output$results = renderPrint({
                    input$mydata
            })

    })

text.js

window.pressed = function(){
        var a = document.getElementById('fileIn');
        if(a.value === "")
        {
            noFile.innerHTML = "No folder choosen";
        }
        else
        {
            noFile.innerHTML = "";
        }
    };

getFolders.js

     document.getElementById("fileIn").addEventListener("change", function(e) {

            let files = e.target.files;
            var arr = new Array(files.length*2);
            for (let i=0; i<files.length; i++) {

            //console.log(files[i].webkitRelativePath);
            //console.log(files[i].name);
            arr[i] = files[i].webkitRelativePath;
            arr[i+files.length] = files[i].name;


            }

            Shiny.onInputChange("mydata", arr);

    });

Faites-moi savoir si cela aide.

9
Valter Beaković

Avez-vous essayé le package shinyFiles? Il y a un widget qui vous permet de choisir un répertoire. En sortie, vous obtenez le chemin de ce répertoire que vous pouvez à son tour utiliser pour accéder aux fichiers. Voici un exemple de fonctionnement.

serveur

library(shiny)
library(shinyFiles)

shinyServer(function(input, output, session) {

  # dir
  shinyDirChoose(input, 'dir', roots = c(home = '~'), filetypes = c('', 'txt'))
  dir <- reactive(input$dir)
  output$dir <- renderPrint(dir())

  # path
  path <- reactive({
    home <- normalizePath("~")
    file.path(home, paste(unlist(dir()$path[-1]), collapse = .Platform$file.sep))
  })

  # files
  output$files <- renderPrint(list.files(path()))
}) 

ui

library(shiny)
library(shinyFiles)

shinyUI(fluidPage(sidebarLayout(

  sidebarPanel(
    shinyDirButton("dir", "Chose directory", "Upload")
  ),

  mainPanel(
    h4("output$dir"),
    verbatimTextOutput("dir"), br(),
    h4("Files in that dir"),
    verbatimTextOutput("files")
  )

))) 

J'espère que cela t'aides.

9
mRcSchwering