First Step of Linux and ROOT

Last updated on September 18, 2026

Download the article

Lesson 0 install root and software on your compute

If you get the THU’s computer cluster account, use following commands to get into.

$ ssh -XY -p 48571 -o ServerAliveInterval=5 yourname@hepthu.com

You can also run code on your pc if you have installed root, it’s up to you.

homebrew Click this link to go to the Homebrew page, follow the instructions to install Homebrew on your Mac. Homebrew is a software package manager that allows you to download many applications on your Mac!
After finishing the installation, paste the following command in a macOS terminal to install CERN ROOT software: $ brew install root. This way, you can also install applications like firefox which you can’t find in the App Store.
Additionally, $ indicates a shell command, so drop the $ sign when you copy the command.

Lesson 1 base commands for Linux


Some simple commands you can have a try!

1
2
3
4
5
6
7
8
9
10
11
pwd  #print work directory
cd /path/to/directory #change directory
cd .. #back to parent directory
ls #list directory contents
mkdir test #make a directory
touch test.txt #creat a new txt file
cp test.txt copy.txt #copy and rename a file
mv copy.txt copy1.txt #move and rename a file
rm copy.txt #remove
rm -r test #delete a directory
vi filename #open or make a file with vim editor

Vim editor

1
2
3
4
5
i     #insert, edit mode
Esc #exit edit mode
:wq #save and exit
:q #exit, will mention you if you have modified the file
:q! #exit !without! save

you will use the next commands from time to time
vi somefile -> press i into edit mode -> do something ->esc exit edit mode -> :wq

Some tricks that can help you:

Press the TAB key to automatically complete some of your commands, such as file names. Pressing it twice will show you the available commands/file names you can input.
Press ↑ to retrieve previous commands.


Lesson 2: Basic ROOT exercises

Enter the ROOT environment:

$ root

Use root [0] .q to exit ROOT.

ROOT can interpret commands one line at a time.

You can also interpret commands while entering them, or compile and run a macro file with root yourprogram.C.

For example, enter the following commands in ROOT to create an empty histogram:
TH1F* graph=new TH1F("name","title",200,2.97,3.03);
graph->Draw();
An empty histogram is not very interesting, so use Fill to add data

You can also create a macro file to hold a longer program.

Get start!

$ vi test.C

//push i to enter the insert mode//

1
2
3
4
5
6
7
8
9
10
void test() //be sure it is similar with your file name

{

TH1F* graph=new TH1F("name","title",200,2.97,3.03);
//TH1F* graph name=new TH1F("name","title”,bins, low, high)

graph->Draw(); //draw your graph

}

//push ESC to end the insert mode//

:wq //save and exit

$ root test.C //run your code

///successful!///

.q //exit the program


Let’s add something into your graph!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void test(){

//TCanvas* c1=new TCanvas("c1","fitting with Gaussian function"); //if you don’t set the canvas’s name, it will created default canvas with name c1

//c1->SetGrid(); // set grid

TH1F* graph=new TH1F("name","title",200,2.97,3.03);

graph->Fill(2.99); // you can add just one data in your graph using “Fill” command and try to draw your graph.It’s boring, right? We need more!

TRandom n; // define a random variable n

for (int i=0;i<1000;++i){

graph->Fill(n.Gaus(3,0.005)); //Determine variable n using Gaussian distribution and fill to graph

}

graph->Draw();

graph->Fit("gaus"); //fit your graph with Gaussian function

}

Wow! now you can use root to do some simple fit works. but we usually use RooFit to do more complex job! So, ready for more programs!

These are only basic fits. Many parameters cannot be defined freely, while RooFit provides more professional and flexible fitting functions.

