Edited at
R ShinyDay 3

rintrojsでShinyアプリにチュートリアル機能を追加する

この記事では rintorjs パッケージを利用してShinyアプリにチュートリアル機能を追加する方法を紹介します。

Webアプリケーションにステップ・バイ・ステップのチュートリアル機能を追加するためのJavaScriptライブラリとして intro.js が知られています。rintorjs はその intro.js をShinyアプリで利用するためのパッケージです。


デモ

こちらにデモアプリを公開しました。


スクリーンショット




元となるShinyアプリを用意する

それでは作り方を解説していきます。

まずはチュートリアルの無いサンプルアプリを作成します。

ここではRStudioで新規Shinyプロジェクトを作成したときに用意されるおなじみのサンプルコードを利用します。


app.R

library(shiny)

# アプリケーションのUIを定義
ui <- fluidPage(

# アプリケーションのタイトル
titlePanel("Old Faithful Geyser Data"),

# サイドバー
sidebarLayout(
sidebarPanel(
# スライダー
sliderInput("bins",
"ビンの数:",
min = 1,
max = 50,
value = 30)
),

# メインパネル
mainPanel(
plotOutput("distPlot")
)
)
)

# サーバー側ロジックを定義
server <- function(input, output) {

output$distPlot <- renderPlot({
# ui.Rから来た input$bins に基づいてビンを生成
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)

# 指定のビン数でヒストグラムを描画
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}

# アプリケーションを起動する
shinyApp(ui = ui, server = server)

(もとのサンプルでは英語になっている部分を適宜日本語に変更しています。)


チュートリアルを追加する

このサンプルアプリを修正してチュートリアル機能を追加していきます。

まずはマシンにrintrojsパッケージをインストールしておきます。

install.packages("rintrojs")

次にapp.Rを書き換えます。


app.R

library(shiny)

library(rintrojs) # パッケージを読み込む

# アプリケーションのUIを定義
ui <- fluidPage(

introjsUI(), # これをUI定義のどこかに含める

# アプリケーションのタイトル
titlePanel("rintrojsで手軽にチュートリアルを実装"),

# サイドバー
sidebarLayout(
sidebarPanel(
introBox( # チュートリアルのステップ
sliderInput("bins", "ビンの数:", min = 1, max = 50, value = 30), # このステップでハイライトされる要素
data.step = 1, # ステップ番号
data.intro = "このスライダーを動かしてビンの数を変更してください" # このステップのメッセージ
),

actionButton("tutorial", "チュートリアルを開始")
),

# メインパネル
mainPanel(
introBox( # チュートリアルのステップ
plotOutput("distPlot"), # このステップでハイライトされる要素
data.step = 2, # ステップ番号
data.intro = "スライダーの値に合わせてこのヒストグラムが変化します" # このステップのメッセージ
)
)
)
)

# サーバー側ロジックを定義
server <- function(input, output, session) {

output$distPlot <- renderPlot({
# ui.Rから来た input$bins に基づいてビンを生成
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)

# 指定のビン数でヒストグラムを描画
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})

observeEvent(
input$tutorial, # tutorialボタンがクリックされたら
introjs( # チュートリアルを開始する
session,
options = list( # オプション設定
nextLabel = "次へ", # 次のステップへ進むボタンのラベル
prevLabel = "戻る", # 前のステップへ戻るボタンのラベル
skipLabel = "やめる", # チュートリアルをスキップするボタンのラベル
doneLabel = "完了", # チュートリアルを完了するボタンのラベル
showBullets = FALSE, # 進捗を表す中点マークを表示する/しない
showProgress = TRUE # プログレスバーを表示する/しない
)
)
)
}

# アプリケーションを起動する
shinyApp(ui = ui, server = server)

これを起動するとデモアプリと同じものが開始します。『チュートリアルを開始』ボタンをクリックして動作を確認してみましょう。


ポイント

サンプルコードのポイントを押さえていきます。


rintrojsパッケージの読み込み

library(rintrojs) # パッケージを読み込む


関数introjsUI()でintro.jsを有効化

UI定義の中のどこかに introjsUI() を入れる必要があります。

# アプリケーションのUIを定義

ui <- fluidPage(

introjsUI(), # これをUI定義のどこかに含める

# ...省略...

)


関数introBox()でステップを定義

introBox() でチュートリアルの各ステップを定義します。このとき、そのステップでハイライトされる要素を囲むようにします。

また、引数 data.step でステップ番号を、引数 data.intro でメッセージを指定します。

      introBox( # チュートリアルのステップ

sliderInput("bins", "ビンの数:", min = 1, max = 50, value = 30), # このステップでハイライトされる要素
data.step = 1, # ステップ番号
data.intro = "このスライダーを動かしてビンの数を変更してください" # このステップのメッセージ
),


チュートリアル開始の制御

サーバー側では、トリガーとなるイベント(この例では『チュートリアルを開始』ボタンクリック)を受けてチュートリアルが開始するよう observeEvent()introjs() を組み合わせて使用します。

また、ここでserver()の引数sessionintrojs()に渡すこともポイントです。

# サーバー側ロジックを定義

server <- function(input, output, session) {

# ...省略...

observeEvent(
input$tutorial, # tutorialボタンがクリックされたら
introjs( # チュートリアルを開始する
session,
options = list( # オプション設定

# ...省略...

)
)
)
}


intro.jsオプションの設定

introjs()の引数optionsで様々なオプションを設定します。設定可能なオプション項目についてはintro.jsの公式ドキュメントを参照ください。

今回のサンプルではボタンのラベルがデフォルトで英語になっているところを日本語にするなどの変更を行いました。

    introjs( # チュートリアルを開始する

session,
options = list( # オプション設定
nextLabel = "次へ", # 次のステップへ進むボタンのラベル
prevLabel = "戻る", # 前のステップへ戻るボタンのラベル
skipLabel = "やめる", # チュートリアルをスキップするボタンのラベル
doneLabel = "完了", # チュートリアルを完了するボタンのラベル
showBullets = FALSE, # 進捗を表す中点マークを表示する/しない
showProgress = TRUE # プログレスバーを表示する/しない
)
)


以上、rintorjs を利用してShinyアプリにチュートリアル機能を追加する方法を解説しました。

サンプルコードはGitHub (terashim/begin-shiny-rintrojs) でも公開しています。

rintorjs には他にもintrojs()と類似の関数hintjs()が用意されています。こちらはステップ・バイ・ステップのチュートリアルではなくUI上の各部にヒントボタンを表示するためのものです。hintjs()の利用法については他の機会にご紹介できればと思います。