R Shiny : プログラムのデバッグについて

本日はShinyでプログラムを作る際に必要となるデバッギングについてです。

想定通り動かない場合に変数の中身をチェックしたりは必須ですが、ここでは
私のようなShiny初心者でも使えるテクニックをピックアップして補足解説します。

本日のネタは以下のオフィシャルサイトをベースに最低限必要な情報を整理してまとめます。

今回使うサンプルプログラム

Shinyのチュートリアルにあるオールドフェイスフルの間欠泉データを使います。

(参考までに、old faithful geyserはアメリカにある最初に指定された国立公園にある有名な間欠泉のことです。
90分程度に1回判を押したように大規模に噴水するので観光客に人気です)

以下が今回利用するプログラムですが、コメントなどは外してさっぱりさせています。

library(shiny)
ui <- fluidPage(
titlePanel("Hello Shiny!"),
sidebarLayout(
sidebarPanel(
sliderInput(inputId = "bins",
label = "Number of bins:",
min = 1,
max = 50,
value = 30)
),
mainPanel(
plotOutput(outputId = "distPlot")
)
)
)
server <- function(input, output) {
output$distPlot <- renderPlot({
x    <- faithful$waiting
bins <- seq(min(x), max(x), length.out = input$bins + 1)
hist(x, breaks = bins, col = "#75AADB", border = "white",
xlab = "Waiting time to next eruption (in mins)",
main = "Histogram of waiting times")
})
}
shinyApp(ui, server)

ブレークポイントの設定

最も基本的なテクニックと思いますが、R Studioの標準エディターだけでしか動かず、他のエディターには対応していないのが残念ですね。

さて使い方はシンプルで、行番号の左端をクリックすると赤い丸印が出てきます。これでブレークポイントが設置できました。

f:id:okdata:20190908114733p:plain:w600

この状態でプログラムを実行するとブレークポイントでプログラムが停止して以下の画面が現れます。

f:id:okdata:20190908115228p:plain:w600

このときに画面右側のEnvironmentタブには以下のような変数情報が表示されます。

f:id:okdata:20190908115423p:plain:w600

変数xx <- faithful$waitingで情報を入れたところで停止しているので、
変数xに入ったデータの値(value)を表示して止まっています。

このプログラムではまだ変数xだけに情報を入れているのでこれしか表示していませんが、
その時点で登録された変数の情報はすべて確認することができます。

その後F10を押すごとに1ステップ実行していきますので、変数の中身などが想定通り入っているかなどを
確認することができます。

ブレークポイントの注意点

  1. ブレークポイントはserver.Rにしか設定できません。ui.Rやglobal.Rなどに設定したブレークポイントは無視されます。
  2. ブレークポイントはそのポイントが実行されたときにストップするので、そのコードが実行されていることはわかるが、
    ブレークポイントに到達しないと実行がストップしないので、”なぜこのコードが実行されないのか” がわからないという
    問題点がある。
  3. R StudioのIDEでしか動かない。

browser()

もう一つの解決方法がプログラムにブレークポイントbrowser()を記載する方法です。

基本的な使い方はブレークポイントと一緒で、プログラムを止めたい点にbrowser()のコードを挿入するだけですので簡単です。

以下の画面が実行した時の結果ですが、そのときに変数の情報がEnvironmentタブに表示さており基本的に同じように使えます。

f:id:okdata:20190908121044p:plain:w600

browser()によるブレークポイントはプログラムの中に埋め込めるので以下のような特徴を備えています。

  1. server.R以外でも埋め込める
  2. 条件付きでブレークポイントを発動させるなどの制御が可能となる。

以下ではセレクターが40以上になったときにブレークポイントが発動される例です。
プログラムを実行してスライダーを動かしてみてください。

f:id:okdata:20190908121511p:plain:w600

CATによる変数の出力

もう一つ極めて原始的なテクニックもご紹介します。

上記のデバッギングはR Studioの謹製ですが、簡単に確認する方法として
変数をログに出力させるという方法もあります。

ログ出力はcat関数を使います。

cat(file=stderr(), "myValue= ", myValue , "\n")
のように使います。

f:id:okdata:20190908122418p:plain:w600

スライダーを40以上にセットしたときに、input$binsの値がログにプリントされます。

プログラムにこれを仕掛けておけばコードがポーズした時点での途中経過を確認しながら進めることができます。

f:id:okdata:20190908122440p:plain:w400

CAT利用時の注意点

変数の動きを見るためにCATの中に表示する変数としてリアクティブ変数を使う場合プログラムの
動きが変になる可能性があるのでご注意ください。

背景として、リアクティブ変数はその中身が変化したときに自動的に反応するので、CATに含まれるリアクティブ変数により
想定していなかったタイミングで
リアクティブが働いて思わぬ部分(CAT周辺)のプログラムが実行されてしまう可能性があるためです。

くれぐれもCAT+リアクティブ変数の組み合わせは慎重にご利用ください。

グローバル変数に入れて後から確認する方法

Shinyのグローバル変数はいくつかの方法があって影響の範囲を理解するのがややこしいのが欠点です。

ui.Rserver.Rの中で設定した変数は、セッションを終了すると消えてしまいますが、その途中状況をスナップショットとして
残しておきたい場合などには変数の値をグローバル変数として放り込んでしまう方法があります。

具体的には、
test_outVar <<- outVarのように、残したい変数を(<<-)で変数に入れればセッションを終了しても値がEnvironmentに残ります。
プログラム終了後に値を確認したい場合などには使い道もあります。

Reactive Logパッケージを使ったリアクティブ動作のデバッグ

ここまでのテクニックは基本的に静的な変数の動きを確認するための手段を紹介してきました。

Shinyのプログラムを作っていて問題になるのがリアクティブな動きが想定通り働かないといったケースではないでしょうか。

こんな時に頼もしいツールがreactlogパッケージです。

使い方は簡単で、CRANからreactlogパッケージをインストールしたら、プログラムの頭に以下の2行を加えるだけです。

options(shiny.reactlog = TRUE)
library(reactlog)

ではold faithfulのプログラムに上記を追加して実行してみます。

プログラムはスライダーのインプット待ちで止まりますので、そのときに
Ctrl + F3`` (Mac: Cmd + F3)を実行してください。以下のようなリアクティブログ画面が立ち上がります。
(画面が立ち上がらないときは何度か押してみると良いようです)

f:id:okdata:20190908130132p:plain

この状態はその時点でのリアクティブ変数の状態を示しています。画面の上部に何種類かの矢印が出ているので一番左の矢印を押すとプログラムの最初の状態になります。
その後は右矢印(next step)を押していけばどういった順番に情報のやりとりがなされているのか見ることができます。

残念ながら私はまだこのreactlogを使いこなせていませんが、動きが変だと感じたときには使ってみると原因が特定できる可能性があります。
ただし、大きなプログラムになるとエレメントや矢印が複雑になるので扱いをうまくやる必要がありそうです。このあたりは、サーチ、フィルター、ズームなどいろいろな
機能が搭載されているようですので使いこなせれば強力なツールになると思います。

当面管理人を含むShinyの初級者には、原始的ではありますが、これまでに紹介したテクニックで変数に情報がうまく格納されたかを一つ一つ見ていくのが結局近道のように思います。

最後に

今回はShinyのチュートリアルをベースに管理人のレベルに合わせて必要な情報を整理してまとめてみました。

より詳細は以下のチュートリアルを参考にしてさらに深掘りしてください。