Lesson 2 Gaussian fitting using RooFit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include "RooAbsReal.h"
#include "RooRealVar.h"
#include "RooGaussian.h"
#include "RooChebychev.h"
#include "RooAddPdf.h"
//#include "RooProdPdf.h"
#include "RooDataSet.h"
//#include "RooDataHist.h"
//#include "RooFitResult.h"
#include "RooPlot.h"
//#include "RooArgList.h"
//#include "RooArgSet.h"
//#include "RooRandom.h"
//#include "RooPrintable.h"
using namespace RooFit;
void test() {
RooRealVar x("x", "x", 2.97, 3.03);
// Declares a real-valued variable 'x' with a range from 2.97 to 3.03.

RooRealVar mean("mean", "mean", 3.0, 2.8, 3.2);
// Declares a real-valued variable 'mean' with an initial value of 3.0 and a range from 2.8 to 3.2.

RooRealVar sigma("sigma", "sigma", 0.003, 0.002, 0.003);
// Declares a real-valued variable 'sigma' with an initial value of 0.003 and a range from 0.002 to 0.003.

RooAbsPdf* gaus = new RooGaussian("gaus", "gaus", x, mean, sigma);
// Creates a Gaussian probability density function (PDF) named 'gaus' with 'x' as the observable, 'mean' as the mean, and 'sigma' as the standard deviation.

RooRealVar n("n", "n", 0, 0, 50000);
// Declares a real-valued variable 'n' with an initial value of 0 and a range from 0 to 50000.

RooExtendPdf* exp = new RooExtendPdf("exp", "exp", *gaus, n);
// Creates an extended PDF named 'exp' that combines the Gaussian PDF 'gaus' with the variable 'n'.

RooAddPdf total("total", "total", RooArgList(*exp), RooArgList(n));
// Creates a composite PDF named 'total' that consists of the extended PDF 'exp' and the variable 'n'.

RooDataSet* data;
// Declares a pointer to a RooDataSet object named 'data'.

data = gaus->generate(RooArgSet(x), 1000);
// Generates a dataset 'data' with 1000 events based on the Gaussian PDF 'gaus' and the observable 'x'.

RooFitResult* result = total.fitTo(*data, Save());
// Fits the composite PDF 'total' to the dataset 'data' and saves the fit result in 'result'.

TCanvas* c1 = new TCanvas("c1", "fitting with Gaussian function");
// Creates a new canvas named 'c1' with the title "fitting with Gaussian function" for plotting.

RooPlot* xframe = x.frame(RooFit::Title("Fit GausX"));
// Creates a frame for the observable 'x' with the title "Fit GausX".

data->plotOn(xframe);
// Plots the dataset 'data' on the frame 'xframe'.

total.plotOn(xframe);
// Plots the composite PDF 'total' on the frame 'xframe'.

xframe->Draw();
// Draws the frame 'xframe' on the canvas.
}


One function can look a little lonely. We can use RooAddPdf to combine two functions.

RooRealVar fsig(“fsig”,”fsig”,0.2,0,1.);

//model(x) = fsig*gaus(x) + (1-fsig)*chev(x)

RooAddPdf model(“fsig”,”fsig”,RooArgList(gaus,chev),fsig);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void test(){
using namespace RooFit;
//build gaussian and shev pdf
RooRealVar x("x","x",2.97,3.03);
RooRealVar mean("mean","mean",3.0,2.8,3.2);
RooRealVar sigma("sigma","sigma",0.005,0.003,0.007);
RooRealVar a0("a0","a0",0.005,0.004,0.006);
RooAbsPdf* gaus=new RooGaussian("gaus","gaus",x,mean,sigma);
RooAbsPdf* shev=new RooChebychev("shev","shev",x,a0);
RooRealVar n1("n1","n1",0,0,50000);
RooRealVar n2("n2","n2",0,0,50000);
RooExtendPdf*signal1=new RooExtendPdf("sig1","sig1",*gaus,n1);
RooExtendPdf*signal2=new RooExtendPdf("sig2","sig2",*shev,n2);
RooAddPdf totalPdf("total","total",RooArgList(*signal1,*signal2),RooArgList(n1,n2));//totalPdf(x)=signal1(x)+signal2(x)

//generate data point
RooDataSet*data1;
RooDataSet*data2;
data1=gaus->generate(RooArgSet(x),1000);
data2=shev->generate(RooArgSet(x),1000);
data1->append(*data2);

//fit
RooFitResult*result= totalPdf.fitTo(*data1,Save());
RooPlot*xframe=x.frame();
data1->plotOn(xframe);
totalPdf.plotOn(xframe);
totalPdf.plotOn(xframe, Components(*signal1),LineStyle(kDashed),LineColor(6));
totalPdf.plotOn(xframe, Components("sig2"),LineStyle(kDashed),LineColor(2));//two different ways set the Components name
xframe->Draw();
}

Components of the fitted functions

