Shinyに手を出したらエラーを吐き出されたので何を言ってるのか纏めてみる
そのまま。
諸事情でShinyを使うことにした。
そこそこの大きさのデータを細かい条件で少しずつ弄りながら解析してみるとか、複数ファイルを読み込んで所定の動きをさせたいとか、そういうやり方をするならWebアプリ化しておくと毎度コード書き換えなくてもいいので便利だなと。
というか、「同じような解析を複数ファイルに行うなら、わざわざファイルパス書くの面倒じゃね?」ってことに、R使い3年目にしてようやく気付いた()。
という訳で、今ちょうど業務で回している解析向けにアプリをちまちま組んでいるのだが、その時に当然の如くエラーが出てくる。
そのまま捨てるのももったいないので、一応そのエラー毎に「大体この辺が絡んでいるっぽい」ってのを纏めておく。
なお、記載しているエラーは「とりあえずアプリは立ち上がる」場合のエラーのみなので、例えばrenderPlot()とかでグラフを出力するコードにエラーがある場合は本来グラフが出力される場所にエラー内容が出てくるので、個別には記載しない。
あくまで「コンソール上にエラーメッセージが出てる」とか「アプリを起動してる途中で落ちた」場合に確認するための内容という認識で進めていく。
Error in .getReactiveEnvironment()$currentContext() : Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
エラー内容そのままだが、「reactive()に入れないといけないものがなってないよ」って意味。
大抵は新しい変数を立てる時、reactive()の絡んでいる変数が含まれているのにreactive()で囲んでいないパターンが多い。
#ui.Rから指定ファイルのパスを取得 filepath <- reactive({ input$file$datapath }) #これだとエラー dat <- filepath() %>% read_csv() #reactiveな変数が含まれる場合はreactive()で囲む dat <- reactive({ filepath() %>% read_csv() })
「とりあえず全部reactive()で囲んでおけばいいわ」くらいのテンションでいると平和かもしれない。
- 警告: Error in [[: 添え字が許される範囲外です - Error : Argument 1 must be a data frame or a named atomic vector.
これも上と似たような感じだが、どっかのreactiveな変数を使う時に変数の後ろの「()」が抜けているパターンが多い気がする。
#ui.Rから指定ファイルのパスを取得 filepath <- reactive({ input$file$datapath }) #filepathの後ろに()が必要なのでエラーを吐く dat <- reactive({ filepath %>% read_csv() })
「Listening on http://~」以降に行かない
Shinyを走らせるとコンソールに「Listening on http://~」というメッセージが出て、その後に各コードの処理がコンソールに表示される。 これが最初のメッセージで止まって進まない場合は、「ui.R内のinput関連」か「server.R内のoutput関連」のどっかで変数名が競合していて引っ掛かっている場合が多い。
ちょっとびっくりしたのがoutputでserver.Rからui.Rに結果を返す時の挙動。 「ui.R内の2ヵ所の*Output()に同じ結果を返す場合でも、server.R内ではoutput$~を2つ別々に用意する必要がある」ということ。
言葉だと分かりにくいのでコードで書いてみる。 まずはserver.R側のコード。
### server.R server <- function(input, output) { output$text1 <- renderText( "これはサンプルコードです。" ) output$text2 <- renderText( "This is sample code." ) }
文字を送るだけ。
これをui.Rで受け取る時に同じ変数を2回使うと、上で書いたように最初のメッセージから進んでくれなくなってしまう。
### ui.R ui <- fluidPage( titlePanel("Basic widgets"), fluidRow( column(12, h3( textOutput("text1") ), h3( textOutput("text2") ), hr(), h3( textOutput("text1") ) ) ) ) shinyApp(ui, server)
なので、同じ文章を送る場合でも変数は別に立てて送る必要がある。
### ui.R ui <- fluidPage( titlePanel("Basic widgets"), fluidRow( column(12, h3( textOutput("text1") ), h3( textOutput("text2") ), hr(), h3( textOutput("text3") ) ) ) ) ### server.R server <- function(input, output) { output$text1 <- renderText( "これはサンプルコードです。" ) output$text2 <- renderText( "This is sample code." ) output$text3 <- renderText( "これはサンプルコードです。" ) } shinyApp(ui, server)
Shinymoduleを使えばこの辺は改善できるみたいだけど、まだ試している最中なので記事に載せるのは止めておく。必要な人は調べてみていただければ。
とりあえず簡単なアプリを作った時に引っ掛かったのがこの辺だった。 また何かあれば更新するかも。
Enjoy!