本文へスキップ
からだにいいもの

Rのトピックスを中心に『まだ、まだ、知らない、役に立つ情報?』を発信します。

Rで解析:ggplot2の図をAnime.jsで動くSVGにする「gganime」パッケージの紹介

時間とともに変化するデータは、静止した図を並べるよりも、動きのある表現の方が推移を追いやすい場面があります。しかし、gganimateで作成したアニメーションをGIFや動画として書き出すと、ファイルの容量が大きくなり、拡大したときに輪郭がぼやける、再生位置を指定しにくいといった手間がかかります。

「gganime」パッケージは、gganimateで定義した図をAnime.jsというJavaScriptライブラリを用いて、ブラウザ上で動作するSVGアニメーションのウィジェットへ変換します。フレーム数や再生速度、ウィジェットの大きさの指定、ループ回数の制限、再生と一時停止の操作バーの表示が可能です。

また、gganimeOutputとrenderGganimeによるShinyアプリへの埋め込みも可能です。本パッケージの利用で、解像度に依存しない動的なグラフをHTMLの一部として扱えるのではないかと考えます。

パッケージバージョンは0.1.0。Windows 11 x64 (build 26200)のR version 4.6.1で確認しています。

パッケージのインストール

下記コマンドを実行してください。

# パッケージのインストール
install.packages("gganime")

# パッケージの読み込み
library("gganime")

# コマンド例実行で必要なパッケージを読み込み
library("ggplot2")
library("shiny")
スポンサーリンク

コマンド例

詳細はコメント、パッケージのヘルプを確認してください。

gganimeは、gganimateの記法をそのまま使います。ggplot2で作成した図にtransition_states()やtransition_time()などの時間遷移を加えると、gganim(アニメーションの設計図)というオブジェクトになります。gganimateのtransition_states、transition_time、transition_reveal、ease_aes、enter_fade、exit_fade、shadow_mark などの関数はgganimeからも読み込めるため、library(“gganimate”) を別途行う必要はありません。

anime()はこのgganimオブジェクトを受け取り、指定した数のフレームで図を描き分け、フレーム間の座標の変化をAnime.jsで補間するSVGアニメーションのウィジェットに変換します。出力はhtmlwidgetのため、R Markdownやシャイニー、単体のHTMLファイルとして保存できます。

ここでは、京都の主要な観光地(嵐山、伏見稲荷、宇治、天橋立)について、1年を隔月で区切った推計入込客数、平均気温、月間降水量をまとめた擬似データを共通データとして使用します。桜と紅葉の時期に客数が増える動きを、月の経過に沿ったアニメーションで確認します。

# 京都の観光地の隔月データを模したデータフレームの作成(4地点×6時点=24行)
観光 <- data.frame(
  # 観光地の名称
  地点 = factor(rep(c("嵐山", "伏見稲荷", "宇治", "天橋立"), each = 6)),
  # 対象の月(隔月)
  月 = rep(c(1, 3, 5, 7, 9, 11), times = 4),
  # 月の平均気温(℃)
  気温 = c(
    4, 9, 19, 27, 23, 12,
    4, 9, 19, 27, 23, 12,
    4, 9, 18, 27, 23, 12,
    3, 8, 17, 26, 22, 11
  ),
  # 月間の推計入込客数(万人)
  客数 = c(
    18, 42, 30, 22, 28, 55,
    22, 35, 28, 25, 26, 40,
    8, 15, 14, 12, 13, 22,
    4, 9, 12, 20, 11, 10
  ),
  # 月間降水量(mm)
  降水量 = c(
    50, 110, 150, 220, 180, 70,
    50, 110, 150, 220, 180, 70,
    48, 108, 150, 210, 175, 68,
    60, 120, 140, 200, 190, 80
  )
)

[アニメーション付きSVGウィジェットの生成]:animeコマンド

