web-dev-qa-db-ja.com

Shinyアプリ(R)での対話型ディレクトリ入力

ユーザーがローカルマシン上のフォルダーを選択することを要求する光沢のあるアプリを作成しています。フォルダーにはアプリで処理されるファイルが含まれています。

私は提案されたソリューションを使用しています here 。これはローカルマシンでは正常に機能しますが、アプリがshinyappsサーバーにデプロイされている場合は機能しません。このソリューションの作成者は、ディレクトリダイアログを表示するためにOS Shell呼び出しを行うため、ローカルのShinyアプリでのみ動作するように設計されていることを確認しました。

展開されたShinyアプリで動作するディレクトリダイアログの別のソリューションがあるかどうか疑問に思っています(shinyapps.ioに展開しています)。

編集:次の2つの理由で fileInput インターフェイスを使用できないことに注意してください。

  1. アプリのユーザーは技術者ではなく、フォルダー内のどのファイルがアプリで使用されているのかわかりません。
  2. 選択したフォルダーには、必要なファイルが存在する他のフォルダーが含まれている場合があります。そのため、fileInputインターフェイスでmultipleオプションが有効になっていても、すべてのファイルを一度に選択することはできません。

フォルダー/ファイル構造は私が変更できるものではなく、AS IS=医療機器からダウンロードされるため、ユーザーに期待できる唯一のことは親フォルダーと残りを指定することですRコード内で行う必要があります。

14
Sasha

これは、「webkitdirectory」属性の使用に基づく実用的な例です。現時点では、この属性はChromeでサポートされていますOperaおよびSafari(モバイルおよびデスクトップ)。9月にリリースされるFirefox 49でサポートされる必要があります。これについての詳細 こちら 。サブディレクトリでも動作します。

Ui.Rでtagsキーワードを使用する必要があります。私は、それぞれがv睡状態で区切られた3つの数字を含む3つのcsvファイルをアップロードすることでテストしました。ローカルで、ChromeとOperaを使用してshinyapps.ioでテストします。これはコードです:

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);

    });

これが役立つかどうか教えてください。

9

shinyFilesパッケージを試してみましたか?ディレクトリを選択できるウィジェットがあります。出力として、そのディレクトリのパスを取得します。このパスを使用して、ファイルにアクセスできます。以下に例を示します。

サーバ

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")
  )

))) 

お役に立てれば。

9
mRcSchwering