CERN ROOT (C++) グラフ作成 (6) 複数のグラフをタイル状に並べて表示

# 概要
複数のグラフをタイル状に並べて表示する。このとき重要になるのがPadの概念である。1Padに1グラフ表示するのでPadの増やし方やPadの選択の仕方を学ばなければならない。

# Pad (TPad)

Canvasを作ると1個のPadが作られる。というか`TCanvas`は`TPad`を継承しているクラスです。これまで投稿していた記事のグラフはその１個のPadに表示していたのです。
Padは入れ子にできるので、CanvasのPad内にタイル状に複数のPadを作成することできる。その複数Padにそれぞれグラフを表示させる。
- Padの追加
    - `TPad::Divide(Int_t nx = 1, Int_t ny = 1, Float_t xmargin = 0.01, Float_t ymargin = 0.01, Int_t color = 0)`
        - `nx`が列数、`ny`が行数、でny行nx列の行列の配置になる 
    - TopのPadはCanvasなので`TCanvas::Divide`
- Padの選択
    - `TVirtualPad* TPad::cd(Int_t subpadnumber = 0)`
        - `subpadnumber`は0が親Padで子Padは行列の左から右、上から下に１から順番に割り振られる
        - `cd()`で選ばれたPadにグラフを描画することができる。また、選択されたPadは`gPad`というROOTのグローバル変数にも設定される。`gPad`はいつでも現在選択されているPadを示している
- Padへの描画
    - 描画したいPadを選択する
    - 表示したいグラフの`Draw()`を実行する
        - `Draw`を実行したときに選択されているPadに描画されるので、Draw以外の関数はPad選択前に実行してもOK



# ２行２列にグラフ表示

２行２列のPadを作って４個のグラフを描画させる例です。

```c++:tiled_graphs.C
void sincos() {
    gPad->SetGrid();
    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->SetMarkerSize(0.5);
    gr->SetMarkerColor(2);
    gr->Draw("apc");
    auto gr2 = new TGraph(n, x, yc);
    gr2->SetMarkerColor(4);
    gr2->SetMarkerSize(0.5);
    gr2->SetMarkerStyle(40);
    gr2->Draw("pc");
}
void tiled_graphs() {
    auto canvas = new TCanvas("canvas", "Tiled Graphs");
    canvas->Divide(2, 2);
    auto tf1 = new TF1("sin1","sin(2.0 * x)",0,5);
    auto tf2 = new TF1("cos1","cos(2.0 * x)",0,5);
    auto tf3 = new TF1("log","log(x)",0,5);
    canvas->cd(1);
    tf1->Draw();
    canvas->cd(2);
    tf2->Draw();
    canvas->cd(3);
    sincos();
    canvas->cd(4);
    gPad->SetGrid();
    gPad->SetFillColor(kGray);
    tf3->SetLineColor(kCyan);
    tf3->Draw();
}
```

```c++
root [0] .x tiled_graphs.C  
root [1]
```

![2024-11-27 13.11.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258007/74fdf781-efd6-7c8e-4b77-52acfecffc31.png)

# 3個のグラフ表示

トップのPadを２分割する。２分割した一方のPadをさらに２分割して３個の描画用Padを用意する。

```c++:tiled_graphs2.C
void sincos() {
    gPad->SetGrid();
    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->SetMarkerSize(0.5);
    gr->SetMarkerColor(2);
    gr->Draw("apc");
    auto gr2 = new TGraph(n, x, yc);
    gr2->SetMarkerColor(4);
    gr2->SetMarkerSize(0.5);
    gr2->SetMarkerStyle(40);
    gr2->Draw("pc");
}
void tiled_graphs2() {
    auto canvas = new TCanvas("canvas", "Tiled Graphs");
    canvas->Divide(2, 1);
    auto tf1 = new TF1("sin1","sin(2.0 * x)", 0, 5);
    auto tf2 = new TF1("cos1","cos(2.0 * x)", 0, 5);
    auto pad1 = canvas->cd(1);
    pad1->Divide(1, 2, 0.01, 0);
    pad1->cd(1);
    gPad->SetGrid();
    tf1->Draw();
    pad1->cd(2);
    gPad->SetGrid();
    tf2->Draw();
    canvas->cd(2);
    sincos();
}
```

`tf1`と`tf2`のx軸の範囲は同じなのでy方向のマージンを0にしました。

```c++
root [0] .x tiled_graphs2.C  
root [1]
```

![2024-11-27 18.02.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258007/4ea08846-1cb4-936b-59a9-2961be63d3c4.png)


# 終わりに

Padをcdで選択して描画するという方法は初めてなので違和感が有りましたが慣れの問題かなと思います。私自身はやり方についてはあまりこだわりがないので、極端に面倒でなければ道具に合わせて受け入れます。