はじめに
ランダムな位置に出現する絵文字が拡大し消えていくアニメーションをmatplotlib, FuncAnimationで表示する。
下記記事の雨のアニメーションを参考にして作成した。

コード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import HTML
#create ini data
n_drops = 20
emoji_drops = np.array(np.zeros(n_drops),
dtype=[('position', 'f8',2),('size','f8'),('growth','f8'),('alpha', 'f8')])
emoji_drops['position'] = np.random.uniform(0, 1, (n_drops, 2))
emoji_drops['growth'] = np.random.uniform(10, 20, n_drops)
emoji_drops['size'] = np.random.rand(n_drops)*20
emoji_drops['alpha'] = np.ones(n_drops)
emoji_drops
'''
array([([0.525481 , 0.9525733 ], 11.40640517, 16.97890011, 1.),
([0.47591703, 0.20430895], 13.11647633, 18.40863668, 1.),
([0.87154477, 0.2623594 ], 2.18445179, 16.54755482, 1.),
([0.23675945, 0.47664944], 14.52640135, 18.06419404, 1.),
([0.07954715, 0.56022691], 13.42285269, 14.20729541, 1.),
([0.81544536, 0.04151431], 10.04656556, 13.20391036, 1.),
([0.42159024, 0.07903694], 6.6884128 , 19.7719662 , 1.),
([0.05697779, 0.48979293], 4.57498104, 16.99453915, 1.),
([0.70958286, 0.15696977], 18.00021145, 10.67566331, 1.),
([0.26698077, 0.1733919 ], 19.82952921, 13.36839084, 1.),
([0.81591394, 0.53246656], 15.47280466, 19.68430789, 1.),
([0.11243768, 0.52536727], 9.05800302, 16.94833053, 1.),
([0.993191 , 0.66019158], 3.50660599, 12.5812297 , 1.),
([0.37264631, 0.66956094], 16.4602031 , 14.66848912, 1.),
([0.77868742, 0.13085961], 2.25006547, 16.72627871, 1.),
([0.29315259, 0.1148292 ], 16.2123757 , 18.38888197, 1.),
([0.224187 , 0.98843321], 3.48138286, 19.11202544, 1.),
([0.85439632, 0.55499377], 10.88810717, 15.0667364 , 1.),
([0.09051999, 0.49917992], 6.10093697, 18.37969202, 1.),
([0.21668941, 0.05439581], 17.59723974, 10.87886474, 1.)],
dtype=[('position', '<f8', (2,)), ('size', '<f8'), ('growth', '<f8'), ('alpha', '<f8')])
'''
#animation 1
fig = plt.figure(figsize=(6, 6))
ax = fig.add_axes([0, 0, 1, 1], frameon=False)
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis('off')
ax.scatter(emoji_drops['position'][:, 0], emoji_drops['position'][:, 1],alpha=0)
marker1 = '😃'
for x,y,s,a in zip(emoji_drops['position'][:, 0], emoji_drops['position'][:, 1],emoji_drops['size'],emoji_drops['alpha']):
scat = ax.annotate(marker1, (x,y),fontsize=s, ha='center',va='center',alpha=a,
xytext=(0,0), textcoords='offset pixels')
def update(frame_number):
# Get an index which we can use to re-spawn the oldest emoji.
current_index = frame_number % n_drops
# Make all emojies more transparent as time progresses.
emoji_drops['alpha'] -= 1.0/len(emoji_drops)
emoji_drops['alpha'] = np.clip(emoji_drops['alpha'], 0, 1)
# Make all emojies bigger.
emoji_drops['size'] += emoji_drops['growth']
# Pick a new position for oldest emoji, resetting its size,
# alpha and growth factor.
emoji_drops['position'][current_index] = np.random.uniform(0, 1, 2)
emoji_drops['size'][current_index] = np.random.rand(1)*20
emoji_drops['alpha'][current_index] = 1
emoji_drops['growth'][current_index] = np.random.uniform(10, 20)
# Update the scatter collection, with the new colors, sizes and positions.
ax.cla()
for x,y,s,a in zip(emoji_drops['position'][:, 0], emoji_drops['position'][:, 1],emoji_drops['size'],emoji_drops['alpha']):
scat = ax.annotate(marker1, (x,y),fontsize=s, ha='center',va='center',
alpha=a,xytext=(0,0), textcoords='offset pixels')
ani = FuncAnimation(fig, update, interval=50)
ani.save('emoji_expand1.mp4', writer="ffmpeg",dpi=100)
HTML(ani.to_html5_video())
解説
モジュールのインポートなど
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import HTML
バージョン
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version
import IPython
import matplotlib
print(matplotlib.__version__)
print(IPython.__version__)
print(np.__version__)
#3.2.0
#7.13.0
#1.18.1
データの作成
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#create ini data
n_drops = 20
emoji_drops = np.array(np.zeros(n_drops),
dtype=[('position', 'f8',2),('size','f8'),('growth','f8'),('alpha', 'f8')])
emoji_drops['position'] = np.random.uniform(0, 1, (n_drops, 2))
emoji_drops['growth'] = np.random.uniform(10, 20, n_drops)
emoji_drops['size'] = np.random.rand(n_drops)*20
emoji_drops['alpha'] = np.ones(n_drops)
emoji_drops
'''
array([([0.525481 , 0.9525733 ], 11.40640517, 16.97890011, 1.),
([0.47591703, 0.20430895], 13.11647633, 18.40863668, 1.),
([0.87154477, 0.2623594 ], 2.18445179, 16.54755482, 1.),
([0.23675945, 0.47664944], 14.52640135, 18.06419404, 1.),
([0.07954715, 0.56022691], 13.42285269, 14.20729541, 1.),
([0.81544536, 0.04151431], 10.04656556, 13.20391036, 1.),
([0.42159024, 0.07903694], 6.6884128 , 19.7719662 , 1.),
([0.05697779, 0.48979293], 4.57498104, 16.99453915, 1.),
([0.70958286, 0.15696977], 18.00021145, 10.67566331, 1.),
([0.26698077, 0.1733919 ], 19.82952921, 13.36839084, 1.),
([0.81591394, 0.53246656], 15.47280466, 19.68430789, 1.),
([0.11243768, 0.52536727], 9.05800302, 16.94833053, 1.),
([0.993191 , 0.66019158], 3.50660599, 12.5812297 , 1.),
([0.37264631, 0.66956094], 16.4602031 , 14.66848912, 1.),
([0.77868742, 0.13085961], 2.25006547, 16.72627871, 1.),
([0.29315259, 0.1148292 ], 16.2123757 , 18.38888197, 1.),
([0.224187 , 0.98843321], 3.48138286, 19.11202544, 1.),
([0.85439632, 0.55499377], 10.88810717, 15.0667364 , 1.),
([0.09051999, 0.49917992], 6.10093697, 18.37969202, 1.),
([0.21668941, 0.05439581], 17.59723974, 10.87886474, 1.)],
dtype=[('position', '<f8', (2,)), ('size', '<f8'), ('growth', '<f8'), ('alpha', '<f8')])
'''
numpyの構造化配列で作成する。pandasのDataFrameのような感じで配列の要素を変更することができる。
np.random.uniform(10, 20, n_drops)で10〜20の値を持つ要素数n_dropsの配列を作成する。
np.random.rand(n_drops)*20では0〜20の要素をもつ要素数n_dropsの配列を作成する。
初期データで図を表示
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#show ini data
fig = plt.figure(figsize=(4, 4))
ax = fig.add_axes([0, 0, 1, 1], frameon=False)
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis('off')
ax.scatter(emoji_drops['position'][:, 0], emoji_drops['position'][:, 1],alpha=0)
marker1 = '😃'
for x,y,s,a in zip(emoji_drops['position'][:, 0], emoji_drops['position'][:, 1],emoji_drops['size'],emoji_drops['alpha']):
scat = ax.annotate(marker1, (x,y),fontsize=s, ha='center',va='center',alpha=a,
xytext=(0,0), textcoords='offset pixels')
plt.savefig('emoji_expand.png',dpi=100)
plt.show()
図中への絵文字の表示は下記記事と同様にannotateで行う。

