MoviePyで作るデータビジュアライゼーション - 時系列データのアニメーション表現

Pythonで時系列データをアニメーション化する記事を書きました。pandasでデータを整形し、matplotlibでグラフを描画、MoviePyで動画化する方法をまとめています。データの変化を視覚的に伝えたい方に参考になれば。

![マインドマップ (20).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/c84d658e-e3c7-4c23-9e81-07676b78cab3.png)

## はじめに

Pythonのデータ分析ライブラリ `pandas` や `matplotlib` に加え、動画編集を行うための `MoviePy` を活用して、時系列データのアニメーションを作成する方法を紹介します。

### この記事の概要

![article-summary-diagram (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/e50961e5-7cb9-4964-9ad2-5bd478924f14.png)

- pandas でデータを読み込み・加工
- matplotlib でグラフを生成
- MoviePy でグラフを動画としてアニメーション化
- コード例と実行例

### 必要なライブラリ

以下のライブラリを事前にインストールしてください。

```bash
pip install pandas matplotlib moviepy
```

---

## 1. サンプルデータの作成

まずは時系列データを `pandas` の `DataFrame` で用意します。

```python
import pandas as pd
import numpy as np

np.random.seed(42)
dates = pd.date_range("2021-01-01", periods=10, freq="D")
values = np.random.randint(50, 100, size=10)

df = pd.DataFrame({"date": dates, "value": values})
print(df)
```

---

## 2. matplotlib でフレームを描画する関数の作成

`make_frame(t)` を作成し、`MoviePy` に与えるフレーム（画像）を生成します。

```python
import matplotlib.pyplot as plt
import numpy as np
from io import BytesIO

# Matplotlib の Figure を NumPy 配列に変換する関数
def fig_to_npimage(fig):
    fig.canvas.draw()
    w, h = fig.canvas.get_width_height()
    buf = fig.canvas.buffer_rgba()
    rgba_arr = np.frombuffer(buf, dtype=np.uint8).reshape(h, w, 4)
    return rgba_arr[..., :3]  # RGBA → RGB

# フレーム生成関数
def make_frame(t):
    day = int(t)
    plot_df = df.iloc[:day+1]

    fig, ax = plt.subplots(figsize=(6, 4))
    ax.bar(plot_df["date"].dt.strftime("%m/%d"), plot_df["value"], color="skyblue")
    ax.set_xlabel("Date")
    ax.set_ylabel("Value")
    ax.set_ylim(0, 100)
    ax.set_title(f"Day {day+1} (up to {plot_df.iloc[-1]['date'].date()})")

    frame = fig_to_npimage(fig)
    plt.close(fig)
    return frame
```

### 画像の解像度が荒くなってしまう場合の対策
#### DPIを上げる
fig, ax = plt.subplots(figsize=(6, 4), dpi=200) のように dpi を高めに設定すると、出力画像の解像度が向上する。

#### Figureサイズを大きくする
figsize=(12, 8) など大きめにすると、解像度が上がることがある。
ただし、大きくしすぎると MoviePy の処理が重くなる可能性があるので注意。

#### 適切なフォントサイズを設定する
ax.set_title(), ax.set_xlabel(), ax.set_ylabel() などのテキストがぼやける場合、
fontsize=12 などを指定すると可読性が向上する。

#### アンチエイリアスを有効にする
plt.rcParams['text.antialiased'] = True を設定すると、滑らかな描画になることがある。

---

## 3. MoviePy で動画を作成

上記の `make_frame` を `VideoClip` に渡し、動画を生成します。

```python
from moviepy.editor import VideoClip

# 動画の長さを10秒に設定（1日1秒）
duration = 10
clip = VideoClip(make_frame, duration=duration)

# 動画ファイルに出力
clip.write_videofile("timeseries_animation.mp4", fps=1)
```

---

## 4. 出力動画のイメージ

上記コードを実行すると `timeseries_animation.mp4` が生成され、1秒ごとにデータが更新されるアニメーションが得られます。


<iframe width="560" height="315" src="https://www.youtube.com/embed/GvARkpKEYg0?si=bMBUYGAo_r_wSp6Z" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

## 5. 応用例

- **折れ線グラフ**: `ax.plot()` を利用して、時系列データの推移を可視化
- **地理データの可視化**: ヒートマップや地図データと組み合わせる
- **アノテーションの追加**: 各時点の数値を表示する

## まとめ

![data-viz-summary-fixed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/0852d65d-0323-4cf9-bae4-53f5c8c1c0b9.png)

- `pandas` でデータを整形し、`matplotlib` でグラフを描画
- `MoviePy` を用いてアニメーション化
- `fig.canvas.buffer_rgba()` を使用して `NumPy` 配列に変換

この手法を活用することで、時系列データの変化を動的に可視化し、より直感的にデータを分析・説明できます。ぜひ試してみてください！