✏️

gganimateでリーマン和の近似を可視化する

2022/12/01に公開

概要

Rのgganimateというパッケージを使ってリーマン和の分割数を増やしていった時の近似具合を可視化してみました. 内容とその実装について紹介します.

実際出来上がったものはこちらです

リーマン和の分割数を増やしていった時

実装全体をとりあえず見れれば良いという方はこちらのリポジトリをご覧ください.

https://github.com/masayukeeeee/riemann-sum-animation

前提条件

  • R触ったことがある
  • ggplotはまぁなんとなくわかる

環境

  • MacOS Monterey12.6
  • RStudio 2022.07.2
  • packages
    • tidyverse
    • gganimate
    • transformr
    • gifski

やりたかったこと

プライベートで話をする際に,リーマン和を扱うシーンがありました.
そこでリーマン和において,その分割数nを大きく知っていた時の様子を可視化できれば,よりわかりやすい資料になるかなと思い立ち,今回の内容を実装しました.
※参考:Wikipedia

なぜRか

資料自体をRのbookdownで作っていたからです.

実装

近似する関数と区間

今回は基本的に,描画する区間I = [a,b]において{}^{\forall} x \in I, f(x) \geq 0という想定をしています.そうでない場合は,適宜そうなるように関数を変更してもらうか,実装を修正してもらうと良いと思います.

f <- function(x) x^3 - 2*x + 3
a <- -sqrt(2) - 0.3
b <- sqrt(2) + 0.3

また,分割数nについては10から300まで10区切りとしています.

ggplotの方針

gganimateを使う場合,あらかじめggplotに与えるデータフレームにプロットする全てのデータを与えておく必要がありそうです(そうでなかったらごめんなさい).

そのため,今回は指定する分割数n \in (10, 20, \ldots, 300)に対してあらかじめ必要な計算を済ませてデータフレームにまとめておきます.

for(split_n in split_ns){
  xbars <- seq(a,b,length.out=split_n+1)
  split_x <- matrix(rep(xbars, each=2), ncol=2, byrow=T) %>% 
    as_tibble() %>% set_names(c("x3", "x4"))
  split_x_lag1  <- dplyr::lag(split_x,1) %>% set_names(c("x1", "x2"))
  ps <- bind_cols(split_x_lag1, split_x) %>% drop_na() %>% 
    mutate(y1 = 0, y2 = f(x3), y3 = f(x3), y4 = 0)
  xs <- ps %>% select(x1, x2, x3, x4) %>% as.matrix() %>% t() %>% as.vector()
  ys <- ps %>% select(y1, y2, y3, y4) %>% as.matrix() %>% t() %>% as.vector()
  ps_longer <- data.frame(x=xs, y=ys) %>% as_tibble() %>% mutate(n = split_n)
  
  if(!exists("rieman_splits")){
    riemann_splits <- ps_longer
  }else{
    riemann_splits <- bind_rows(riemann_splits, ps_longer)
  }
}

結果として,riemann_splitsはこのような内容になっています.
nというカラムの値ごとにプロットを書き換えていくようなイメージになります.

    x     y     n
<dbl> <dbl> <dbl>
-1.71  0       10
-1.71  3.16    10
-1.37  3.16    20
-1.37  0       20
....
-1.03  3.97    290
-1.03  0       290
-1.03  0       300
-1.03  4.05    300

gganimateのセッティング

gganimateについて詳細はドキュメントを参照いただければと思いますが,
書き出し時に以下を設定することができます.

  • fps: frame per sec.デフォルト10
  • nframes: フレーム数.デフォルト100
  • duration: アニメーションの長さ. デフォルトは上記のfps, nframesによる.

これらの関係は以下のようになっているので, どれか二つを設定すれば良いです.

\text{fps} \times \text{nframes} = \text{duration}

ただし,プロットの数とfpsが倍数の関係になっていない場合は,途中でレンダリング途中の画像が出てきてしまう場合があるので注意してください.

以下は変な感じになってしまったものの例です.

# failed setting
output <- animate(anim, nframes=100, duration=10)

失敗例

ファイルの書き出し

アニメーションのオブジェクトを作成したら,最後レンダリングして書き出します.

output <- animate(anim, nframes=length(ns), duration=duration)
anim_save("riemann_sum_animation.gif", output)

終わりに

本記事ではgganimateを使ったアニメーションの作成の実装について紹介しました.
個人的には面白かったのでまた何か作ったら書いていこうと思います.

Discussion