概要
通常グラフを作成するときはEXCEL、pythonのmatplotlibやseabornなど、あるいはgnuplot使うことが多くC++でのグラフ作成はあまり見られません。そこで、CERN ROOTでのグラフ作成を紹介したいと思います。
CERN ROOTはC++のインタプリタでも、C++のコンパイラを用いてバイナリーでも動かすことができるので両方を紹介します。さらにJupyter Notebookも紹介します。
通常、グラフはjpeg,png,gifなどの画像ファイルを作成することが多いと思いますが、CERN ROOTは専用GUI上にグラフを表示し、グラフに対してインタラクティブにいくつかの操作をすることができます。当然、画像ファイルとしても保存することが可能です。
実行環境
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, ...)
void sample01() {
printf("sample01\n");
}
sample01.C
を実行する
root [1] .x sample01.C
sample01
root [2]
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]
2番目の引数に文字列を直接指定するので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]
当然ですが、ファイル名と同じ関数が存在しなくても大丈夫です。関数が1つも含まれていなくてもOKです。
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のメニューから画像ファイルの書き出しも可能です。
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]
ソースの解説
注意点
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
で作成しました。
#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++でコンパイルして実行する
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を設定する必要があるためです。
source thisroot.sh
thisroot.???
はWindows用も含めCERN ROOTのbinディレクトリに含まれています。
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
の実行
python3 sincos.py
GUIはREPLのときと同じです。よってGUIのスクショは省略します。
Jupyter Notebookでグラフを書く
Jupyter Notebookの起動
root --notebook
当然Pythonを選んでもpyROOTを使えばJupyter Notebook上にグラフを表示できます。
終わりに
グラフのクラスはTGraph
以外にもたくさんありすが、日本語の情報が少ないのでなかなか大変です。
グラフ作成にPythonやEXCELばかり使っていますが、C/C++を忘れないためにもC++でグラフを作るのも良いと思います。