manimをgoogle colabで手軽に遊んでみよう。

## 学べること
・google colabでmanimを使えるようになる。
→すでにgoogle colabでデモンストレーションできるサンプルがあるが、現在（2024/3/18時点）ではgoogle colabでただ単にmanimをインストールするだけだと使えない。

## 背景
・数式や抽象的なイメージをアニメーションで表現することで、理解を促進するための表現方法を増やしたい。

## 用意するもの
Google Colab: ブラウザ上でのPython実行環境。gmailアドレスがあれば無料で使える。
manim: 数式や図をアニメーションできるフレームワーク。
詳しくは下記参照してほしい。
https://blog.shinonome.io/manim/

## やってみよう。
まず、manimを使えるようにcolabの環境を構築する。
```
!apt-get update
!apt-get install build-essential
!apt-get install libpango1.0-dev libcairo2-dev
!pip install --upgrade pip
!pip install setuptools wheel
```

次にmanimをインストールする。
```
# manimをインストール。
!pip install manim
```

:::note warn
ここで、セッションを再起動するというポップアップが出るので再起動するを押下。再度環境構築のコードからスタートするとmanimがインストールできる。
:::

manimはデフォルトだと字幕を日本語にできないので以下のフォントをインストール。
```
!apt-get install fonts-noto-cjk
```

主成分分析をアニメーションする。
内容としては下記。
（初めて作ったのでほとんどわけわからない状態ですがご勘弁を・・・・）
データ点の作成と表示: 2次元の座標点を用意し、Manimでシーンに描画。
主成分の計算と可視化: データを中心化し、共分散行列から固有値と固有ベクトルを取得します。最大固有値に対応する固有ベクトルを可視化。
分散の可視化: 第1主成分に沿った分散を表現する図形を描画。
データ点の主成分への射影: データ点を第1主成分に射影し、射影されたデータを表示。

```
from manim import *
import numpy as np

class PCAVisualizer(Scene):
    def construct(self):
        # データ点の説明
        caption_1 = Text("データ点の作成と表示", font="Noto Sans CJK JP",font_size=24).to_edge(UP)
        self.play(Write(caption_1))
        self.wait(2)

        # 元のデータ点を作成 (3次元に変更)
        data = np.array([
            [2, 1, 0], [1, 3, 0], [3, 4, 0], [4, 3, 0], [3, 2, 0], [2, 4, 0]
        ], dtype=float)

        # データ点をグラフ化
        dots = VGroup(*[
            Circle(radius=0.07, fill_color=YELLOW, fill_opacity=1).move_to([x, y, 0])
            for x, y, _ in data
        ])
        self.play(DrawBorderThenFill(dots))
        self.wait()
        self.play(FadeOut(caption_1))

        # 主成分の計算と可視化
        caption_2 = Text("主成分の計算と表示", font="Noto Sans CJK JP",font_size=24).to_edge(UP)
        self.play(Write(caption_2))
        self.wait(2)

        # 主成分を計算
        mean = np.mean(data, axis=0)
        centered_data = data - mean
        cov_matrix = np.cov(centered_data.T)
        eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)

        # 主成分を可視化
        pc1 = eigenvectors[:, np.argmax(eigenvalues)][:2]
        pc1_line = Line(
            np.append(pc1 * 3 + mean[:2], 0), # 3次元座標に変更
            np.append(-pc1 * 3 + mean[:2], 0), # 3次元座標に変更
            color=GREEN
        )
        self.play(Create(pc1_line))
        self.wait()
        self.play(FadeOut(caption_2))

        # 分散の可視化
        caption_3 = Text("分散の可視化", font="Noto Sans CJK JP",font_size=24).to_edge(UP)
        self.play(Write(caption_3))
        self.wait(2)

        # 分散を可視化
        variance_box = Rectangle(
            height=1, width=eigenvalues.max() * 2
        ).move_to([pc1[0] * eigenvalues.max() + mean[0], pc1[1] * eigenvalues.max() + mean[1], 0])
        self.play(FadeIn(variance_box))
        self.wait()
        self.play(FadeOut(caption_3))

        # 射影の可視化
        caption_4 = Text("データ点の主成分への射影", font="Noto Sans CJK JP",font_size=24).to_edge(UP)
        self.play(Write(caption_4))
        self.wait(2)

        # 二次元からスカラーへの射影を示す
        projected_data = np.dot(centered_data[:, :2], pc1)
        projected_dots = VGroup(*[
            Dot(
                np.array([projected, mean[2], 0]),
                radius=0.05,
                color=BLUE
            )
            for projected in projected_data
        ])
        self.play(ReplacementTransform(dots, projected_dots))
        self.wait()
        self.play(FadeOut(caption_4))

# Sceneをレンダリング
scene = PCAVisualizer()
scene.render(preview=True)

```
画像の通り、左のフォルダ画面のmedia配下に動画が出現する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535433/63f4c19f-410f-296c-c3d8-4c89ec132138.png)

![PCAVisualizer (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535433/17dda550-ebdf-9150-9174-1dafd14b95a8.gif)

## 作った感想
環境構築で意外と苦労しましたが、これでmanimを手軽に遊べるようになりました。
上記のやり方を参考に色々字幕付きで遊んでみるとうまい動画が作れるなと思いました。
youtubeとかでこんなのより遥かにうまい主成分分析のmanimがあったりするのでご覧ください。
そして私にも教えて下さい（切実）