Np-Urのデータ分析教室

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

ShinyでGoogleスプレッドシートにアクセスするアプリケーション作成

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


Shiny100本ノック第14弾の今回は、GoogleスプレッドシートにアクセスするShinyアプリケーションを作成してみたいと思います。

スプレッドシートにアクセスできるようになると、

  • Googleスプレッドシート上に集計結果を表示させ、ファイルを保存
  • Googleスプレッドシートのデータを直接読み込んで分析

というツールを作れるようになります。

今回は、

  • Shinyアプリケーション上でGoogleアカウントの認証を行う
  • ドライブ内のスプレッドシートの一覧を表示する
  • ファイル名を指定して、そのファイル内のデータを表示させる

という機能を持つアプリケーションを作成してみます。

下準備

Googleスプレッドシートにアクセスするためには、GoogleのAPI(Google driveとspredsheet)を有効にし、クライアントIDとシークレットキーを取得する必要があります。

詳しい取得方法については、以下記事で紹介しているので、ご参照ください。
www.randpy.tokyo

クライアントIDとシークレットキーが取得できたら、どこかにメモしておきましょう。
下準備ができたところで、次節以降で具体的なコードを見ていきましょう。

server.Rとui.Rのソースコード

server.Rとui.Rのスクリプトをまずは貼り付けます。
後ほど躓きやすいところを解説していきます。

server.R

##server.R
library(shiny)
library(googleAuthR)
library(googlesheets)
library(plyr)
library(dplyr)
library(DT)

options(shiny.port = 1221)
options("googlesheets.webapp.client_id" = "クライアントID")
options("googlesheets.webapp.client_secret" = "シークレットキー")
options("googlesheets.webapp.redirect_uri" = "http://127.0.0.1:1221")

shinyServer(function(input, output, session) {
  gs_deauth(clear_cache = TRUE)
  ##ログインボタン
  output$loginButton <- renderUI({
    if (is.null(isolate(access_token()))) {
      tags$a("Authorize App",
             href = gs_webapp_auth_url(),
             class = "btn btn-default")
    } else {
      return()
    }
  })
   ##ログアウトボタン
  output$logoutButton <- renderUI({
    if (!is.null(access_token())) {
      tags$a("Logout",
             href = getOption("Googlesheets.webapp.redirect_uri"),
             class = "btn btn-default")
    } else {
      return()
    }
  })
  
  ## token取得部分
  access_token  <- reactive({
    pars <- parseQueryString(session$clientData$url_search)
    
    if (length(pars$code) > 0) {
      gs_webapp_get_token(auth_code = pars$code)
    } else {
      NULL
    }
  })
  
  output$table <- DT::renderDataTable({
    tmp_data <- with_shiny(f = gs_read, 
                           shiny_access_token = access_token(),
                           gs_title(input$file_name),
                           ws = as.integer(input$sheet_id))
    return(tmp_data)
  })
  
  output$allfile <- renderTable({
    read_data <- with_shiny(f = gs_ls, 
                            shiny_access_token = access_token())
    return(read_data)
    })
})


ui.R

## ui.R

library(shiny)
library(DT)

shinyUI(fluidPage(#theme = shinytheme("cerulean"),
  titlePanel("Google Spread sheet"),
  
  sidebarLayout(
    sidebarPanel(
      uiOutput("loginButton"),
      br(),
      uiOutput("logoutButton"),
      br(),
      textInput('file_name','ファイル名'),
      br(),
      selectInput('sheet_id','sheet',choices = c(1:26))
      )
    ),
  
  mainPanel(
    tabsetPanel(
      tabPanel("file一覧", tableOutput("allfile")),
      tabPanel("Table", DT::dataTableOutput("table"))
                )
            )
  )
))

コード解説

ui.Rに関しては、Googleアカウント連携が済んでいない状態ではログインボタンを表示し、連携済みであればログアウトボタンを表示するという設計になっています。

ログインボタンをクリックすると、どのGoogleアカウントと連携するかの選択画面に飛びます。アカウント連携が成功すると、元のShinyアプリケーション画面にリダイレクトします。

textinputでファイル名を入力し検索することができ、その後にDT::dataTableOutputの部分で、指定したファイルの中身を表示するようになっています。

さて、次にserver.Rについて見ていきましょう。

options(shiny.port = 1221)
options("googlesheets.webapp.client_id" = "クライアントID")
options("googlesheets.webapp.client_secret" = "シークレットキー")
options("googlesheets.webapp.redirect_uri" = "http://127.0.0.1:1221")

まず初めに、先程メモっておいたクライアントIDとシークレットキーを上記の部分に入力しましょう。
portとredirect_uriの部分は、特に自分でサーバーを立ててないという方は上記のものを使用してください。

