CERN ROOT (C++) グラフ作成 (３)  for とsleepを使ってアニメーション (sinの進行波, sin cos描画)

# 概要
通常グラフのアニメーションはアニメーションgifが一般的であるが、長いアニメーションはファイルサイズの大きくなり、gifファイルを作成するのも少し時間を要する。通常のアプリケーションのようにGUI上で簡単にアニメーションができたら良いなと思っていた。
CERN ROOTでは描画の間にSleepを入れるだけで簡単にアニメーションになる。CERN ROOTを本格的に覚えようと思った動機でもある。

# 実行環境

```zsh
sw_vers
ProductName:		macOS
ProductVersion:		14.6.1
BuildVersion:		23G93

root --version
ROOT Version: 6.32.06
Built for macosxarm64 on Sep 21 2024, 18:21:53
From tags/6-32-06@6-32-06
```

# sinの進行波のアニメーション
sinの進行波は次の式で表される
$$
A\sin(kx-\omega t)
$$
$k$:波数　$\omega$: 角振動数
```c++:sin_wave.C
void sin_wave() { 
    constexpr double timer = 100;
    constexpr double y_max = 1.5;
    auto canvas = new TCanvas("canvas");
    canvas->SetGrid();
    auto gr = new TF1("wave", "TMath::Sin([0]*x - [1]*[2])", 0,10);
    double t = 0;
    double k = 2;
    double w = 1;
    gr->SetParameters(k, w, t);
    gr->SetTitle("sin (kx - #omega t)");
    gr->SetMaximum(y_max);   //y軸の最大値
    gr->SetMinimum(-y_max);  //y軸の最小値  
    gr->Draw();
    canvas->ModifiedUpdate();
    for(int i = 0; i < 100 && !gSystem->ProcessEvents(); i++) {
        gSystem->Sleep(timer);
        t += 0.2;
        gr->SetParameter(2,t);
        canvas->ModifiedUpdate();
    }
}

```
`TF1`の第２引数が進行波の計算式で、[0]が波数、[1]が角振動数、[2]が時間で`gr->SetParameters(k,w,t)`で具体的な値をセットしています。 
forループ内の`gr->SetParameter(2,t)`は時間だけが変化するので計算式の[2]だけを変更します。
`gSystem->Sleep`はミリ秒です。`gSystem->ProcessEvents`は無くても問題なく動作します。

実行するが、これはGUI上のアニメーションなのでアニメーションをここで表示することはできない。なので、終了時の画面のスクショを添付する。

```c++
root [0] .x sin_wave.C
root [1]
```
途中で止めたいときはROOT上で`CTRL+C`を打鍵します。

![2024-11-02 15.33.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258007/126a4965-7846-5be1-dfee-5073702c1e4b.png)

#### PyROOTバージョン

```sin_wave.py
import ROOT as RT

timer = 100
y_max = 1.5
canvas = RT.TCanvas("canvas")
canvas.SetGrid()

gr = RT.TF1("wave", "TMath::Sin([0]*x - [1]*[2])", 0,10)
t = 0.0
k = 3.0
w = 1.0
gr.SetParameters(k, w, t)
gr.SetTitle("sin (#kappa x - #omega t)")
gr.SetMaximum(y_max)
gr.SetMinimum(-y_max)    
gr.Draw()
canvas.ModifiedUpdate()
for i in range(100):
    if RT.gSystem.ProcessEvents():
        break
    RT.gSystem.Sleep(timer)
    t += 0.2
    gr.SetParameter(2,t)
    canvas.ModifiedUpdate()
```
実行する

```zsh
source thisroot.sh

python3 -i sin_wave.py
>>> 
```
`-i`オプションは実行終了後Pythonが終了してしまうと、実行終了時が画面も消えてしまうので、`-i`オプションでPythonを終わらせないようにします。 スクショは同じなので省略します。

# sin,cosの重ねグラフを徐々に描画するアニメーション

