概要
Jupyter / ipywidgetsで__簡易__アニメーションプレイヤーを実装しました.
以下のような形でアニメーションを再生できます.
そもそものモチベーションとしては,「連番画像を手軽にJupyterで再生したい」でした.
方法としてmatplotlib.animation
が真っ先に浮かんだのですが,これを用いてスムーズに実装できた事が私はあまり無く,時間を注ぐような部分でもなかったので,今回はipywidgets
単体でのシンプルな実装を試みました.
実装
以降のコードでは,連番画像は変数 movie
に入っており,そのshapeは (t, h, w, c)
であるものとします.
import os
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
from ipywidgets import IntSlider
from ipywidgets import Play, jslink, HBox
from ipywidgets import interactive_output
まず本体のコードになります.今回は ipywidgets
の Play
, IntSlider
, interactive_output
などを組み合せてプレイヤーを実装しています.
def plotPlayer(plot, start, end, interval=250, step=1):
play = Play(min=start,
max=end,
step=step,
interval=interval,
description="Press play",
disabled=False
)
slider = IntSlider(min=start, max=end)
jslink((play, 'value'), (slider, 'value'))
controller = HBox([play, slider])
output = interactive_output(plot, {'t': slider})
return display(controller, output)
Play
は再生・一時停止・停止・リピートといったようなプレイヤー部分を,IntSlider
はその名の通り,スライダー部分となっています.jslink
はプレイヤーとスライダーの同期を取っています.
各引数の意味や,他の Widget
については, 公式ドキュメント がコード例もついていてわかりやすいのでそちらを参照ください.このコードも殆どそれに沿ったものになっています.
最後の2行で,ここまでで作成したWidgetと,画像表示部分を合わせて表示しています.innteractive_output()
の引数にある plot
ですが,これはアニメーションさせたいものに合わせて自分で作る必要のある関数です.今回は画像表示のために以下のような関数を用意しています.至って単純なプロットを行う関数ですが,注意点としては,引数の t
が innteractive_output()
の第2引数と対応しているという点です.ここを合わせておかないと,全てが同期して動いてくれません.
def plotMovie(t, figsize=(12, 8)):
plt.figure(figsize=figsize)
plt.imshow(movie[t])
plt.grid(False)
plt.show()
最後に,以下のコードを実行すれば,最初のgifのようにプレイヤーが起動します.
# np.shape(movie) -> (t, h, w, c)
plotPlayer(plotMovie, 0, len(movie)-1, interval=250)
ちなみに画像である必要はなく,plotMovie()
を変更することでグラフなども再生することが可能です.
def plotLine(t, figsize=(16, 8)):
plt.figure(figsize=figsize)
plt.xlim(0, 10)
plt.ylim(-5, 5)
plt.plot(x[:t], y[:t])
x = np.arange(0, 100, 0.1)
y = np.sin(x) + np.random.randn(len(x))
plotPlayer(plotLine, x[0], x[-1], interval=100)
最後に
gifを見て頂けると分かるかと思いますが,上記の私の実装では,どうしても「カクつき(ラグ)が生じる」「保存はできない」という問題点が生じており,再生スピード(interval
)を上げると何とも微妙な感じになってしまいます.(もっとも私の本来の目的の上では特に問題ではなかったのですが,)これがタイトルでも"簡易"と入れている理由になります.