あかり描像のブログ

思ったことや学習記録を適当に書いていきます。お気軽にコメントください

【ROOT】あぁ^~グラフがぴょんぴょんするんじゃぁ^~

ROOT でお遊びしてみました。
自分用メモです。

ROOT とは

CERN が開発している C++ ライブラリ群で、高エネルギー物理業界では標準的に用いられています。
その機能は実に膨大で、その上だれでも無料でインストールすることができます *1
ただ、私自身 ROOT に全然明るくないので、ROOT を知らないよという方は

などを参照してください。ごめんなさい。

この記事では私が手探り状態で書いたコードとその出力を置いておきます。
後に私の勉強が進み、かつその気になれば ROOT 関連の更なる記事を書いていきたいとは思いますが、CERN の公式マニュアルを読めば (多分) 大抵何とかなるのでまぁまずそんな未来はないでしょう。

書いたもの

 N = 20, 10, 5 に対して  y = \dfrac{\sin N \pi x}{ \sin \pi x } のグラフを重ねて描くだけのコードです。

なんでこんな関数のグラフをこんな強力な ROOT を用いてまでして描こうとしたのかには深ぁい訳があるんです。
( X 線回折のラウエによる議論の中でこんな感じの関数が出てくるのですが、それについてはいつか気が向いたときに話そうと思います。 )

以下にコードを示しますが、これは ROOT がないとコンパイルできないので念のためそこだけ注意願います。

using namespace TMath;	// TMath::Pi(), TMath::Abs()

void graph()
{
	gROOT -> Reset();
	TCanvas *c1 = new TCanvas("name", "title", 0, 0, 900, 700);
	TLegend *leg = new TLegend(0.78, 0.65, 0.89, 0.85);

	Int_t n = 5000;			// required n >= 2 
	Double_t N[3] = {20.0, 10.0, 5.0};
	Double_t x[3][n], y[3][n];
	Double_t a = -3, b = 3;		// plot n points from a to b

	c1 -> SetGrid();	// grid of x, y axes
	
	for(Int_t i = 0; i < 3; i++) {
		for(Int_t j = 0; j < n; j++) {
			x[i][j] = a + (b - a) * j / (n - 1);
			y[i][j] = Abs( sin(N[i] * Pi() * x[i][j]) / sin(Pi() * x[i][j]) );
		}

		TGraph *g = new TGraph(n, x[i], y[i]);

		g -> SetTitle("y = |sin(N pi x)/sin(pi x)|; x; y");

		g -> GetXaxis() -> SetLimits(a, b);	// min x, max x
		g -> SetMaximum(22);	// max y
		g -> SetMinimum(0);	// min y
		g -> SetLineWidth(2);

		switch (i) {
			case 0:
				g -> SetLineColor(6);	// purple
				g -> Draw("AC");
				break;
			case 1:
				g -> SetLineColor(4);	// blue
				g -> Draw("C");
				break;	
			case 2:
				g -> SetLineColor(2);	// red
				g -> Draw("C");
		}

		leg -> AddEntry(g, Form( "  N = %2.0f", N[i] ));
		leg -> SetBorderSize(1);

	}
	
	leg -> Draw();
	// c1 -> Print("graph.pdf");
}
f:id:bakkyalo:20201015194517p:plain
得られたグラフ

あぁ^~グラフがぴょんぴょんするんじゃぁ^~


備忘録