絵文字は文字列扱いなのでfontsizeでサイズを変更する。
図示すると以下のようになる。

アニメーション関数の設定
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def update(frame_number):
# Get an index which we can use to re-spawn the oldest emoji.
current_index = frame_number % n_drops
# Make all emojies more transparent as time progresses.
emoji_drops['alpha'] -= 1.0/len(emoji_drops)
emoji_drops['alpha'] = np.clip(emoji_drops['alpha'], 0, 1)
# Make all emojies bigger.
emoji_drops['size'] += emoji_drops['growth']
# Pick a new position for oldest emoji, resetting its size,
# alpha and growth factor.
emoji_drops['position'][current_index] = np.random.uniform(0, 1, 2)
emoji_drops['size'][current_index] = np.random.rand(1)*20
emoji_drops['alpha'][current_index] = 1
emoji_drops['growth'][current_index] = np.random.uniform(10, 20)
# Update the scatter collection, with the new colors, sizes and positions.
ax.cla()
for x,y,s,a in zip(emoji_drops['position'][:, 0], emoji_drops['position'][:, 1],emoji_drops['size'],emoji_drops['alpha']):
scat = ax.annotate(marker1, (x,y),fontsize=s, ha='center',va='center',
alpha=a,xytext=(0,0), textcoords='offset pixels')
current_index = frame_number % n_dropsでリセットするインデックスを決めておく。
emoji_drops[‘alpha’] -= 1.0/len(emoji_drops)でalpha値を下げていき、np.clip(emoji_drops[‘alpha’], 0, 1)で0を下回ったときに0とし、1を上回ったときに1とする。
emoji_drops[‘size’] += emoji_drops[‘growth’]でsizeにgrowthを加えていくことでsizeを大きくしていく。
78-81行ではcurrent_indexのデータをリセットしている。
ax.cla()で表示されている図をけして、すべてのデータを再びannotateで表示することでアニメーションとする。
アニメーションの表示
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ani = FuncAnimation(fig, update, interval=50)
ani.save('emoji_expand1.mp4', writer="ffmpeg",dpi=100)
HTML(ani.to_html5_video())
FuncAnimationでアニメーションを表示する。frame数はデフォルトで100なのでintervalが50msの場合、5秒のアニメーションとなる。 HTML(ani.to_html5_video())
により、jupyter notebook またはjupyter lab上にアニメーションを表示できる。
ani.save(‘ファイル名’, writer=”ffmpeg”,dpi=100)でアニメーションをMP4形式で保存することができる。
マーカーを😎とした場合
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#animation 2
fig = plt.figure(figsize=(6, 6))
ax = fig.add_axes([0, 0, 1, 1], frameon=False)
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis('off')
ax.scatter(emoji_drops['position'][:, 0], emoji_drops['position'][:, 1],alpha=0)
marker1 = '😎'
for x,y,s,a in zip(emoji_drops['position'][:, 0], emoji_drops['position'][:, 1],emoji_drops['size'],emoji_drops['alpha']):
scat = ax.annotate(marker1, (x,y),fontsize=s, ha='center',va='center',alpha=a,
xytext=(0,0), textcoords='offset pixels')
def update(frame_number):
current_index = frame_number % n_drops
emoji_drops['alpha'] -= 1.0/len(emoji_drops)
emoji_drops['alpha'] = np.clip(emoji_drops['alpha'], 0, 1)
# Make all circles bigger.
emoji_drops['size'] += emoji_drops['growth']
emoji_drops['position'][current_index] = np.random.uniform(0, 1, 2)
emoji_drops['size'][current_index] = np.random.rand(1)*20
emoji_drops['alpha'][current_index] = 1
emoji_drops['growth'][current_index] = np.random.uniform(10, 20)
ax.cla()
for x,y,s,a in zip(emoji_drops['position'][:, 0], emoji_drops['position'][:, 1],emoji_drops['size'],emoji_drops['alpha']):
scat = ax.annotate(marker1, (x,y),fontsize=s, ha='center',va='center',
alpha=a,xytext=(0,0), textcoords='offset pixels')
ani = FuncAnimation(fig, update, interval=50)
ani.save('emoji_expand2.mp4', writer="ffmpeg",dpi=100)
HTML(ani.to_html5_video())
マーカーを😴とした場合
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#animation 3
fig = plt.figure(figsize=(6, 6))
ax = fig.add_axes([0, 0, 1, 1], frameon=False)
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis('off')
ax.scatter(emoji_drops['position'][:, 0], emoji_drops['position'][:, 1],alpha=0)
marker1 = '😴'
for x,y,s,a in zip(emoji_drops['position'][:, 0], emoji_drops['position'][:, 1],emoji_drops['size'],emoji_drops['alpha']):
scat = ax.annotate(marker1, (x,y),fontsize=s, ha='center',va='center',alpha=a,
xytext=(0,0), textcoords='offset pixels')
def update(frame_number):
current_index = frame_number % n_drops
emoji_drops['alpha'] -= 1.0/len(emoji_drops)
emoji_drops['alpha'] = np.clip(emoji_drops['alpha'], 0, 1)
emoji_drops['size'] += emoji_drops['growth']
emoji_drops['position'][current_index] = np.random.uniform(0, 1, 2)
emoji_drops['size'][current_index] = np.random.rand(1)*20
emoji_drops['alpha'][current_index] = 1
emoji_drops['growth'][current_index] = np.random.uniform(10, 20)
ax.cla()
for x,y,s,a in zip(emoji_drops['position'][:, 0], emoji_drops['position'][:, 1],emoji_drops['size'],emoji_drops['alpha']):
scat = ax.annotate(marker1, (x,y),fontsize=s, ha='center',va='center',
alpha=a,xytext=(0,0), textcoords='offset pixels')
ani = FuncAnimation(fig, update, interval=50)
ani.save('emoji_expand3.mp4', writer="ffmpeg",dpi=100)
HTML(ani.to_html5_video())
コメント