世界一やさしいデータ分析教室

オーブンソースデータなどWeb上から入手できるデータを用いて、RとPython両方使って分析した結果を書いていきます

【R Shiny】fileInputメソッドでファイルアップロード&散布図プロット

本記事は、Shiny Advent Calendar 2017の15日目の記事です。


Shiny100本ノックも気付けば第16弾まできました。

今回は、Shinyアプリケーションにファイルをアップロードする機能の実装方法について紹介します。

第11弾・第12弾にて、ドラッグ&ドロップによるファイルアップロードについて実践しました。
www.randpy.tokyo
www.randpy.tokyo

実は、わざわざ難しいドラッグ&ドロップでファイルをインプットしなくても、デフォルトで**fileInput**メソッドというエクスプローラーからファイルを選択できる機能があります。

ということで…。今回はfileInputメソッドを使ってファイルアップロードと、そのファイルを元にプロットを行うShinyアプリケーションを作成してみましょう。

また、サンプルコードはGithubにも置いてあります。
github.com


完成形はこんな感じ

まずはどんなアプリケーションが出来上がるのか、完成形の画像を貼ります。

何もファイルを選択していない状態
f:id:Np-Ur:20171215225334p:plain
ファイル選択後
f:id:Np-Ur:20171215225344p:plain
プロット後
f:id:Np-Ur:20171215225424p:plain

はい、このようなShinyアプリケーションです。

以下とデータ入力の仕方が変わっただけで、後は一緒なので分かりやすいかと思います。
www.randpy.tokyo

また、fileInputメソッドを使うことで実装も相当楽になります。

ソースコード解説

ドラッグ&ドロップの場合は、Javascriptファイルが必要でしたが、今回は不要です。
ui.Rファイルと、server.Rファイルのみで実装可能です。

ui.Rのソースコード

まずは、ui.Rのコードを紹介します。

library(shiny)

shinyUI(
  fluidPage(
    sidebarLayout(
      sidebarPanel(
        fileInput("file", "Choose CSV File",
                  accept = c(
                    "text/csv",
                    "text/comma-separated-values,text/plain",
                    ".csv")
        ),
        tags$hr(),
        h2("プロットするデータを選択"),
        htmlOutput("colname1"),
        htmlOutput("colname2"),
        actionButton("submit", "プロット")
      ),
      mainPanel(
        tabsetPanel(type = "tabs",
                    tabPanel("Table", tableOutput('table')),
                    tabPanel("Plot", plotOutput("plot"))
        )
      )
    )
  )
)

以下の部分がファイルをエクスプローラーから受け取る部分です。

fileInput("file", "Choose CSV File",
           accept = c(
           "text/csv",
           "text/comma-separated-values,text/plain",
           ".csv")
)

fileInput("server,Rに送る変数名", "表示するテキスト", accept = "どんなファイル形式を受け取るか")
という風に書いいけばOkです。

今回はserver.Rに送る変数名をfileとしたので、server.R側で「input$file」と書くことで参照が可能です。

テーブル表示部分やプロット部分は第12弾紹介した記事内容と同じなので説明は省略します。

server.Rのソースコード

続きまして、server.Rのソースコードを紹介します。

server = function(input, output, session) {
  observeEvent(input$file, {
    
    csv_file = reactive(read.csv(input$file$datapath))
    output$table = renderTable(csv_file())
    
    output$colname1 = renderUI({ 
      selectInput("x", "x軸方向", colnames(csv_file()))
    })
    output$colname2 = renderUI({ 
      selectInput("y", "y軸方向", colnames(csv_file()))
    })
  })
  
  observeEvent(input$submit, {
    name = names(input$file)
    csv_file = reactive(read.csv(input$file$datapath))
    
    x = csv_file()[input$x]
    y = csv_file()[input$y]
    
    output$plot = renderPlot({
      plot(x[,1], y[,1])
    })
  })
}

構成は前回と一緒ですね。
変わったところは、以下のファイルの受け取り方。

csv_file = reactive(read.csv(input$file$datapath))

input$file変数の、datapathという変数にテキストデータが格納されているので、上のように取り出して、csvファイルとして読み込みます。

ここまでできたら後は第12弾と全く一緒です!

読み込んだcsvファイルの列情報を元に、何をプロットするのか選択するためのUIをui.Rに返します。
その後ui.Rにてプロットボタンが押されれば、その情報を元にrenderPlotにてプロットを返しています。

このあたりも第12弾で解説したので、説明は省略させていただきます。

まとめ

今回はfileInputメソッドを使って、ファイルアップロード機能を作りました。

ドラッグ&ドロップによるファイルアップロードの場合は、どうしてもJavascriptの知識が必要となるのでハードルは高いかもしれませんが、こちらであればかなり簡単に書くことができます。

できれば両方実装できていると幅が広がって良いと思いますが、まずはfileInputを使ってアップロード機能を実装するというのが良いかもしれません。

是非試してみてください!