The example above is a one-dimensional fit. In many analyses we study two different components, which requires a two-dimensional fit. A two-dimensional fit does not simply add two PDFs; it uses products, which can be understood as the probability that two components occur together. For an x event with probabilities p(x) and q(x), and a y event with probabilities p(y) and q(y), there are four possible combinations. Their probabilities include p(x)*p(y), the probability that x and y occur together. We therefore build four probability functions for the different combinations.


Note: The default random seed is 0. A seed is usually based on the current time so that each run produces different data, but a fixed seed is convenient for debugging. With seed 0, a program like this produces the same data every time. You can set the seed with RooRandom::randomGenerator()->SetSeed(seed) or with gRandom->SetSeed(seed). The first controls RooFit’s random generator; the second controls ROOT’s global random generator and can also cover uses outside RooFit. Use gRandom->GetSeed() to inspect the current seed.

1
2
3
4
5
TDatime* starttime=new TDatime();
Int_t today=starttime->GetDate();
Int_t clock=starttime->GetTime();
Int_t seed=today+clock;
RooRandom::randomGenerator()->SetSeed(seed);

Lesson 3 2D fitting

The following section shows two two-dimensional fits.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <TH2.h>
#include <TStyle.h>
#include <TCanvas.h>
#include <iostream>
#include <fstream>
#include "TF1.h"
#include "TText.h"
#include "TLorentzVector.h"
#include "TVector3.h"
#include "TLorentzRotation.h"
#include "RooNumIntConfig.h" //no matter what, copy directly!

