TH1F *hist = new TH1F("name","title",binの数,下限,上限); hist->Fill(n);//Fillはある数値に対応するbinをインクリメントする hist->Draw();//Draw()で作ったヒストグラムを描くことができる
例えばTH1IはInt_tなので、各binには整数型の値しか記憶できない。例えばweight0.5でFillしても縦軸の値はすべて整数になる。
(横軸、つまりbin幅は常にDouble_tの精度で記録されることに注意)。
hist->Fill(x,w);
hist->FillRandom("func",n);
TH1::Fitと同様にgausやlandauでFillできる。
hist->FillRandom("gaus");
またhistogramの分布にしたがってFillもできる。かつて使ったことがない。
hist->FillRandom(hist2,ntimes);
普通にヒストグラムを作るとbin幅は均等になる。
自由にbin幅を設定する場合は配列を使う。
double xbins[] = {0,4,5,10} TH1F *hist = new TH1F("hist","",3,xbins);
hist->Draw("オプション")
"AH":xy軸を表示しない "E":エラーバーを表示 "C":滑らかな線で結ぶ "L":折れ線グラフで表示 "P":点をプロットする "SAME":前に描いていたヒストグラムに重ねて描く etc...
オプションは大文字と小文字を区別しない
2つ以上のヒストグラムを重ね書きしたい場合は、2つ名以降のヒストグラムに対してsameオプションを使う。
またはTHStack(後述)を使う。
TCanvas *c1 = new TCanvas("c1",""); h1->Draw(); h2->Draw("same")
しかしFillColorをつけていると、軸の目盛りがヒストグラムと被って消えてしまう。
こんなときはRedrawAxisを使うと軸が復活する。
c1->RedrawAxis()
またはTGaxisを新たに作って再描画という手もあるが面倒すぎるし、綺麗にかけないと思う。
これはヒストグラムを重ね書きするのではなく、複数のヒストグラムを足し上げて、一つのヒストグラムを作るためのクラス。
多次元ヒストグラムでも使える。
THStack *hs = new THStack("hs","test stacked histograms"); TH1F *h1 = new TH1F("h1","h1",100,-5,5); h1->SetFillColor(kRed);//あらかじめFillColorをSetしておく TH1F *h2 = new TH1F("h2","h2",100,-5,5); h2->SetFillColor(kBlue); TH1F *h3 = new TH1F("h3","h3",100,-5,5); h3->SetFillColor(kGreen); //h1,h2,h3を適宜Fillする h1->FillRandom("gaus",2000); h2->FillRandom("gaus",2000); h3->FillRandom("gaus",2000); hs->Add(h1); hs->Add(h2); hs->Add(h3); hs->Draw();
オプションでnostackにするとhistを積まずに単に重ね合わせをする。
hs->Draw("nostack");
axisにtitleを付けたい場合は、宣言するときにtitleを;で区切る。
THStack *hs = new THStack("hs", "test; x title; y title");
ヒストグラムの軸はTAxisというクラスになっている。
軸の設定を変えたいときはほぼすべてTAxisにアクセスすればいい。
もしも、x軸にアクセスしたいなら
hist->GetXaxis()
Y軸なら
hist->GetYaxis()
とすればいい。以下の文章は例として、X,Yのどちらかを書いているがテキトウに読み替えてください。
それが嫌ならあらかじめTCanvasにDrawFrameをさせるという方法がある。
軸にタイトルを付ける場合は下のように、コンストラクタで行うのが楽だと思う。
TH1F *hist = new TH1F("name","title;Xtitle;Ytitle;Ztitle",binの数,下限,上限);
(Z軸がないのであれば、"title;Xtitle;Ytitle"とする)。
また下のようにセットすることもできる。
hist->SetTitle("title;Xtitle;Ytitle;Ztitle");
又は
hist->SetXTitle("Xtitle"); hist->SetYTitle("Ytitle"); hist->SetZTitle("Ztitle");
しばしば一つのマクロでヒストグラムは大量に作るので、いちいちSetTitleで余計な行数を増やすのはあまりおすすめしない。コンストラクタで行うのがいいと思う。
が、たぶんTH1とそれに付随するTAxisはタイトルを共有している。
つまり、TH1のタイトルを"title;Xtitle"とすれば、x軸のTAxisのタイトルは"Xtitle"になる。なのでどちらのタイトルを変えても結果は同じ、だと思う。
ROOTではタイトルはTitle、目盛りはLabelと呼んでいる。
hist->SetTitleSiZe(0.07,"x");
hist->SetLabelSiZe(0.04,"x");
まず適当なヒストグラムを作る。今回はbinが4つのヒストグラムを例にする。
TH1F *h = new TH1F("h","",4,0,4); //binの数だけが意味を持つので、下限、上限は適当でいい
次に各binに名前をつける。binの番号は0からではなく1から始まることに注意。
h->GetXaxis()->SetBinLabel(1,"A"); h->GetXaxis()->SetBinLabel(2,"B"); h->GetXaxis()->SetBinLabel(3,"C"); h->GetXaxis()->SetBinLabel(4,"D");
あとは普通にFillすればいい。
h->Fill(1); ...
binにつけた名前でFillすることも出来る。
h->Fill("A",weight); //weightは省略不可。
もしも、binの名前がつけられていない場合、空いているbinのうち一番左側から詰めていくのだと思われる。
hist->GetXaxis()->SetRange(first bin,last bin);//bin番号を引数にする hist->GetXaxis()->SetRangeUser(first,last);//user座標を引数にする
y軸を変えたい場合はGetYaxis()をすればいい。
がしかし、ROOTにおいてx軸の範囲を変えるのはなかなか難しい場合が多い(私が言っているx軸の範囲を変えるというのはbinningを変えずに見た目の調整を行うことを意味している。)
例えば、すでにFillしてある、histogramの軸の範囲を上の方法で変えてDrawすると、おそらく意図したものにはならない。
つまり、histogramは配列でbinの値を記録しているので、histogramの軸の設定を書き換えても、binの順番は変わらないため、結局Fillされているbinの位置が変わってしまう。
逆にFillする前に軸の範囲だけを変えてしまうと、binの数は変わっていないので、これもおかしなことになる。
つまり、正しくは、どちらの場合もSetBins(n,xmin,xmax)でbinning自体を変えるべき。なのだが、この場合、(同じヒストグラムにするためには)元のbin幅と一致するように気をつけてbinの数を変更する必要があるので、面倒である。
なので、
canvas->DrawFrame(xmin,ymin,xmax,ymax); hist->Draw("same"); canvas->RedrawAxis();
とするのが最も簡単。x軸dでもy軸でも使えるし、またTGraphやTF1の場合も利用できるので、知っておいた方がいいテクニックだと思う。
もう一回いうと、この方法が一番簡単。いろいろ調べたので間違いない。
GUIでいつもやっているやつ。
hist->GetXaxis()->ZoomOut(Double_t factor, Double_t offset);
例えば、軸が0から100の場合、ZoomOut(0.5,0)とすると、25から75になる。第二引数はなんかよくわからん。
なぜかは知らないが、log scaleにするのはTPadのメソッドになっている。いや一応なぜかはわかるんだけど、直感的にはやっぱり不可解。
c1->SetLogy(); c1->SetLogy(false);//元に戻す
LogScaleはデフォルトでは10の指数しか表示しか表示されない。細かい目盛りというか、数字を表示するには、
hist->GetYaxis()->SetMoreLogLabels(); hist->GetYaxis()->SetMoreLogLabels(false);//元に戻す
と、なぜかTAxisにアクセスする必要がある。いや理屈はわかるんだけどさ。
桁数の許容最大数を指定する。指定された数値を超えると指数関数表示される。
デフォルト値は5。
((TGaxis*)hist->GetXaxis())->SetMaxDigits(n); ((TGaxis*)hist->GetYaxis())->SetMaxDigits(n);
例えばデフォルトでY軸は5桁まで許されているので、下の絵のようになるが、
((TGaxis*)hist->GetYaxis())->SetMaxDigits(4);
とすると最大4桁までなので下の絵のように指数表示される。
hist->GetYaxis()->SetNoExponent(); hist->GetYaxis()->SetNoExponent(falase);//元に戻す
hist->GetYaxis()->SetNdivisions(n);
Canvasの右上にある統計ボックスはTPaveStatsというクラスでヒストグラムをDrawしたときに自動的に生成される。
hist->SetStats(1); //表示 hist->SetStats(0); //非表示
gStyle->SetOptStat(stat);
引数はint又は文字列。デフォルト値は000001111
intを引数にする場合は9桁の10進数で各桁がksiourmenという順番で対応する。
(例えば101010101ならk=1,s=0,o=0,…という感じ)
文字列を引数にする場合は小文字が1、大文字が2に対応する。
(例えば、Kioならk=2,i=1,o=1他は0になる)
k = 1; kurtosis printed
k = 2; kurtosis and kurtosis error printed
s = 1; skewness printed
s = 2; skewness and skewness error printed
i = 1; integral of bins printed
o = 1; number of overflows printed
u = 1; number of underflows printed
r = 1; rms printed
r = 2; rms and rms error printed
m = 1; mean value printed
m = 2; mean and mean error values printed
e = 1; number of entries printed
n = 1; name of histogram is printed
かといってgStyle->SetOptStat(000000001);のように先頭が0で始まる場合は八進数で解釈されるので、やはりnameだけにはならない。
このため、余分に1をつけて10桁にして、gStyle->SetOptStat(1000000001);とする必要がある。
なんやねん、この仕様は。
gStyle->SetOptFit(stat);
引数は10進数の4桁の整数で各桁がpcevに対応する。デフォルトは0111。
p = 1 | 確率の表示 |
c = 1 | χ二乗/ndf |
e = 1 | エラーの表示(v=1になる) |
v = 1 | パラメータの名前と値の表示(固定パラメータを除く) |
v = 2 | 固定されているパラメータも含めてすべて表示 |
GUIでも統計ボックスのところを右クリックすると変更できる。
//ボーダーサイズ gStyle->SetStatBorderSize(Width_t size = 2) // //ボックスの背景色 gStyle->SetStatColor(Int_t color = 19) //よく知らない gStyle->SetStatFormat(const char* format = "6.4g") gStyle->SetStatStyle(Style_t style = 1001) //Font関係 gStyle->SetStatFont(Style_t font = 62) gStyle->SetStatFontSize(Float_t size = 0) gStyle->SetStatTextColor(Int_t color = 1) //ボックスのサイズ? gStyle->SetStatH(Float_t h = 0.1) //高さ gStyle->SetStatW(Float_t w = 0.19) //幅 //ボックスの位置 gStyle->SetStatX(Float_t x = 0) //ボックスの右上の点x座標 gStyle->SetStatY(Float_t y = 0) //ボックスの右上の点のy座標
重要なことはヒストグラムをPaintするまでは統計ボックスは存在しないということ。
PaintはDrawしたあとに自動的に行われるので、コマンドラインで下のようにすることは可能。
[ ] hist->Draw(); [ ] TPaveStats *stat = hist->FindObject("stats"); //CINTではキャストは省略可能
しかし、スクリプト中ではPaintはスクリプト実行後行われるので、Paintを強制する必要がある。
hist->Draw(); c1->Update(); TPaveStats *stat = (TPaveStats*)hist->FindObject("stats");
このように、統計ボックスはヒストグラムのメンバ変数ではないので、TAxisのように直接呼び出すメソッドはTH1には存在しない。
しかも、なぜかヒストグラムの関数(fitして得られたTF1)と同じTListに加えられる。
やや隠しキャラ的な存在。
例えば、Draw("same")をして2つのヒストグラムを作った場合は2つ目の統計ボックスは表示されない。
Draw("sames")にすると2つ目以降も統計ボックスが表示されるが、この場合一つ目の統計ボックスに重なって見えなくなってしまう。
重なった統計ボックスの位置を変えるには以下の作業を強いられる。
h1->Draw() h2->Draw("sames") c1->Update(); //paintする(画面に表示される) TPaveStats *st = (TPaveStats*)h2->FindObject("stats"); st->SetX1NDC(x1); //x座標の始点、4行あるときの初期位置は0.78? st->SetX2NDC(x2); //x座標の終点、4行あるときの初期位置は0.98? st->SetY1NDC(y1); //y座標の始点、4行あるときの初期位置は0.775? st->SetY2NDC(y2); //y座標の終点、4行あるときの初期位置は0.935? c1->Modified(); //オブジェクトの設定変更を伝える
見て分かるようにきちんとROOTの仕様をマニアックに理解してないと正しく作ることができない。統計ボックスを2つ作ることを想定していないんだろうなあ。
あるいはDraw("sames")する前にgStyleで設定書き換えればもっと単純にできるのか。その方がいいかなあ。
GUIなら統計ボックスの位置をドラッグするだけでいいので、これに関してはGUIで操作のほうが楽だと思う。
void macro(){ TH1F *h1 = new TH1F("h1","",100,-3,3); h1->SetLineColor(kRed); h1->FillRandom("gaus",6000); TH1F *h2 = new TH1F("h2","",100,-3,3); h2->SetLineColor(kBlue); h2->FillRandom("gaus",3000); h1->Draw(); h2->Draw("sames"); c1->Update(); TPaveStats *st1 = (TPaveStats*)h1->FindObject("stats"); st1->SetTextColor(kRed); TPaveStats *st2 = (TPaveStats*)h2->FindObject("stats"); st2->SetTextColor(kBlue); st2->SetX1NDC(0.18); st2->SetX2NDC(0.38); c1->Modified(); }
猿でも番外編のここに書かれている方法は使えなかったのだが、古いrootならできるのだろうか。
hist->Add(hist1,x);//各binの値=現在の値+x*hist1の値 hist->Add(hist1,hist2,x,y);//各binの値=x*hist1の値+y*hist2の値
hist->Divide(hist1,x);//各binの値=現在の値/(x*hist1の値) hist->Divide(hist1,hist2,x,y);//各binの値=(x*hist1の値)/(y*hist2の値)
hist->Multiply(hist1,x);//各binの値=現在の値*x*hist1の値 hist->Multiply(hist1,hist2,x,y);//各binの値=x*hist1の値*y*hist2の値
hist->Scale(x);//各binの値=x*現在の値
上で紹介しているhistの演算はbinの最大値や最小値が同じでないと足せないが、Mergeなら可能。細かい仕様はしらない。
TList *l = new TList; l->Add(h1); l->Add(h2); l->Add(h3);
まず、上のようにTListを作って、mergeしたいヒストグラムをいれておく。
TH1F *h = new TH1F("h","title",100,-100,100); h->Merge(l); h->Draw();
上のようにMergeの引数としてTListをいれる。
hist->Integral(); //全Entry数を返す hist->Integral(binx1,binx2); //ビン番号をいれる hist->Integral(binx1,binx2,"width"); //ビンの中身×ビン幅で重み付けして積分する
ヒストグラムやグラフに凡例をいれるクラス。なぜTH1の下位項目なのかというツッコミをいれないでください。
TH1F *h = /**/; TGraph *g = /**/; TF1 *f = /**/; //TLegend(x1,y1,x2,y2,"title")、位置はNDCで指定する(0−1の間の値) //最後の引数の"title"はlegendに表示にされるタイトル、邪魔な場合はいれなくてもいい TLegend *leg = new TLegend(0.1,0.7,0.48,0.9); //第一引数はポインタ、第二引数は項目名、第三引数で表示したいattributeを指定 leg->AddEntry(h,"histogram","f"); leg->AddEntry(gr,"graph","lep"); leg->AddEntry(f,"function","l"); leg->Draw()
AddEntryの3つ目の引数は凡例を表示したいクラスに合わせて、下のように変える。
f | TAttFill、主にヒストグラム |
l | TAttLine、グラフや関数などの線 |
p | TAttMarker、グラフのマーカー |
e | error bar、グラフやヒストグラムのエラーバー |
テキストを挿入するには
leg->AddEntry((TObject*)0, "Some text", "");
leg->SetBorderSize(0); //影をなくす leg->SetFillStyle(0); //背景を透明にする
又は
gStyle->SetLegendBorderSize(0); //影をなくす
※Styleの変更はオブジェクトを生成する前に行うこと
TPadに描かれているObjectのLegendを自動的につくる一見便利そうなメソッド。
TCanvas *c1 = new TCanvas("c1","c1"); h1->Draw(); h2->Draw(); c1->BuildLegend();
動作としてはTLegendを生成して、順番にTPadに描かれているObjectをAddEntryする。
Objectのtitleを項目名に、Objectが継承しているTAtt系のクラスをすべて凡例に表示する(例えばTAttLineを継承していれば、オプション"l"を追加という具合)。
がしかし、例えば、TGraphなら凡例にMarkerだけを出したい場合やLineだけを出したい場合もあるので、いまいち痒いところに手が届かない。
単純なメソッドなので、もっと便利なように自分で作ったほうがいい気がする。
TH1のメソッドはビン番号を引数にすることが多いので、このメソッドはよく使う。
h1->FindBin(数値); h1->FindFixBin(数値);
h1->GetBinContent(ビン番号);
h1->SetBinContent(binのnum,代入したいvol);
bin番号がわからければ使えないわけだが、多次元ヒストになってくるとbin番号を調べるのはかなり面倒。
Fill(x,w)で重み付けしてFillしたほうが簡単な気がする。
ヒストグラムのbinをいくつかまとめて、binを区切り直すことができる。
ただ、例えば{0,1,2,3,4}を{0,2,4}と切り直すことはできるが、逆はできない。もはや情報が失われている。
TH1F h_rebin* = hist->Rebin(n); TH1F h_rebin* = hist->Rebin(n,"h_rebin");//第二引数は新しく作るhistoの名前
double x[n] = {}; TH1F h_rebin* = hist->Rebin(n,"h_rebin",xbins);
TH2F *h = new TH2F("name","title; X; Y", nbinsx, xlow, xup, nbinsy, ylow, yup); h->Fill(x,y);
とりあえず使えばわかると思う。
h->Draw("colz");
これが一番よく使う。zはカラーパレットを表示するオプションでcol以外でも使える。
h->Draw("arr");
legoは色なし、lego1はFillColorの色、lego2は値に応じて色を変える。
後ろ側が見えないので、画像にするときはあまり使わない。
h->FillColor(kYellow) h->Draw("lego1");
h->Draw("lego2z");
等高線を表示する。
h->Draw("cont1z");
h->Draw("cont2");
boxの面積又は体積はデータに比例する。
h->Draw("box");
各binに数値をtextで表示。textの大きさはmarkerのsizeに比例。色はmarkerの色。
h->Draw("text");
これは他のオプションと組み合わせても有効。textの右に書かれている数値は角度を表す。
h->Draw("text45 colz");
散布図を描画。パッと見るとbin幅より細かい情報を持つように見えるが、たぶんbinの中でrandomにplotしているだけ。
h->Draw("scat");
MarkerのStyleはTAttMarkerのメソッドでスタイルを変えることができる。
gr->SetMarkerColor(3); gr->SetMarkerSize(2); gr->SetMarkerStyle(3);
h->Draw("surf1z");
h->Draw("surf3z");
二次元ヒストのx軸の各bin毎の、y値の平均とエラーを計算してグラフにするメソッド。rootの動きとしてはTH2からTProfileを生成している。
TProfile *pf = h2->ProfileX(); pf->Draw();
x値の平均とエラーが知りたい場合はProfileYを使う。
あるビンからビンまでの範囲での射影を作るメソッド。
TH1D *pj = h2->ProjectionX("object name",first,last); pj->Draw();
X軸にスライスして、Y軸に射影するときはProjectionYを使う。
ポイントとしてはProjectionはたとえTH2Fだったとしても、生成されのはTH1Dであること。
一番ノーマルな使い方。プロットしたいx,y座標をいれた配列をそれぞれ用意して、そのアドレスをTGraphに渡せばいい。
const Int_t n = 20; Double_t x[n] = {0}, y[n] = {0}; for (Int_t i=0;i<n;++i) { x[i] = i*0.1; y[i] = 10*sin(x[i]+0.2); } TGraph *gr = new TGraph(n,x,y); gr->Draw("AP");
error barをつけたい場合は、TGraphErrorsを使う
TGraphErrors *gr = new TGraphErrors(n,x,y,xerror,yerror);
SetPointを使うと、TGraphを作った後に各点の位置を変更したり追加することが出来る。
const Int_t n = 20; TGraph *gr = new TGraph(n); //各点が(0,0)で初期化される for (Int_t i=0;i<n;++i) { gr->SetPoint(i , i*0.1 , 10*sin(x[i]+0.2)); //SetPoint(点番号,x座標,y座標) } gr->Draw("AP");
SetPointを使うときに、最初に用意した点の数より大きな点番号を引数にした場合は自動的に配列を拡張して、点を追加することができる。
といっても、当然配列を拡張するのでコストは高い作業なので、最初から丁度いい大きさの配列を用意するほうが望ましい。
ifstreamで作らずに、データファイルからコンストラクタで一発でTGraphを作る方法。
0 0 1 10 2 20
のようなファイルを用意して
TGraph *gr = new TGraph("ex.dat","%lg %lg");
とする。
0 1 0 1 1 10 2 1 20
のようなファイルで1行目と3行目をデータとして使いたい場合は
TGraph *gr = new TGraph("ex.dat","%lg %*lg %lg");
又は
TGraph *gr = new TGraph("ex.dat","%lg %*s %lg");
とする。ただしsはchar*型として受け取る(が、スキップするだけなので、この場合どちらでも同じ)。
csvファイルの区切り文字(delimiter)を変えたい場合は
TGraph *gr = new TGraph("ex.dat","%lg %lg",",");
などとすればいい。
TF1を使って初期化することも出来る。どういう場合に役立つかはよくわからない。
TGraph *g = new TGraph(f); //関数の形にプロット TGraph *g = new TGraph(f,"d"); //導関数の形にプロット TGraph *g = new TGraph(f,"i"); //関数の積分の形にプロット TGraph *g = new TGraph(f,"I"); //正規化した積分の形にプロット
複数のグラフを重ね書きする場合は2つ目以降はAを除く。
gr1->Draw("AP"); gr2->Draw("P"); gr3->Draw("P");
Aオプションはフレームを描画するオプションである。
ソースは確認してないけど、おそらくオプションAをつけた場合はTGraphのメンバー変数のTH1にいったんDrawさせているんだと思う。だから2つ目以降のTGraphにAをつけてしまうと上書きされて消えてしまう。
なので、Aは2つ目以降はつけない。
複数のグラフをまとめてDrawするクラス。私は使わないと思うから書かないけど、3D表示とかも出来る。
{ gStyle->SetMarkerStyle(20); gStyle->SetMarkerSize(0.7); TF1 *f1 = new TF1("f1","x^3+x^2+2",-5,5); TF1 *f2 = new TF1("f2","10*x^2+x - 50",-5,5); TF1 *f3 = new TF1("f3","-x -8",-5,5); TGraph *g1 = new TGraph(f1); g1->SetMarkerColor(kRed); TGraph *g2 = new TGraph(f2); g2->SetMarkerColor(kBlue); TGraph *g3 = new TGraph(f3); g2->SetMarkerColor(kOrange); TMultiGraph *mg = new TMultiGraph(); // Axisにtitleを付けたい場合は // TMultiGraph *mg = new TMultiGraph("name","title; xtitle; ytitle"); // 又は // mg->SetTitle("title; xtitle; ytitle"); mg->Add(g1); mg->Add(g2); mg->Add(g3); mg->Draw("ap"); }
TMultiGraphはすべてのグラフが範囲に収まるように調整してくれる。逆に言うとそれぐらいしかいいところがないと思う。
詳しくはここを見ましょう→http://root.cern.ch/root/html/TGraphPainter.html
"L" すべての点を単純に折れ線で結ぶ
"F" フィル領域を描く
"F1" "F"と同じだがX=0またはY=0の近くのフィル領域の描画には適さない
"F2" フィル領域にビンの中心を結ぶ折れ線を引く
"A" グラフを座標軸で囲む
"C" 滑らかな曲線を描く
"*" 各点に星印をつける
"P" 各点にグラフの現在のマーカーをつける
"B" 各点に棒グラフを描く
"[]" 誤差棒の端の縦/横の線だけを描く。このオプションはTGraphAsymmErrorsだけに使える。
"1" ylow = rwymin
gr->SetTitle("title;Xtitle;Ytitle")
gr->SetMaximum(x); gr->SetMinimum(x);
X軸は下で成功した。
gr->GetXaxis()->SetLimits(min,max);
ちなみにLogScaleの時に、SetLimitsで軸の最小値を0にした場合は(最大値についても)無視される?みたい。
下のようにしても、理由は知らないが、軸に影響はない。
gr->GetXaxis()->SetRangeUser(min,max);
ちょっと違うけど、下でもできる。
gr->GetHistogram()->SetBins(てきとう,min,max);
ただし、これはヒストグラムのbinningを変えている荒業。
普通にgr→Write()するだけなんだけど、少しだけ注意事項。
TGraphはデフォルトでオブジェクト名とタイトルがGraphになるようにしている。
TFile** hoge.root TFile* hoge.root KEY: TGraph Graph;1 Graph
なので区別したいなら、したのように予め名前とtitleをつけたほうがいいと思う。
gr->SetName("name"); gr->SetTilte("title"); gr->Write();