PythonでPillowを使ってGIFファイルを作る


コンター図をパラパラ漫画みたいにしたGIF動画を作ったので備忘録。
環境はPython 3.6.8


## matplotlib.animation

matplotlib.animationで動くグラフは作れるみたい。

GIFファイルとして保存するにはwriterにimagemagickを使うのが普通の様子。

## imagemagick

windowsにインストールする場合、ちょっと面倒な様子。

インストールしようとして参考にさせていただいたページ。
https://higuma.github.io/2016/08/31/imagemagick-1/

## PythonのライブラリPillow

Pillowについて参考にさせていただいたサイト。

インストールとか
https://note.nkmk.me/python-pillow-basic/

GIFの作り方
https://note.nkmk.me/python-pillow-gif/


## 作ってみる

```python:import_lib.py

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import os
from PIL import Image, ImageDraw  
```

こんな感じのデータを用意する。

![スクリーンショット 2019-11-24 21.48.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84834/6b70a796-2f4e-3f6c-183d-b5841e31fe0d.png)

座標はこんな感じを想定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84834/e4d0801e-d020-9000-f86d-7b93289c0809.png)



```python:test_data.py

test_data = pd.DataFrame({'key':range(10),
                          't1': [10] * 10,
                          't2': [i * 10 + 10 for i in range(10)],
                          't3': [i * 10 + 20 for i in range(10)],
                          't4': [5] * 10,
                          't5': [i * 10 + 5 for i in range(10)],
                          't6': [i * 10 + 15 for i in range(10)],
                          't7': [3] * 10,
                          't8': [i * 10 + 2 for i in range(10)],
                          't9': [i * 10 + 10 for i in range(10)]})

t = ['t' + str(int(i)) for i in range(1, 10)]
x = [i * 10 for i in range(1, 4)] * 3
y = [10] * 3 + [20] * 3 + [30] * 3

```

コンター図を作る用のデータ抽出関数を作っておく

```python:create_function.py

def f_contour_data(df, timing):
    # コンター図を描きたいタイミングの行のデータを抽出
    df0 = df[df['key'] == timing].copy()  
    # 抽出したデータを使いやすいようにindexを0にしておく
    df0.reset_index(drop = True, inplace = True)
        
    x = [10, 20, 30] # コンター図のx軸
    y = [10, 20, 30] # コンター図のy軸
    
    # 番号のリストを作る
    # [[t1, t2, t3], [t4, t5, t6], [t7, t8, t9]]
    # これをつくる
    l_T = []
    for i in range(len(y)):
        T = ['t' + str(int(j + i * 3)) for j in range(1, 4)]
        l_T.append(T)
        
    # x軸の2darrayをつくる
    x0 = np.empty((0, len(y))) # 空のndarrayをつくる
    for i in range(len(y)):
        x0 = np.append(x0, np.array([x]), axis = 0) # xをndarrayに換えてx0に追加
    # y軸の2darrayをつくる
    y0 = np.empty((0, len(y)))
    for i in range(len(y)):
        y0 = np.append(y0, np.array([[y[i]] * 3]), axis = 0)
        
    # z軸の2darrayをつくる    
    z0 = np.empty((0, len(y)))
    for i in range(len(y)):
        temp = []
        T = l_T[i]
        for s in T:
            temp.append(df0[s][0])
        z0 = np.append(z0, np.array([temp]), axis = 0)                           
    return x0, y0, z0, l_T # l_Tは確認用 削除してもOK

```

これを使ってコンター図をテキトーに描くとこんな感じになる。

```python:create_contour.py
x0, y0, z0, l_t = f_contour_data(df = test_data, timing = 0)

plt.figure()
p = plt.contourf(x0, y0, z0, cmap = 'jet')
cbar = plt.colorbar(p)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84834/ba424aae-00f5-3edb-e039-83fb7749ee29.png)

あとはこれをループでどんどん作って保存していく。

```python:loop.py

l_img = [] # コンター図の.pngのpathをいれるようのリスト
os.makedirs('Contour_gif/', exist_ok = True) # グラフ保存用のフォルダ―を作る
lv = [i * 10 for i in range(14)]
for i in range(10):
    x0, y0, z0, l_tc = f_contour_data(df = test_data, timing = i)
    plt.figure()
    p = plt.contourf(x0, y0, z0, lv, ![test.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84834/dd6833da-c69d-95de-f016-f0a7e6082a08.gif)
cmap = 'jet')
    cbar = plt.colorbar(p)
    plt.title('key = ' + str(int(i)))
    save_path = 'Contour_gif/key_' + str(int(i)) + '.png'
    plt.savefig(save_path, bbox_inches="tight") # 作ったグラフを保存
    l_img.append(save_path) #　コンター図の順番を確実に維持したいのでココでリストに追加しておく
    
images = [] # 開いたpngを入れておくよう。
# 別にl_imgの範囲は指定しなくてもOK 画像の容量によっては怒られるけど。。。
for s in l_img[0:151]:
        im = Image.open(s)
        images.append(im)
        # images[0]を起点に残りをつなげる　durationで切り替わりの時間(msec) loop = 0 で無限ループ
        images[0].save('test.gif',
                       save_all = True, append_images = images[1: len(images)],
                       duration = 500, loop = 0, optimaize = False)

```

こんな感じのGIFファイルができる。

![test.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84834/1d1124f8-0ad7-8b8b-792b-d5a5e50f22d0.gif)