以下 クッソ汚ねぇ コードの クッソ汚ねぇ 説明です。

  • using namespace TMath;
  • 円周率 Pi() や絶対値 Abs()名前空間 TMath 上にあるっぽい。

  • gROOT -> Reset();
  • よくわかりません。ごめんなさい。

  • TCanvas *c1 = new TCanvas("name", "title", 0, 0, 900, 700);
  • キャンバスを用意するにはこう書くらしいです。1, 2 つめの引数は正直分かりませんが、そこから先は左下と右上の座標を  (0, 0), (900, 700) にしろと言っています。

  • TLegend *leg = new TLegend(0.78, 0.65, 0.89, 0.85);
  • TLegend クラスでグラフの凡例を用意します。引数が意味不明ですが後で説明します *2

  • Int_t n = 5000;
  • プロットする点の個数。今回は  5000 個にしました。

  • Double_t N[3] = {20.0, 10.0, 5.0};
  • パラメーター  N = 20, 10, 5 の配列。 N がでかいほどグラフがぐちゃぐちゃになって見づらいので先に描いておきたい。だから降順。

  • Double_t x[3][n], y[3][n];
  • プロットする点の  x, y 座標。本当は x を 2 次元にする意味はないんだけど、面倒なので y に合わせた。これはよくない。

  • Double_t a = -3, b = 3;
  • グラフの定義域。今回は  a から  b までの  n 点をプロットする戦略です。

  • c1 -> SetGrid();
  • これでグラフにグリッドを敷ける。

  • x[i][j] = a + (b - a) * j / (n - 1);
  • ここだけちょっと算数。閉区間  [ a, b]  n 等分するとき、両端と分点の  x 座標はどうあらわされるか。 x_j = a +  \dfrac{b - a}{n - 1} j \quad (j = 0, 1, 2, \dots, n - 1 )  です。PythonMATLAB みたいに「ここからここまで、~点の配列」を取れる仕様があればこんなこと考えなくてもいいんだけどね。まぁ ROOT にもあるのかもしれないけど。あと上でも言ったけど  x 座標は  N の値に関係ないから 2次元配列にする意味もない。これはよくない。

  • y[i][j] = Abs( sin(N[i] * Pi() * x[i][j]) / sin(Pi() * x[i][j]) );
  • 直前で得た  x の配列を当初の関数に入れているだけです。ROOT では円周率 Pi() と絶対値 Abs()名前空間 TMath に定義されているみたいです。便利。

  • TGraph *g = new TGraph(n, x[i], y[i]);
  • グラフの作成。TGraph クラスを使います。引数は順に、点の個数  n,  x 座標,  y 座標。

  • ここから数行でグラフのタイトル, 描画領域, 線の太さを設定しています。
  • switch 文について
  • ここで  N の値によって線の色と描画オプションを分岐させています。

    • g -> SetLineColor(~);
    • 線の色です。 ~ の数値で色が変わります。

      f:id:bakkyalo:20201015222107p:plain

      ただ、数値だと訳が分からないから ROOT に列挙型として EColor が次のように定義されているらしい。

      enum EColor { kWhite =0,   kBlack =1,   kGray=920,
                    kRed   =632, kGreen =416, kBlue=600, kYellow=400, kMagenta=616, kCyan=432,
                    kOrange=800, kSpring=820, kTeal=840, kAzure =860, kViolet =880, kPink=900 };
      

      なので、例えば g -> SetLineColor(KRed) と書けば赤色になってくれる。特に新たに #includeする必要もなし。


    • g -> Draw("~");
    • グラフ描画。オプションについて、このページ に書いてあるのをコピペしておくと

      • "AH" :  x, y 軸を表示しない
      • "E" :エラーバーを表示
      • "C" :滑らかな線で結ぶ
      • "L" :折れ線グラフで表示
      • "P" :点をプロットする

      ただ、どこかの記事に、1回目は "AC" にしておいて、2回目以降は "A" を付けない方が良いと書いてあった気がするのでそれに従った。どこのサイトだっけ。

  • leg -> AddEntry(g, Form( " N = %2.0f", N[i] ));
  • これで凡例を追加できる。Form() を使うことで  N の値によって表示を変えることができる。

  • leg -> SetBorderSize(1);
  • 凡例の枠線の太さ。 leg -> SetBorderSize(0); にすると線がなくなる。

  • leg -> Draw();
  • 凡例を描画。

  • c1 -> Print("graph.pdf");
  • pdf として保存したいなら Print() を使う。


感想等

ここまで結構苦労してしまいましたが何とか ROOT でグラフを描けて感無量です。
これからもっと ROOT ちゃんと戯れていきたいです。

*1: ただし ROOT は OS XLinux じゃないと動かないので、WSL が使えない Windows 7 等の OS をお使いの方は残念ながら導入できません。悲しいことに私もそのうちの1人でした。

*2: 結構先の話になるかもしれない。