using namespace RooFit;
void test(){
//build gaussian pdf in two dimension
RooRealVar x("x","x",2.7,4);

RooRealVar meanx("meanx","meanx",3.0967,2.9,3.2);
RooRealVar sigmax("sigmax","sigmax",0.03,0.01,0.06);
RooAbsPdf* gausx=new RooGaussian("gausx","gausx",x,meanx,sigmax);

RooRealVar ax0("ax0","ax0",0.005,0.004,0.006);
RooRealVar ax1("ax1","ax1",0.01,0.01,0.02);
RooAbsPdf* shevx=new RooChebychev("shevx","shevx",x,RooArgSet(ax0,ax1));

RooRealVar y("y","y",2.7,4);

RooRealVar meany("meany","meany",3.0967,2.9,3.2);
RooRealVar sigmay("sigmay","sigmay",0.03,0.01,0.06);
RooAbsPdf* gausy=new RooGaussian("gausy","gausy",y,meany,sigmay);

RooRealVar ay0("ay0","ay0",0.005,0.004,0.006);
RooRealVar ay1("ay1","ay1",0.01,0.01,0.02);
RooAbsPdf* shevy=new RooChebychev("shevy","shevy",y,RooArgSet(ay0,ay1));

//constructor with 2 pdf
RooProdPdf* sigxsigy=new RooProdPdf("sigxsigy","sigxsigy",*gausx,*gausy);
RooProdPdf* bkgxsigy=new RooProdPdf("bkgxsigy","bkgxsigy",*shevx,*gausy);
RooProdPdf* sigxbkgy=new RooProdPdf("sigxbkgy","sigxbkgy",*gausx,*shevy);
RooProdPdf* bkgxbkgy=new RooProdPdf("bkgxbkgy","bkgxbkgy",*shevx,*shevy);

RooRealVar n_sigxsigy("n_sigxsigy","n_sigxsigy",0,0,50000);
RooRealVar n_bkgxsigy("n_bkgxsigy","n_bkgxsigy",0,0,50000);
RooRealVar n_sigxbkgy("n_sigxbkgy","n_sigxbkgy",0,0,50000);
RooRealVar n_bkgxbkgy("n_bkgxbkgy","n_bkgxbkgy",0,0,50000);


RooExtendPdf*signal1=new RooExtendPdf("signal1","signal1",*sigxsigy,n_sigxsigy);
RooExtendPdf*signal2=new RooExtendPdf("signal2","signal2",*sigxbkgy,n_sigxbkgy);
RooExtendPdf*signal3=new RooExtendPdf("signal3","signal3",*bkgxsigy,n_bkgxsigy);
RooExtendPdf*signal4=new RooExtendPdf("signal4","signal4",*bkgxbkgy,n_bkgxbkgy);

RooAddPdf totalPdf("total","total",RooArgList(*signal1,*signal2,*signal3,*signal4),RooArgList(n_sigxsigy,n_sigxbkgy,n_bkgxsigy,n_bkgxbkgy));

//generate data point

RooDataSet*data1;
RooDataSet*data2;
RooDataSet*data3;
RooDataSet*data4;
data1=sigxsigy->generate(RooArgSet(x,y),1000);
data2=sigxbkgy->generate(RooArgSet(x,y),2000);
data3=bkgxsigy->generate(RooArgSet(x,y),2000);
data4=bkgxbkgy->generate(RooArgSet(x,y),4000);

data1->append(*data2);
data1->append(*data3);
data1->append(*data4);

//fit
RooFitResult*result= totalPdf.fitTo(*data1,Save());
//x dimension

//create two canvases, because you have to know two dimensions fitting.
TCanvas*c1 =new TCanvas("c1","Fitting X");
c1->cd();
RooPlot*xframe=x.frame(RooFit::Title("Fit GausX"));
data1->plotOn(xframe);
totalPdf.plotOn(xframe,Name("fullModel"));
totalPdf.plotOn(xframe,Components(*signal1),LineColor(2),LineStyle(1),Name("JpsiJpsi"));
totalPdf.plotOn(xframe,Components(*signal2),LineColor(6),LineStyle(1),Name("BkgJpsi"));
totalPdf.plotOn(xframe,Components(*signal3),LineColor(7),LineStyle(1),Name("JpsiBkg"));
totalPdf.plotOn(xframe,Components(*signal4),LineColor(8),LineStyle(1),Name("BkgBkg"));

TLegend leg(0.7, 0.7, 0.9, 0.9);
leg.AddEntry(xframe->findObject("fullModel"), "Full Model", "L");
leg.AddEntry(xframe->findObject("JpsiJpsi"), "J/#psi_{#mu1#mu2}J/#psi_{#mu3#mu4}", "L");
leg.AddEntry(xframe->findObject("BkgJpsi"), "Bkg_{#mu1#mu2}J/#psi_{#mu3#mu4}", "L");
leg.AddEntry(xframe->findObject("JpsiBkg"), "J/#psi_{#mu1#mu2}Bkg_{#mu3#mu4}", "L");
leg.AddEntry(xframe->findObject("BkgBkg"), "Bkg_{#mu1#mu2}Bkg_{#mu3#mu4}", "L");

xframe->Draw();
leg.DrawClone();

//y dimension
TCanvas*c2 =new TCanvas("c2","Fitting Y");
c2->cd();
RooPlot*yframe=y.frame(RooFit::Title("Fit GausY"));
data1->plotOn(yframe);
totalPdf.plotOn(yframe);
totalPdf.plotOn(yframe,Name("fullModel"));
totalPdf.plotOn(yframe,Components(*signal1),LineColor(2),LineStyle(1),Name("JpsiJpsi"));
totalPdf.plotOn(yframe,Components(*signal2),LineColor(6),LineStyle(1),Name("BkgJpsi"));
totalPdf.plotOn(yframe,Components(*signal3),LineColor(7),LineStyle(1),Name("JpsiBkg"));
totalPdf.plotOn(yframe,Components(*signal4),LineColor(8),LineStyle(1),Name("BkgBkg"));

TLegend leg2(0.7, 0.7, 0.9, 0.9);
leg2.AddEntry(yframe->findObject("fullModel"), "Full Model", "L");
leg2.AddEntry(yframe->findObject("JpsiJpsi"), "J/#psi_{#mu1#mu2}J/#psi_{#mu3#mu4}", "L");
leg2.AddEntry(yframe->findObject("BkgJpsi"), "Bkg_{#mu1#mu2}J/#psi_{#mu3#mu4}", "L");
leg2.AddEntry(yframe->findObject("JpsiBkg"), "J/#psi_{#mu1#mu2}Bkg_{#mu3#mu4}", "L");
leg2.AddEntry(yframe->findObject("BkgBkg"), "Bkg_{#mu1#mu2}Bkg_{#mu3#mu4}", "L");

yframe->Draw();
leg2.DrawClone();

TCanvas*c3 =new TCanvas("c3","2D plot");
c3->cd();
TH2F* mytwojpsimass = new TH2F("mytwojpsimass","mytwojpsimass",40,2.7,3.5,40,2.7,3.5);
data1->fillHistogram(mytwojpsimass,RooArgList(x,y));
mytwojpsimass->Draw("colz");

}

