【matplotlib基本】動的グラフを書いてみる♬~動画出力；Gifアニメーション

簡単に考えていたが、難解でした。
ということで、Gifアニメーションに出力できました。
###やったこと
・animation.ArtistAnimation(fig, ims, interval=100)もanimation.FuncAnimation(fig, plot, interval=100)
・mp4やaviで動画出力
・PILを使ってGifアニメーションとして出力させる
###・animation.ArtistAnimation(fig, ims, interval=100)もanimation.FuncAnimation(fig, plot, interval=100)
はっきり言って使いたくない。

コードは簡単で、以下のとおり
性能を見たいので、４分割のグラフに表示している。
※もちろん、一か所であればそれなりに使える
【参考】
①[matplotlib でアニメーションを作る](https://qiita.com/yubais/items/c95ba9ff1b23dd33fde2)
②[matplotlibで簡単にアニメーションをつくる（mp4, gif)](https://qiita.com/msrks/items/e264872efa062c7d6955)

```py
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation

# プロット領域(Figure, Axes)の初期化
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
ax1.axis([-1.2, 1.2, -1.2, 1.2])
ax2.axis([0, 100, -2, 2]) 

# 棒グラフの作成
s = 1
ims = []

for i in range(10):
        rand = np.random.randn(100)     # 100個の乱数を生成
        im = ax1.plot(rand)             # 乱数をグラフにする
        ims.append(im)                  # グラフを配列 ims に追加
        im = ax2.plot(rand)             # 乱数をグラフにする
        ims.append(im)
        im = ax3.plot(rand)             # 乱数をグラフにする
        ims.append(im)
        im = ax4.plot(rand)             # 乱数をグラフにする
        ims.append(im)

ani = animation.ArtistAnimation(fig, ims, interval=100)
ani.save('anim.gif', writer="imagemagick")
#ani.save('anim.mp4', writer="ffmpeg")
plt.show()
```
そして、コードの最後に記載しているが、imagemagick、ffmpeg、どちらもうまく動かなかった。
一時的なものかも知れないが、imagemagickはリンクにとべずインストールできなかった。⇒なんと本日はダウンロードできた⇒そして無事にanim.gifが保存できました
※ffmpegは動きませんでした。
[ダウンロードページ＠imagemagick](http://www.imagemagick.org/script/download.php)
![anim.gif](https://qiita-image-store.s3.amazonaws.com/0/233744/95b40be6-3d96-a751-80c3-5abe48f085ae.gif)
###・mp4やaviで動画出力
これはこれまでも利用したOpenCVで出力する方法。ただし、Gifアニメーションには対応していない。

```py
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import cv2
from PIL import Image, ImageDraw

def cv_fourcc(c1, c2, c3, c4):
        return (ord(c1) & 255) + ((ord(c2) & 255) << 8) + \
            ((ord(c3) & 255) << 16) + ((ord(c4) & 255) << 24)


OUT_FILE_NAME = "output_video.mp4"
#OUT_FILE_NAME = "output_video.avi"
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
dst = cv2.imread('image.png') #一度、savefigしてから再読み込み
rows,cols,channels = dst.shape
out = cv2.VideoWriter(OUT_FILE_NAME, int(fourcc), int(10), (int(cols), int(rows)))
#out = cv2.VideoWriter(OUT_FILE_NAME, cv_fourcc('X', 'V', 'I', 'D'), 30, (cols, rows), True)  #avi

x = np.arange(0, 10, 0.1)
fig=plt.figure(figsize=(12, 8))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(224)
ax4 = fig.add_subplot(223)
ax1.axis([0, 10,-1.2, 1.2])
ax2.axis([0, 100, 0, 100]) 
ax3.axis([-1.2, 1.2,0, 10]) 
ax4.axis([0, 100, 0, 100]) 

def f(x, y):
    return np.sin(x) + np.cos(y)

x1 = np.linspace(0, 2 * np.pi, 100)
y1 = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
ims = []
images=[]
for a in range(10):
    fig.delaxes(ax1)
    fig.delaxes(ax3)
    ax1 = fig.add_subplot(221)
    ax3 = fig.add_subplot(224)
    y = np.sin(x - a)
    line, = ax1.plot(x, y, "r")
    ims.append([line])
    line, = ax3.plot(y, x, "r")
    ims.append([line])

    x1 += np.pi / 15.
    y1 += np.pi / 20.
    im = ax2.imshow(f(x1, y1), animated=True)
    ims.append([im])
    im = ax4.pcolormesh(f(x1, y1), cmap='hsv')
    ims.append([im])
   
    fig1=plt.pause(0.001)
    #Gifアニメーションのために画像をためます
    plt.savefig("output/image"+str(a)+".png")
    dst = cv2.imread('output/image'+str(a)+'.png')
    out.write(dst) #mp4やaviに出力します
```
[【matplotlib基本】動的グラフを書いてみる♬](https://youtu.be/9Al1vfcMj2o)
<a href="http://www.youtube.com/watch?feature=player_embedded&v=9Al1vfcMj2o" target="_blank"><img src="http://img.youtube.com/vi/9Al1vfcMj2o/0.jpg" 
 </a>
※画像をクリックするとYouTube動画につながります
###・PILを使ってGifアニメーションとして出力させる
やっとたどり着いた感じ。。
【参考】
③[Python, PillowでアニメーションGIFを作成、保存@note.nkmk.me](https://note.nkmk.me/python-pillow-gif/)
④[Python PillowでPNGからGIFを作る](https://qiita.com/hiro9/items/222bea3e77dfed235f0a)

コードは以下のとおり、上記の動画出力の最後に以下を追加するだけで実現できました。

```py
import glob

files = sorted(glob.glob('output/*.png'))
images = list(map(lambda file: Image.open(file), files))
images[0].save('out.gif', save_all=True, append_images=images[1:], duration=100, loop=0)    
```
画像50枚を使って、gifアニメーションしてみると、以下のとおり。なお、100枚もやってみたが、それなりに動いた。しかし、ファイルが大きすぎてアップできなかった。
![out.gif](https://qiita-image-store.s3.amazonaws.com/0/233744/d062a476-9215-ab0e-15d3-7dc6b761c29e.gif)
※どうもがくがくしている？？

なお、環境はPillowのバージョンは以下のとおり、3.4以上で対応している。
【参考】
⑤[Creating a multiframe image object #2401@python-pillow/Pillow](https://github.com/python-pillow/Pillow/issues/2401)

```
This makes sense, as append_images was added in Pillow 3.4. So I recommend that you upgrade.
```
ということで、windows10でも、以下のコマンドで...一応Pillowのバージョンは3.3.1からUpgradeできたようです。

```
>pip install -U Pillow
>python
>>> import PIL
>>> print(PIL.__version__)
5.4.1
```
###まとめ
・PILとimagemagickでGifアニメーションに出力できた
・PILの方が使い勝手は良い
・matplotlibのanimationは単独程度の低負荷な場合は使えるが、普通にアニメーションさせた方が性能は良い

・よくよく見ると、mp4などでの出力（元画像のパラパラ動画）に比較して、Gifアニメーションの動画は途中余分に変な動作をしているが、~~原因は不明である~~。
　⇒おまけに追記した。
・いよいよ、次回はFFT,STFT,そしてWavelet変換のアプリを作ろう
###おまけ
以下、ちゃんと出力できなかったが、ダウンロードして動きそうな気配もあるので、記載しておく

[images2gif/images2gif.py](https://github.com/isaacgerg/images2gif/blob/master/images2gif.py)
使い方は、
[python3で3dのgifを作成](https://qiita.com/gymnstcs/items/43ce39355c1d3e7e1547)
[Animated 3-D Plots in Python](https://geoffboeing.com/2015/04/animated-3d-plots-python/)    
###追記（30/1/2019）
どうもガクガクする理由が正しくソートされていないことが原因だったので、スマートなコードはあきらめて、以下のように明示的に読み込んだ。
⇒スムーズに100枚読込んで表示できた！

```py
from PIL import Image, ImageDraw

images = []
for i in range(40):
    im = Image.open('output/image' + str(i)+ '.jpg') 
    images.append(im)
    
images[0].save('out_original40.gif', save_all=True, append_images=images[1:40], duration=40, loop=0) 
```
100枚、50枚も綺麗に動いたが、40枚しかアップできないのでそれを貼っておく。
![out_original40.gif](https://qiita-image-store.s3.amazonaws.com/0/233744/264acc70-199b-305d-80a2-7efaa36dda6e.gif)
もともとの動画もほとんど同じコードでGifアニメーション作成できたので貼っておく
※こちらは100枚貼れました

```py
from PIL import Image, ImageDraw

images = []
for i in range(100):
    im = Image.open('output_ori/image' + str(i)+ '.png') 
    images.append(im)
   
images[0].save('out_original_ori100.gif', save_all=True, append_images=images[1:100], duration=40, loop=0)    
```

![out_original_ori100.gif](https://qiita-image-store.s3.amazonaws.com/0/233744/22250eb1-66a0-8008-b6cd-5dc02f14c5bf.gif)
これで、ほんとにすっきり！