CERN ROOT (C++)   グラフ作成 (1)      sin,cosのグラフの重ね表示

# 概要
通常グラフを作成するときはEXCEL、pythonの**matplotlib**や**seaborn**など、あるいは**gnuplot**使うことが多くC++でのグラフ作成はあまり見られません。そこで、**CERN ROOT**でのグラフ作成を紹介したいと思います。
CERN ROOTはC++のインタプリタでも、C++のコンパイラを用いてバイナリーでも動かすことができるので両方を紹介します。さらにJupyter Notebookも紹介します。
通常、グラフはjpeg,png,gifなどの画像ファイルを作成することが多いと思いますが、CERN ROOTは専用GUI上にグラフを表示し、グラフに対してインタラクティブにいくつかの操作をすることができます。当然、画像ファイルとしても保存することが可能です。
# 実行環境
```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

g++ --version
Apple clang version 15.0.0 (clang-1500.3.9.4)
Target: arm64-apple-darwin23.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
```

# REPLでソースファイルを実行するためのコマンドとプログラムの作り方

ソースファイルの拡張子に特に決まりはありませんが、ROOTで使われているのは`.C`です。個人的にはインタプリタ用のソースを`.C`でコンパイルしてバイナリを作るためのソースを`.cc`としています。

#### ソースファイルを読み込み、ファイル名を同じ関数名を実行するコマンド

```
root [0] .x ファイル名
root [1] .x ファイル名(引数1, ...)
```

```sample01.C
void sample01() {
    printf("sample01\n");
}
```
`sample01.C`を実行する
```
root [1] .x sample01.C
sample01
root [2]
```
```sample02.C
void sample02_sub() {
    printf("sample02_sub\n");
}
void sample02(int n, const char * const c) {
    sample02_sub();
    printf("n=%d c=%s\n", n,  c);
}

```
`sample02.C`を実行する
```
root [0] .x sample02.C(123,"abcd")
sample02_sub
n=123 c=abcd
root [1] char c[]="xyz";
root [2] sample02(456,c);
sample02_sub
n=456 c=xyz
root [3]
```
２番目の引数に文字列を直接指定するので`const char* const`としないと警告がでる。関数`sample02`は**REPL**上で定義済みになるので、何度でも関数`sample02`を呼び出すことができる。

#### ソースの読み込みをするコマンド

```
root [0] .L ファイル名
```
ソースを読み込むが関数は実行されない。しかし関数外、つまりグローバルに記述されているコードは実行される。

```
root [0] .L sample02.C
root [1] sample02(789,"uiop");
sample02_sub
n=789 c=uiop
root [2]
```
当然ですが、ファイル名と同じ関数が存在しなくても大丈夫です。関数が１つも含まれていなくてもOKです。
```sample03.C
int sum = 0;
for (int i = 1; i <= 1000; i++)
    sum += i;
printf("sum=%d\n", sum);
```
sample03.Cの読み込み
```
root [0] .L sample03.C
sum=500500
root [1] 
```

# REPLでプログラムソースを実行させてsin,cosのグラフの重ね表示
sin関数とcos関数のグラフを重ねて表示させる。ここでは画像ファイルの書き出しではなくGUI上にグラフを表示させます。
画像ファイルの書き出しはもちろんプログラムで可能ですし、GUIのメニューから画像ファイルの書き出しも可能です。

```sincos.C
void sincos() {
    constexpr int n = 100;
    float x[n], ys[n], yc[n];
    for(int i=0; i < n; i++){
        x[i] = 0.04 * i;
        ys[i] = TMath::Sin(x[i]*4);
        yc[i] = TMath::Cos(x[i]*4);
    }
    auto gr = new TGraph(n, x, ys);
    gr->SetMarkerStyle(20);
    gr->SetMarkerColor(2);
    gr->Draw("apc");
    auto gr2 = new TGraph(n, x, yc);
    gr2->SetMarkerColor(4);
    gr2->SetMarkerStyle(40);
    gr2->Draw("pc");
}
```
`sincos.C`を実行する
```
root [0] .x sincos.C
Info in <TCanvas::MakeDefCanvas>:  created default TCanvas with name c1
root [1]
```
![2024-10-26 16.16.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258007/644e0347-667f-f421-bddc-ead56bebf395.png)

#### ソースの解説
#### 注意点
:::note alert
**gr**や**gr2**を**delete**しない。deleteすると描画したグラフも消去される。
:::

グラフの描画には`TCanvas`のオブジェクトが必要であるが、自動的に生成されるのでプログラムで生成する必要はない
##### Drawオプション
|Option	|Description|
|:-----:|:-----------|
|"A"|Produce a new plot with Axis around the graph|
|"I"|	Combine with option 'A' it draws invisible axis|
|"L"|	A simple polyline is drawn|
|"F"|	A fill area is drawn ('CF' draw a smoothed fill area)|
|"C"|	A smooth Curve is drawn|
|"*"|	A Star is plotted at each point|
|"P"|	The current marker is plotted at each point|
|"B"|	A Bar chart is drawn|
|"1"|	When a graph is drawn as a bar chart, this option makes the bars start from the bottom of the pad. By default they start at 0.|
|"X+"|	The X-axis is drawn on the top side of the plot.|
|"Y+"|	The Y-axis is drawn on the right side of the plot.|
|"PFC"|	Palette Fill Color: graph's fill color is taken in the current palette.|
|"PLC"|	Palette Line Color: graph's line color is taken in the current palette.|
|"PMC"|	Palette Marker Color: graph's marker color is taken in the current palette.|
|"RX"|	Reverse the X axis.|
|"RY"|	Reverse the Y axis.|