fit_xyTwo-dimensional density plot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <TH2.h>
#include <TStyle.h>
#include <TCanvas.h>
#include <iostream>
#include <fstream>
#include "TF1.h"
#include "TText.h"
#include "TLorentzVector.h"
#include "TVector3.h"
#include "TLorentzRotation.h"
#include "RooNumIntConfig.h" //no matter what, copy directly!
using namespace RooFit;
void test(){
//build gaussian pdf in two dimension
RooRealVar x("x","x",2.7,4);
RooRealVar meanx1("meanx1","meanx1",3.0967,2.9,3.2);
RooRealVar sigmax1("sigmax1","sigmax1",0.03,0.01,0.06);
RooAbsPdf* gausx1=new RooGaussian("gausx1","gausx1",x,meanx1,sigmax1);

RooRealVar meanx2("meanx2","meanx2",3.686,3.5,3.8);
RooRealVar sigmax2("sigmax2","sigmax2",0.1,0.01,0.2);
RooAbsPdf* gausx2=new RooGaussian("gausx2","gausx2",x,meanx2,sigmax2);

RooRealVar y("y","y",2.7,4);

RooRealVar meany1("meany1","meany1",3.0967,2.9,3.2);
RooRealVar sigmay1("sigmay1","sigmay1",0.03,0.01,0.06);
RooAbsPdf* gausy1=new RooGaussian("gausy1","gausy1",y,meany1,sigmay1);

RooRealVar meany2("meany2","meany2",3.686,3.5,3.8);
RooRealVar sigmay2("sigmay2","sigmay2",0.1,0.01,0.2);
RooAbsPdf* gausy2=new RooGaussian("gausy2","gausy2",y,meany2,sigmay2);

//constructor with 2 pdf
RooProdPdf* gausx1y1=new RooProdPdf("gausx1y1","gausx1y1",*gausx1,*gausy1);
RooProdPdf* gausx1y2=new RooProdPdf("gausx1y2","gausx1y2",*gausx1,*gausy2);
RooProdPdf* gausx2y1=new RooProdPdf("gausx2y1","gausx2y1",*gausx2,*gausy1);

RooRealVar n_x1y1("n1","n1",0,0,50000);
RooRealVar n_x1y2("n2","n2",0,0,50000);
RooRealVar n_x2y1("n3","n3",0,0,50000);

RooAddPdf totalPdf("total","total",RooArgList(*gausx1y1,*gausx1y2,*gausx2y1),RooArgList(n_x1y1,n_x1y2,n_x2y1));

//generate data point

RooDataSet*data1;
RooDataSet*data2;
RooDataSet*data3;
data1=gausx1y1->generate(RooArgSet(x,y),1000);
data2=gausx1y2->generate(RooArgSet(x,y),1000);
data3=gausx2y1->generate(RooArgSet(x,y),1000);

data1->append(*data2);
data1->append(*data3);

//fit
RooFitResult*result= totalPdf.fitTo(*data1,Save());
//x dimension
//create two canvases, because you have to know two dimensions fitting.
TCanvas*c1 =new TCanvas("c1","Fitting X");
c1->cd();
RooPlot*xframe=x.frame(RooFit::Title("Fit GausX"));
data1->plotOn(xframe,Name("data1"));
totalPdf.plotOn(xframe,Name("fullModel"));
totalPdf.plotOn(xframe,Components(*gausx1y1),LineColor(2),LineStyle(1),Name("JpsiJpsi"));
totalPdf.plotOn(xframe,Components(*gausx1y2),LineColor(6),LineStyle(1),Name("JpsiPsi2S"));
totalPdf.plotOn(xframe,Components(*gausx2y1),LineColor(7),LineStyle(1),Name("Psi2SJpsi"));

TLegend* leg= new TLegend(0.7, 0.7, 0.9, 0.9);
leg->AddEntry(xframe->findObject("data1"), "Data", "pe");
leg->AddEntry(xframe->findObject("fullModel"), "Total Fit", "L");
leg->AddEntry(xframe->findObject("JpsiJpsi"), "J/#psi_{#mu1#mu2}J/#psi_{#mu3#mu4}", "L");
leg->AddEntry(xframe->findObject("JpsiPsi2S"), "J/#psi_{#mu1#mu2}#psi(2S)_{#mu3#mu4}", "L");
leg->AddEntry(xframe->findObject("Psi2SJpsi"), "#psi(2S)_{#mu1#mu2}J/#psi_{#mu3#mu4}", "L");

xframe->Draw();
leg->Draw();



//y dimension
TCanvas*c2 =new TCanvas("c2","Fitting Y");
c2->cd();
RooPlot*yframe=y.frame(RooFit::Title("Fit GausY"));
data1->plotOn(yframe,Name("data1"));
totalPdf.plotOn(yframe,Name("fullModel"));
totalPdf.plotOn(yframe,Components(*gausx1y1),LineColor(2),LineStyle(1),Name("JpsiJpsi"));
totalPdf.plotOn(yframe,Components(*gausx1y2),LineColor(6),LineStyle(1),Name("JpsiPsi2S"));
totalPdf.plotOn(yframe,Components(*gausx2y1),LineColor(7),LineStyle(1),Name("Psi2SJpsi"));


TLegend leg2(0.7, 0.7, 0.9, 0.9);
leg2.AddEntry(yframe->findObject("data1"), "Data", "pe");
leg2.AddEntry(yframe->findObject("fullModel"), "Total Fit", "L");
leg2.AddEntry(yframe->findObject("JpsiJpsi"), "J/#psi_{#mu1#mu2}J/#psi_{#mu3#mu4}", "L");
leg2.AddEntry(yframe->findObject("JpsiPsi2S"), "J/#psi_{#mu1#mu2}#psi(2S)_{#mu3#mu4}", "L");
leg2.AddEntry(yframe->findObject("Psi2SJpsi"), "#psi(2S)_{#mu1#mu2}J/#psi_{#mu3#mu4}", "L");

yframe->Draw();
leg2.DrawClone();

TCanvas*c3 =new TCanvas("c3","2D plot");
c3->cd();
TH2F* mytwojpsimass = new TH2F("mytwojpsimass","mytwojpsimass",40,2.7,4,40,2.7,4);
data1->fillHistogram(mytwojpsimass,RooArgList(x,y));
mytwojpsimass->Draw("colz");

Two-dimensional fit of J\psi and \psi(2S)

Lesson 3+ Pull Plot

To evaluate how well the fit describes the data, inspect the pull distribution. It straightens the fitted curve and shows the distance of each data point from the curve. The pull plot for xframe is shown below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
RooPlot *xfpull=x.frame(RooFit::Title("    "));//create the RooPlot object xfpull for the pull distribution along x
RooHist *pullx=xframe->pullHist("data","fullModel"); //get the data/model pull from xframe; the names must match the objects drawn on the frame
xfpull->addPlotable(pullx,"p");
xfpull->GetXaxis()->SetTitle("J/#psi_{#mu1#mu2}");
xfpull->GetXaxis()->SetTitleSize(0.15);
xfpull->GetXaxis()->SetLabelSize(0.12);
xfpull->GetYaxis()->SetTitle("Pull");
xfpull->GetYaxis()->SetTitleSize(0.15);
xfpull->GetYaxis()->SetLabelSize(0.1);
xfpull->GetYaxis()->SetTitleOffset(0.2);

//在画布 cpull 上创建两个子画布 pad11 和 pad12,分别用于绘制拟合结果和 pull 分布图。
//在 pad11 上绘制 y 维度的拟合结果 xframe 和图例 leg,TPad的位置和TLegend的类似,都是相对于TCanvas的位置关系
TCanvas cpull("cpull","cpull",800,600);
cpull.cd();
TPad pad11("pad11","pad11",0,0.3,1,1.0);
pad11.SetTopMargin(0.08);
pad11.SetBottomMargin(0.005);
pad11.Draw();
pad11.cd();
xframe->Draw();
leg.Draw();
//在 pad12 上绘制 y 维度的 pull 分布图 yfpull
cpull.cd();
TPad pad12("pad12","pad12",0,0.0,1,0.3);
pad12.SetTopMargin(0.005);
pad12.SetBottomMargin(0.4);
pad12.SetGridx();
pad12.SetGridy(2);
pad12.Draw();
pad12.cd();
xfpull->Draw();

cpull.Update();
cpull.SaveAs("cpull.pdf");

pullXpullY