transition_*()を加えたgganimオブジェクトを、Anime.jsで動作するSVGアニメーションのウィジェットに変換します。フレーム数や再生速度、ウィジェットの大きさ、ループ回数、操作バーの有無を指定できます。

オプション意味初期値
plottransition_*()を加えたgganimオブジェクト(ggplot2の図に時間遷移を付けたもの)なし
nframesアニメーションを標本化するフレーム数100
fps毎秒のフレーム数。再生速度を決める10
duration総再生時間(秒)。指定するとfpsより優先されるNULL
widthウィジェットの横幅(ピクセル)。heightとの比が図の縦横比になる640
heightウィジェットの高さ(ピクセル)480
precisionアニメーションさせる座標を丸める小数点以下の桁数2
loopループの指定。TRUE、FALSE、または繰り返し回数の数値TRUE
controls再生・一時停止と再生位置の操作バーを表示するかTRUE
elementIdhtmlwidgetの要素IDの指定NULL
…未使用。将来の引数のための予約なし
# 気温と入込客数の関係を月ごとに描き分けるgganimオブジェクトの作成
p <- ggplot(観光, aes(気温, 客数, size = 降水量, colour = 地点)) +
  geom_point(alpha = 0.8) +
  # 図の主題に現在の月を表示する
  labs(title = "{closest_state}月の京都観光", size = "降水量(mm)") +
  # 月の値ごとに状態を切り替えるアニメーション
  transition_states(月)

# 既定の設定でSVGアニメーションのウィジェットを生成
anime(p)

# フレーム数と再生速度、ウィジェットの大きさを指定して生成
anime(p, nframes = 60, fps = 15, width = 720, height = 540)

# ループを2回に制限し、操作バーを非表示にして生成
anime(p, loop = 2, controls = FALSE)

実際のプロットはアニメーションします。

[Shinyアプリへのアニメーション表示枠の配置]:gganimeOutputコマンド

ShinyアプリのUI側で、gganimeのアニメーションを表示する領域を宣言します。出力IDと表示枠の大きさを指定します。

オプション意味初期値
outputId読み取り先となる出力変数の名前なし
width妥当なCSS単位(”100%”、”400px”、”auto” など)または数値。数値は文字列に変換され “px” が付く“100%”
height妥当なCSS単位(”100%”、”400px”、”auto” など)または数値。数値は文字列に変換され “px” が付く“400px”
# ShinyアプリのUIでアニメーションの表示枠を宣言する
ui <- fluidPage(
  titlePanel("京都観光の月別推移"),
  # 出力IDと表示枠の大きさを指定する
  gganimeOutput("観光アニメ", width = "600px", height = "450px")
)

[Shinyサーバーでのアニメーションの描画]:renderGganimeコマンド

Shinyアプリのサーバー側で、anime()が返すウィジェットを生成する式を評価し、UIのgganimeOutputへ描画します。exprにはanime()の呼び出しを含む式を渡します。

オプション意味初期値
exprgganimeのウィジェットを生成する式。通常はanime()の呼び出しなし
envexprを評価する環境parent.frame()
quotedexprがquote()で囲んだ式かどうか。式を変数に保存して渡す場合に使うFALSE
# UIのgganimeOutputに対応する描画処理をサーバーで定義する
server <- function(input, output, session) {
  output$観光アニメ <- renderGganime({
    p <- ggplot(観光, aes(気温, 客数, size = 降水量, colour = 地点)) +
      geom_point(alpha = 0.8) +
      transition_states(月)
    # anime()が返すウィジェットをそのまま描画する
    anime(p, width = 600, height = 450)
  })
}

# 定義したUIとサーバーを渡してアプリを起動する
if (interactive()) {
  shinyApp(ui, server)
}


この記事が誰かの役に立ちますように。

スポンサーリンク
価格および配送状況は変更される場合があります。購入時は商品ページをご確認ください。
当サイトに表示されている商品情報はAmazonから提供されたものであり、更新または削除される場合があります。
karada-goodはAmazonアソシエイトとして、適格販売により収入を得ています。