#### 画像ファイルとしての書き出し
メニューの[File]->[Save] or [Save As]を選べばps,eps,pdf,tex,gif,png,Cプログラム,rootファイルの書き出しが可能です。さらに、メニューの[View]->[Editor]でグラフのマーカーの種類や色を変えることが可能です。

# g++でコンパイルしてバイナリを作成して実行
コンパイルするためインタプリタとして実行するのとは異なり、ヘッダーファイルのincludeなど完全なC++プログラムを書かなければならない。
上記の`sincos.C`の完全なc++ソースを以下の示します。拡張子は`.cc`で作成しました。
```sincos.cc
#include <TApplication.h>
#include <TCanvas.h>
#include <TGraph.h>
#include <TMath.h>
#include <TRootCanvas.h>

int main(int argc, char* argv[]) {
    TApplication app("app", &argc, argv);
    TCanvas c1("c1");
    constexpr int n = 100;
    float x[n], ys[n], yc[n];
    for(int i=0; i < n; i++){
        x[i] = 0.04 * i;
        ys[i] = TMath::Sin(x[i]*4);
        yc[i] = TMath::Cos(x[i]*4);
    }
    TGraph gr(n, x, ys);
    gr.SetMarkerStyle(20);
    gr.SetMarkerColor(2);
    gr.Draw("apc");
    TGraph gr2(n, x, yc);
    gr2.SetMarkerColor(4);
    gr2.SetMarkerStyle(40);
    gr2.Draw("pc");
    c1.Update();

    TRootCanvas *rc = (TRootCanvas *)c1.GetCanvasImp();
    rc->Connect("CloseWindow()", "TApplication", gApplication, "Terminate()");
    
    app.Run();
    return 0;
}
```

`sincos.cc`をg++でコンパイルして実行する
```zsh
g++ sincos.cc -o  sincos `root-config --cflags --libs`

./sincos
```
**root-config**がCERN ROOTのincludeやリンクライブラリーの指定をしてくれます。
GUIはREPLのときと同じです。よってGUIのスクショは省略します。

# PyROOTによるPythonでの同じグラフ表示
CERN ROOTはPythonのライブラリも提供していて追加インストールなしで使えます。
ただし、Pythonを動かく前に以下のスクリプトを実行してください。これはPYTHONPATHにCERN ROOTのbinを設定する必要があるためです。
```zsh
source thisroot.sh
```
`thisroot.???`はWindows用も含めCERN ROOTのbinディレクトリに含まれています。
```sincos.py
import ROOT as RT
from array import array

c1 = RT.TCanvas("c1")
n = 100
x = array('f',[0]*n)
ys = array('f',[0]*n)
yc = array('f',[0]*n)
for i in range(n):
    x[i] = 0.04 * i;
    ys[i] = RT.TMath.Sin(x[i]*4);
    yc[i] = RT.TMath.Cos(x[i]*4);
gr = RT.TGraph(n, x, ys)
gr.SetMarkerStyle(20)
gr.SetMarkerColor(2)
gr.Draw("apc");
gr2 = RT.TGraph(n, x, yc)
gr2.SetMarkerColor(4)
gr2.SetMarkerStyle(40)
gr2.Draw("pc")
c1.Update()

rc = c1.GetCanvasImp()
rc.Connect("CloseWindow()", "TApplication", RT.gApplication, "Terminate()");

RT.gApplication.Run()
```
配列は`array.array`を使う必要があるようです。ちなみに第1引数の'f'は配列のデータがfloatタイプであることを表しています。

`sincos.py`の実行

```zsh
python3 sincos.py
```
GUIはREPLのときと同じです。よってGUIのスクショは省略します。

# Jupyter Notebookでグラフを書く

Jupyter Notebookの起動

```zsh
root --notebook
```

![2024-10-26 22.02.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258007/cc87f47d-c8af-2fcb-7524-188aa150cac3.png)
![2024-10-26 22.00.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258007/331f8e3e-4878-7e49-6475-500c9a78d177.png)

当然Pythonを選んでも**pyROOT**を使えば**Jupyter Notebook**上にグラフを表示できます。

![2024-10-26 22.18.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258007/adaf92b9-d1ce-3baf-79a1-a8fe0eb15cd7.png)

# 終わりに
グラフのクラスは`TGraph`以外にもたくさんありすが、日本語の情報が少ないのでなかなか大変です。
グラフ作成にPythonやEXCELばかり使っていますが、C/C++を忘れないためにもC++でグラフを作るのも良いと思います。