[CERN ROOT (C++) グラフ作成 (1) sin,cosのグラフの重ね表示](https://qiita.com/h6591/items/085668110a8a016622a5)で描画したsin,cosの重ねグラフの描画を１マーカ毎に描画するアニメーション。

```c++:sincos_anime.C
void sincos_anime() {
    auto canvas = new TCanvas("canvas");
    auto gr = new TGraph();
    auto gr2 = new TGraph();
    gr->SetMarkerStyle(20);
    gr->SetMarkerColor(2);
    gr->SetMinimum(-1.1);  //y軸の最小値
    gr->SetMaximum(1.1);   //y軸の最大値
    gr->GetXaxis()->SetLimits(0,4); //x軸の範囲
    gr->AddPoint(0, TMath::Sin(0)); 
    gr->Draw("apc");

    gr2->SetMarkerColor(4);
    gr2->SetMarkerStyle(40);
    gr2->AddPoint(0, TMath::Cos(0));
    gr2->Draw("pc");

    canvas->ModifiedUpdate();
    for(int i = 1; i < 100 && !gSystem->ProcessEvents(); i++) {
        gSystem->Sleep(100);
        float x = 0.04 * i;
        float ys = TMath::Sin(x * 4);
        float yc = TMath::Cos(x * 4);
        gr->AddPoint(x, ys); 
        gr2->AddPoint(x, yc);
        gr->SetMinimum(-1.1);
        gr->SetMaximum(1.1);
        gr->GetXaxis()->SetLimits(0,4);
        canvas->ModifiedUpdate();
    }
}
```
 [CERN ROOT (C++) グラフ作成 (1) sin,cosのグラフの重ね表示](https://qiita.com/h6591/items/085668110a8a016622a5)のときとは異なり、プロットする点を`AddPoint`を使っています。
 
![2024-11-02 18.16.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258007/2ef5a6e5-b75b-a503-e7f7-0bf2c5ad0683.png)

実際に実行すると赤い点などが１個ずつ描画されるアニメーションなっています。

#### PyROOTバージョン
PyROOTでは以下のようなコードになります。スクショは省略します。
```sincos_anime.py
import ROOT as RT

canvas = RT.TCanvas("canvas")
gr = RT.TGraph()
gr2 = RT.TGraph()
gr.SetMarkerStyle(20)
gr.SetMarkerColor(2)
gr.SetMinimum(-1.1)
gr.SetMaximum(1.1)
gr.GetXaxis().SetLimits(0,4)
gr.AddPoint(0, RT.TMath.Sin(0)) 
gr.Draw("apc")

gr2.SetMarkerColor(4)
gr2.SetMarkerStyle(40)
gr2.AddPoint(0, RT.TMath.Cos(0))
gr2.Draw("pc")

canvas.ModifiedUpdate()
for i in range(1,100):
    if RT.gSystem.ProcessEvents():
       break
    RT.gSystem.Sleep(100)
    x = 0.04 * i
    ys = RT.TMath.Sin(x * 4)
    yc = RT.TMath.Cos(x * 4)
    gr.AddPoint(x, ys) 
    gr2.AddPoint(x, yc)
    gr.SetMinimum(-1.1)
    gr.SetMaximum(1.1)
    gr.GetXaxis().SetLimits(0,4)
    canvas.ModifiedUpdate()
```

# 関連

- [CERN ROOT (C++) グラフ作成 (2) yをxの計算式として与え、x-yグラフを描画 (class TF1 )](https://qiita.com/h6591/items/a81b37c3c3b019db39c7)
- [CERN ROOT (C++) グラフ作成 (1) sin,cosのグラフの重ね表示](https://qiita.com/h6591/items/085668110a8a016622a5)

# 終わりに
ここでは実際のアニメーションを見せられないのが残念ですが、興味にある方はぜひCERN ROOTで実行してみてください。　次回は簡単な物理シミュレーションのアニメーションを予定しています。