はじめに
R言語のgganimateパッケージを使ってグラフを動かそうシリーズです。
この記事では、上下左右に移動する2次元のランダムウォークのアニメーションを作成します。
【前の内容】
【他の内容】
【目次】
2次元ランダムウォークの作図:2方向移動
2方向(上下左右)に移動するランダムウォーク(random walk)のアニメーションを作成します。
gganimate
パッケージの関数 transition_reveal()
については、「transition_reveal関数【gganimate】 - からっぽのしょこ」を参照してください。
利用するパッケージを読み込みます。
# 利用パッケージ library(gganimate) library(tidyverse)
この記事では、基本的に パッケージ名::関数名()
の記法を使うので、パッケージの読み込みは不要です。ただし、作図コードについてはパッケージ名を省略するので、ggplot2
を読み込む必要があります。
また、ネイティブパイプ演算子 |>
を使います。magrittr
パッケージのパイプ演算子 %>%
に置き換えられますが、その場合は magrittr
を読み込む必要があります。
1サンプル
まずは、1つのサンプルを描画します。
試行回数を指定して、移動する量と軸をランダムに生成します。
# 試行回数を指定 max_iter <- 100 # 乱数を生成 random_val_vec <- sample(c(-1, 1), size = max_iter, replace = TRUE) # ±1 random_axis_vec <- sample(c("x", "y"), size = max_iter, replace = TRUE) # x軸・y軸方向 head(random_val_vec); head(random_axis_vec)
[1] 1 1 -1 1 1 -1 [1] "y" "y" "y" "x" "x" "x"
試行ごとに「 -1
または 1
」と「 "x"
または "y"
」をランダムに(等確率で)割り当てます。"x"
はx軸方向、"y"
はy軸方向の変化に対応し、1
は正の方向、-1
は負の方向の移動に対応します。
移動量に応じた座標を計算します。
# 試行ごとに集計 trace_df <- tibble::tibble( iter = c(0, 0, 1:max_iter), # 試行番号 r = c(0, 0, random_val_vec), # 移動量 axis = c("x", "y", random_axis_vec) # 移動方向 ) |> tidyr::pivot_wider( names_from = axis, values_from = r, values_fill = 0 ) |> # 軸ごとの列に分割 dplyr::mutate( x = cumsum(x), y = cumsum(y) ) # 総移動量を計算 trace_df
# A tibble: 101 × 3 iter x y <dbl> <dbl> <dbl> 1 0 0 0 2 1 0 1 3 2 0 2 4 3 0 1 5 4 1 1 6 5 2 1 7 6 1 1 8 7 2 1 9 8 1 1 10 9 1 2 # ℹ 91 more rows
初期値(スタート地点・0回目の結果)を 0
として追加して、pivot_wider()
で軸ごとの列に展開して、それぞれ各試行までの和(累積和)を cumsum()
で計算します。
・簡単な例で確認(クリックで展開)
簡単な例で試してみます。
# 簡単な例で確認 wide_df <- tibble::tibble( iter = c(1, 2, 3), r = c(-1, 1, -1), axis = c("x", "y", "y") ) long_df <- wide_df |> tidyr::pivot_wider( names_from = axis, values_from = r ) wide_df; long_df
# A tibble: 3 × 3 iter r axis <dbl> <dbl> <chr> 1 1 -1 x 2 2 1 y 3 3 -1 y # A tibble: 3 × 3 iter x y <dbl> <dbl> <dbl> 1 1 -1 NA 2 2 NA 1 3 3 NA -1
移動量 -1, 1
を r
列、移動方向 "x", "y"
を axis
列としてデータフレームに格納します。
axis
列の "x", "y"
を列名として r
列の対応する行の値 -1, 1
を格納します。values_fill
引数を指定すると欠損値 NA
を置き換えられます。
点の推移のアニメーションを作成します。
# グラフサイズを設定 axis_size <- c(trace_df[["x"]], trace_df[["y"]]) |> abs() |> max() # 2次元ランダムウォークのアニメーションを作図 anim <- ggplot() + geom_hline(yintercept = 0, color = "red", linetype = "dashed") + # 初期値 geom_vline(xintercept = 0, color = "red", linetype = "dashed") + # 初期値 geom_path(data = trace_df, mapping = aes(x = x, y = y), size = 1) + # 軌跡 geom_point(data = trace_df, mapping = aes(x = x, y = y), size = 4) + # 現在地点 gganimate::transition_reveal(along = iter) + # フレーム切替 coord_fixed(ratio = 1, xlim = c(-axis_size, axis_size), ylim = c(-axis_size, axis_size)) + # アスペクト比 labs(title = "Random Walk", subtitle = "iteration: {frame_along}", x = "x", y = "y") # gif動画を作成 gganimate::animate( plot = anim, nframes = max_iter+1, fps = 10, width = 8, height = 8, units = "in", res = 250 )
初期値(期待値)を破線で示します。
複数サンプル
続いて、複数のサンプルを並べて描画します。
作図コードについては「GitHub - anemptyarchive/gganimate/.../RandomWalk.R」を参照してください。
・最終結果
・推移のアニメーション
等確率で移動する場合、初期値が期待値になりますが分散を持ち(散らばり)ます。
この記事では、格子状に移動する2次元ランダムウォークを扱いました。次の記事では、全ての方向に移動する場合を扱います。
おわりに
このタイプのランダムウォークは知ってましたが、360°方向に変化するパターンもあるんですね。というわけで次はそっちのタイプをやります。
- 2024.02.14:加筆修正しました。
元の記事を書いてから2年近くが経ちましたが、未だに90°・360°タイプの呼び方もどちらが一般的なのかも分かっていません。記事中では雰囲気で呼んでいます。このブログではこういうことが稀によくあります。
【次の内容】