##ログインボタン
  output$loginButton <- renderUI({
    if (is.null(isolate(access_token()))) {
      tags$a("Authorize App",
             href = gs_webapp_auth_url(),
             class = "btn btn-default")
    } else {
      return()
    }
  })
   ##ログアウトボタン
  output$logoutButton <- renderUI({
    if (!is.null(access_token())) {
      tags$a("Logout",
             href = getOption("googlesheets.webapp.redirect_uri"),
             class = "btn btn-default")
    } else {
      return()
    }
  })

ログインボタンとログアウトボタンの切り替えは、access_token()を取得済みかどうかで表示を切り替えています。

ログインする際は、href = gs_webapp_auth_url()で認証画面に飛び、ログアウトする際は、href = getOption("googlesheets.webapp.redirect_uri")のところで、リダイレクトURIに指定したURLにリダイレクトするようになっています。

以下はtoken取得部分のコードになります。

## token取得部分
  access_token  <- reactive({
    pars <- parseQueryString(session$clientData$url_search)
    
    if (length(pars$code) > 0) {
      gs_webapp_get_token(auth_code = pars$code)
    } else {
      NULL
    }
  })

Googleアカウントと認証成功すると、元のShiny画面にリダイレクトされるのですが、その際にURLに色々パラメータが付与された状態で戻ってきます。

それをparseQueryStringでパースし、codeパラメータを元にgs_webapp_get_tokenメソッドを使ってトークン情報を取得してきます。

さて、以上の部分がShinyからGoogleスプレッドシートを扱うための基本構造です。
これをベースに色々機能を追記してみましょう。

今回はGoogleスプレッドシートによるアプリ例として、textInput部分で指定したファイル名をテーブル表示するようにしています。

output$table <- DT::renderDataTable({
    tmp_data <- with_shiny(f = gs_read, 
                           shiny_access_token = access_token(),
                           gs_title(input$file_name),
                           ws = as.integer(input$sheet_id))
    return(tmp_data)
  })

with_shiny(f = '関数', shiny_access_token = '取得したtoken', ~使用関数のオプション)で、access_tokenを読み込んで、Googlesheetの関数を使用することが可能です。

今回は、gs_readというメソッドを使いましたが、公式のPackage ‘googlesheets’を参考にしつつ、リクエスト文を変更することでオリジナルアプリケーションを作成してみてください。

注意点

上記のコードで認証の手続きを説明しましたが、少し注意すべきことがあります。

ローカルでいじるのではなく、サーバーにアップロードして複数人数で同時アクセスする場合、Googleアカウント認証がうまくいかないケースがあります。
これはライブラリの作成者も現在対応中とのことで、私も色々試したのですが結局防ぐことができませんでした。

もし複数人数での運用を検討している場合は、気を付けるようにしてください。
(対策方法を思いついたら追記します。)

アプリ実演

どのようなアプリケーションが作れたのか、スクショを用いならが説明していきます。

アプリを立ち上げる前に、スプレッドシートにアクセスできているか確認できるように、サンプルファイルを作っておきたいと思います。
testというファイル名で、中身は以下のように作成しました。
f:id:gl2000-sans:20171202171919p:plain

さて、アプリを立ち上げると、初めに以下のような画面が表示されます。
f:id:gl2000-sans:20171202172038p:plain

左上にあるAuthorizeボタンを押してみましょう。

すると以下のようにGoogleアカウントの認証を求められるので、自分がアクセスしたいアカウントを選びましょう。
f:id:gl2000-sans:20171202170444p:plain

アカウントの認証が成功したら、file一覧の所に、ドライブ内にあるスプレッドシートの一覧が表示されます。
f:id:gl2000-sans:20171202170742p:plain
そして先程のAuthorizeボタンの位置にlogoutボタンが表示されているかと思います。

Googleアカウントを変えたいときは、こちらのボタンを押すことでログアウトできます。

左のファイル名を入力する部分に、ファイル名を入力することで、ファイルにアクセスすることができます。
またsheetという部分で、アクセスしたいシート番号を指定できます。

さて、本当にアクセスできているのか、試しに先程作ったファイル"test"と打ってみましょう。
f:id:gl2000-sans:20171202172210p:plain
右上のtableタグを開いてみると、きちんとデータにアクセス出来ていますね。

今回はシート内のデータを取ってきましたが、ドライブ内に新たにシートを作ることも可能です。(その場合、Googleアカウント認証時に結構強い権限が要求されます。)

集計や分析結果を新しいスプレッドシートを作って保存しておくといったことができると、共有するときは便利ですね。

終わりに

今回はShinyからスプレッドシートにアクセスする方法について解説してみました。

先程も触れた通り、まだ限定的な場面でのユースケースにしか対応できいません。
現在のところは、そこまで実用的ではないかもしれませんが、Googleスプレッドシートに直接アクセスできると色々と便利だと思うので、是非試してみてください。