4. Projections analysis of n-dimensional histograms
4.2. Interface of AliPainter::DrawHistogram()
4.3. Examples of usage AliPainter::DrawHistogram()
5.1. Interface of AliPainter::DivideTPad()
5.2 Usage of AliPainter::DivideTPad()
This is the jupyter notebook with description of principles for working with AliPainter and AliDrawStyle prototypes. This tools provide to users opportunity to set style of their objects and use simple generators for drawing.
First of all, you should take last version of AliPainter and AliDrawStyle. Now the last changes into the master branch, but this is the [github repositoriy](https://github.com/miranov25/AliRoot), which you could also check for the latest modifications.
AliTMinuitToolkit unstable in root6, so be carefull with usage it in fitting part of AliPainter.
Here we defined variables, which we will use below. We are using root and it's not allowing redefinition of variables, unlike python.
In [1]:
%jsroot off
In [2]:
//define all used variables
//%jsroot //allows to get dynamic plots
TH1D *eHis = new TH1D("eHis", "eHis", 100,-5,5);
TCanvas *exC1;
TCanvas *C;
TH1F *hsBeforeStyling[5];
TH1F *hsAfterStyling[5];
TRandom3 rng;
Double_t px,py;
TObjArray *styleArray;
TString cssString;
TPad *cPad;
TFile::SetCacheFileDir(".");
TFile *finput;
TTree *tree;
TObjArray *hisArray;
TList *keys;
TCanvas *canvasQA;
TString elementID = "";
TString classID = "";
TString objectID = "";
TString localStyle = "";
The default tools for modifying of objects style in root looks not so good, because you should create macro in which you should describe all objects and styles manually. It is the reason why we provide to users special tools for styling based on CSS syntax. Let's closer look to syntax of our tool:
A CSS rule-set consists of a selector and a declaration block:
As you can see on this pictures css provide us the opportunity to select object using selector, and set value for the property. In our case we have 3 type of selectors:
You can see how our parser works:
In [3]:
//let initialize empty string,which will be filled after parsing
elementID = "";
classID = "";
objectID = "";
localStyle = "";
//You can see here, how you can set classID,styleID,objectID and elementID to the your element:
pHis = new TH1D("someName.class(classA,classB).style(marker-size:10px;)", "someTitle", 100,-5,5);
AliDrawStyle::GetIds((TObject *) pHis, elementID, classID, objectID, localStyle, 4);
As you can see in Info message (you can manage it using (int) 4 as last argument. In this case you will get detailed output), our objects with the name "someName.class(classA,classB).style(marker-size:10px;)" was parsed to the next things:
You can use these selectors separately or combine them for managing style of your object
Let's create a some object and closer look to how we can create css file, register it into our active environment and apply it:
First of all, let's remember how we can change the style using standart tools:
In [4]:
// We will take real example from root documentation (a bit simplified). You can see it here:
//https://root.cern/doc/master/histpalettecolor_8C.html
C = new TCanvas("C", "C",980,450);
C->Divide(2,1);
C->cd(1);
for (Int_t j = 0; j <5; ++j) {
hsBeforeStyling[j] = new TH1F (TString::Format("h%d", j).Data(),"",100,-4,4);
hsBeforeStyling[j]->SetStats(kFALSE);
for (Int_t i = 0; i < 25000; ++i) {
rng.Rannor(px,py);
hsBeforeStyling[j]->Fill(px,10-j*2);
}
if (j == 0)
hsBeforeStyling[j]->Draw("");
else
hsBeforeStyling[j]->Draw("SAME");
hsAfterStyling[j] = (TH1F *)hsBeforeStyling[j]->Clone(TString::Format("hn%d", j).Data());
}
C->cd(2);
hsAfterStyling[0]->SetMarkerStyle(kFullCircle);
hsAfterStyling[1]->SetMarkerStyle(kFullSquare);
hsAfterStyling[2]->SetMarkerStyle(kFullTriangleUp);
hsAfterStyling[3]->SetMarkerStyle(kFullTriangleDown);
hsAfterStyling[4]->SetMarkerStyle(kOpenCircle);
hsAfterStyling[0]->SetMarkerColor(928);
hsAfterStyling[1]->SetMarkerColor(kAzure+1);
hsAfterStyling[2]->SetMarkerColor(kTeal-1);
hsAfterStyling[3]->SetMarkerColor(kYellow+1);
hsAfterStyling[4]->SetMarkerColor(5);
for (Int_t j = 0; j <5; ++j) {
if (j == 0)
hsAfterStyling[j]->Draw("");
else
hsAfterStyling[j]->Draw("SAME");
}
C->Draw();
Now we've got our canvas with 5 simple gauses or TH1F objects and we modified the style of it using macro style coding.
In order to add your style you should use this function:
AliDrawStyle::RegisterCssStyle(const char *nameOfAddingStyle, TObjArray *arrayWithStyle);
arrayWithStyle consists from TNamed objects, Name of this objects describes selectors and Title describes declarations. In normal case you can parse your .css file into array using
AliDrawStyle::ReadCSSFile("fullName.css"));
So registration of style should looks like:
AliDrawStyle::RegisterCssStyle("nameOfyourStyle", AliDrawStyle::ReadCSSFile("path/to/your/file.css"));
But I want to make my notebook regardless of side files, so we will create array manually:
In [5]:
// Let's define TString with the same style as in example above: selector and declaration
// Pay your attention to the csv interface for values for properties.
// This is a main difference with the real css.
cssString = "TH1F {\n\
marker-style: 20,21,22,23,24;\n\
marker-color: 928,861,839,401,5;\n\
}";
// Then we should register our style, it means upload all values into the memory.
// Do not forget register your style after moifications.
AliDrawStyle::RegisterCssStyle("test", AliDrawStyle::ReadCssString(cssString));
// Finally just apply your style to pad or canvas with your objects,
// it works recursively for each object including pads or canvas.
AliDrawStyle::ApplyCssStyle(((TPad *)C->cd(2)), "test");
C->Draw();
Try to play with style. Change styles of markers, colors, sizes:
In [6]:
// please try to play with it
// try to change style as you wish
cssString = "TH1* {\n\
marker-style: 2,3,4,5,2;\n\
marker-color: 1,2,3,4,4;\n\
marker-size:10px,15px,20px,25px,30px;\n\
}";
AliDrawStyle::RegisterCssStyle("exc1", AliDrawStyle::ReadCssString(cssString));
AliDrawStyle::ApplyCssStyle(((TPad *)C->cd(2)), "exc1");
C->Draw();
In [7]:
hsAfterStyling[0]->SetName("nm.style(marker-color:#ff69b4;marker-size:2;)");
// As you can see color and size of first object will not change after reading string with style, because it
// defined locally in the name of object;
cssString = "TH1F {\n\
marker-style: 20,21,22,23,24;\n\
marker-color: 928,861,839,401,5;\n\
marker-size:10px;\n\
}";
AliDrawStyle::RegisterCssStyle("test", AliDrawStyle::ReadCssString(cssString));
AliDrawStyle::ApplyCssStyle(((TPad *)C->cd(2)), "test");
C->Draw();
Untill now we used only elementID let's see how we can use css in simple alarm application:
</p>Let's imagine that we have some parameter, which should not be more than some value. You can specify style for three cases:</p>
In [8]:
%%cpp
void CheckState(TH1F *his) {
exC1 = new TCanvas("exC1", "exC1",980,450);
exC1->cd(1);
if(his->GetMaximum()<=4000)
his->SetName("h.class(normal)");
else if (his->GetMaximum()>4000 && his->GetMaximum()<6000)
his->SetName("h.class(warning)");
else if (his->GetMaximum()>600)
his->SetName("h.class(alarm)");
his->Draw();
}
In [9]:
cssString = ".normal {\n\
marker-style:20;\n\
marker-color:#00ff00;\n\
marker-size:15px;\n\
}\n\
\
.warning {\n\
marker-style:21;\n\
marker-color:rgb((0,0,255);\n\
marker-size:2;\n\
}\n\
\
.alarm {\n\
marker-style:22;\n\
marker-color:2;\n\
marker-size:15px;\n\
}";
CheckState(hsBeforeStyling[3]);
AliDrawStyle::RegisterCssStyle("alarm", AliDrawStyle::ReadCssString(cssString));
AliDrawStyle::ApplyCssStyle(exC1, "alarm");
exC1->Draw();
Below I provide canvas with objects for you and show list of part properties which you can manage. Try to do with it whatever you want:
Some properties of objects which you can change using css:
In [10]:
// please try to play with it
// try to change style as you wish
C = new TCanvas("C", "C",980,450);
pad = new TPad("pad", "pad",0,0,1,1);
pad->Draw();
pad->cd();
hsBeforeStyling[0]->Fit("gaus");
hsBeforeStyling[0]->Draw("");
C->Draw();
//let's change something:
cssString = "TH1* {\n\
marker-style:20;\n\
marker-color: 928;\n\
marker-size:10px;\n}\n\
\
TF1* {\n\
line-color:7;\n\
line-width:3;\n\
}\n\
\
TPad {\n\
gridX:1;\n\
gridY:1;\n\
fill-color:#e4e4e4;\n\
tickX:1;\n\
tickY:1;\n\
}";
AliDrawStyle::RegisterCssStyle("exc2", AliDrawStyle::ReadCssString(cssString));
AliDrawStyle::ApplyCssStyle(C, "exc2");
C->Draw();
Here we closer look to the tools for drawing, fitting, slicing of projections of n-dimensional histograms. This class called AliPainter.
Our goal is provide to user full access to the data. You can work with n-dimensional histogram and build your own projections don't care about lost data.
Two main functions called:
1. AliPainter::DrawHistogram();
2. AliPainter::DivideTPad();
Let see what you can do with our tool. Now we've next features:
1. Building 1d,2d,3d projections;
2. Setting ranges, including smart slicers (python arrays syntax);
3. Standart root fitters and only for root5 fitter created by AliTMinuitToolkit;
4. Drawing option including adding classes, local styles and divisions;
Here is the interface which we provide to you for working with THnBase.
static void AliPainter::DrawHistogram(THnBase *hisN, const char *expression, TPad *pad=nullptr,\
TObjArray *keepArray=nullptr, TObjArray *metaData=nullptr,\
Int_t verbose=0);
static void AliPainter::DrawHistogram(const TObjArray *histogramArray, const char *expression, TPad *=nullptr,\
TObjArray *=nullptr, TObjArray *=nullptr, Int_t =0);
As you can see here AliPainter::DrawHistogram() is overloaded method, wich allows to use array of THnBase objects or directly THnBase object.
◉ hisN(histogramArray) - input n-dimensional histogram (array of n-dim histograms) which projections you want to draw;
◉ expression - special query which allows to specify ranges, projections, fitters, drawing options. In general, input expression looks like
histogramName(`
◆ `
1. (0,10,0,20,0,30) using integer numbers will return:
THn::GetAxis(0)->SetRange(0,10)
THn::GetAxis(1)->SetRange(0,20)
THn::GetAxis(2)->SetRange(0,30)
2. (0.,10.,0.,20.,0.,30.) using float numbers will return:
THn::GetAxis(0)->SetRangeUser(0.,10.)
THn::GetAxis(1)->SetRangeUser(0.,20.)
THn::GetAxis(2)->SetRangeUser(0.,30.)
3. (0,10,0:20:10:10,0,30) using python array slicers (:) will return to user array of histograms. Algorithm of generating slices is (start:finish:step:delta)
for (auto i = start; i <= finish - delta; i+=step)
{
startVal = i;
finishVal = i + delta;
}
E.g. 0:20:10:10 will be transform into
0,10;10,20;
So, in our example ranges will be:
//hisN1
THn::GetAxis(0)->SetRange(0,10)
THn::GetAxis(1)->SetRange(0,10)
THn::GetAxis(2)->SetRange(0,30)
//hisN2
THn::GetAxis(0)->SetRange(0,10)
THn::GetAxis(1)->SetRange(10,20)
THn::GetAxis(2)->SetRange(0,30)
◆ `
new projection created THn his = hisInput->Projection(i0,i1....);
at minimum one dimension should be specified, maximum 3D;
◆ `
1. fitterName - standard root fit functions. Also supports AliTMinuitToolkit fitters, but only in root5);
2. fitOption - standard root fit options. For root 5 also you can look to AliTMinuitToolkit fitOptions;
3. range - {x0min,x0max,x1min,xm1max,...} in case not specified - range is not set;
◆ `
1. padDiv - parameter which specified switch pad option:
div = 0 - use the same pad for drawing; (default value);
div = 1 - switch from current pad to the next pad for drawing;
2. lims - allows to set limits for specified axis(not specified by default). Support statistical units and expressions:
xlim = [xmin, xmax] - set the minima and maxima for x-axes;
ylim = [ymin, ymax] - set the minima and maxima for y-axes;
2.1 Numbers: ylim=[100,200];
2.2 Stats units: ylim=[
2.3 Expression with stat units:
ylim=[0.5*`
zlim = [zmin, zmax] - set the minima and maxima for z-axes;
3. className - adds name of class to each object of drawing. It necessary for applying css style. [See AliDrawStyle](http://alidoc.cern.ch/AliRoot/master/class_ali_draw_style.html)
class = [Raw,Error] - in the end of name of object will add ".class(Raw,Error)";
class = Raw - the same with class=[Raw] will add .class(Raw);
class = [] - in this case nothing will add to the end of the name of object (default);
4. drawOpt - root standard draw options [see docs](https://root.cern.ch/root/htmldoc/guides/users-guide/Histograms.html#draw-options)
◉ pad - you can specify which pad you want to use for drawing. In case div=1 in drawingOptions this pad will be starting point. (by default NULL and DrawHistogram use gPad)
◉ keepArray - array for keeping temporary objects.
◉ metaData - array with metadata describing histogram.
First of all let's prepare the data. Let's use something more real then our histogram before.
In [11]:
// we prepared file which you can download without registration. let's use it:
finput = TFile::Open("http://aliqatrkeos.web.cern.ch/aliqatrkeos/performance/AliPainterTest.root","CACHEREAD");
tree = (TTree *) finput->Get("hisPtAll");
keys = finput->GetListOfKeys();
// then we created array with THn histograms
hisArray = new TObjArray();
for (Int_t iKey = 0; iKey<keys->GetEntries();iKey++) {
TObject *o = finput->Get(TString::Format("%s;%d", keys->At(iKey)->GetName(), ((TKey *) keys->At(iKey))->GetCycle()).Data());
hisArray->AddLast(o);
}
In [12]:
canvasQA = new TCanvas("canvasQA", "canvasQA", 1200, 800);
AliPainter::DrawHistogram(hisArray, "hisK0DMassQPtTgl()(0)()()");
canvasQA->Draw();
Now let's choose some part of ranges:
In [13]:
// if you don't remember numbers of bin you can use float numbers for ranges, it means that SetRangeUser will be used:
canvasQA = new TCanvas("canvasQA", "canvasQA", 1200, 800);
canvasQA->Divide(1,3);
canvasQA->cd(1);
AliPainter::DrawHistogram(hisArray, "hisK0DMassQPtTgl(-0.01,0.01)(0)()()");
canvasQA->Draw();
// in the other case you can use just number of bins:
canvasQA->cd(2);
AliPainter::DrawHistogram(hisArray, "hisK0DMassQPtTgl(20,80)(0)()()");
canvasQA->Draw();
// let's see how we can use slicers. Imagine that you can see all bins of first projections and
// two periods of second projection, let it bee 40,60 and 60,80, if we know that total of bins are 80:
canvasQA->cd(3);
AliPainter::DrawHistogram(hisArray, "hisK0DMassQPtTgl(0,100,40:80:20:20)(0)()()");
canvasQA->Draw();
Pay your attention to the last pad. As you can see here it provide us two histogram on the one pad, but you be able to change it using [div](#div) flag in [drawString](#drawString). Let's see what happend if we add it, but first of all we should prepare two pads:
In [14]:
canvasQA = new TCanvas("canvasQA", "canvasQA", 1200, 800);
canvasQA->Divide(1,2);
canvasQA->cd(1);
AliPainter::DrawHistogram(hisArray, "hisK0DMassQPtTgl(0,100,40:80:20:20)(0)()(div=1)");
canvasQA->Draw();
As you can see in output of previous cell AliPainter switched active pad automatically. It means that you can use set of pads and we also provided to you opportunity to dividing pads, but we will tell about it later. Let's go further and let's see to fitting option and add drawOpt:
In [15]:
canvasQA = new TCanvas("canvasQA", "canvasQA", 1200, 800);
AliPainter::DrawHistogram(hisArray, "hisK0DMassQPtTgl(20,80,40,60,0,10)(0)(name=gaus,option=W)(drawOpt=E)");
canvasQA->Draw();
Now let's talk about divisions of canvas.
How you already know in root we have canvases and pads. We can use our dividing function to both of this classes.
Let see what you can do with our tool. Now we've next features:
1. You can get any combinations of pads on the canvas;
2. Share axis in order to combine pads;
3. Set any margin values in pixels;
Main function for dividing is:
AliPainter::DivideTPad(TPad *pad, const char *division, const char *classID="",\
const char *style="", Int_t verbose=0)
◉ pad - input pad or canvas.
◉ division string - `
◆ orientation - (vertical, horizontal):
vertical - it's allows to you choose vertical orientation
horizontal - it's allows to you choose vertical orientation (default)
◆ numberOfPads - it should be specify like csv array. E.g. "1,1" it means two pads. If orientation is vertical it will looks like column, if horizontal like row. Also you can specify more than one pad: e.g in this case "2,1" it means in case horizontal orientation two pads in first row and one in the second raw. So in case of horizontal orientation count of numbers will be count of rows and the number will be specify number of pads in row. In case vertical orientation it will look like you transpose you horizontal orientation.
◆ sharedMargin - this option allows to you choose wich margin you want to make equal to 0: Each pad has 4 margin(b-bottom, l-left, t-top, r-right). So in case you specify t, it will set top margin to 0, etc. One more useful value is "m" - middle, in case of horizontal orientation it will set right and left margin to 0, in case of vertical orientation top and bottom margin will set to 0.
◆ units - you can set value to the chosen margin explicitly. For that you should specify value and units. E.g. b0.3 means set bottom margin 0.3, or rpx100 means set right margin 100 pixels.
◆ classID - optional parameter for [styling](#style_css_syn).
Let's look to some examples:
We will use already created histograms.
In [16]:
//horizontal orientation
C = new TCanvas("C", "C",980,450);
AliPainter::DivideTPad(C, "horizontal[1,1]");
C->cd(1);
AliPainter::DrawHistogram(hisArray, "hisK0DMassQPtTgl(20,80,20:80:20:20,0,10)(0)(name=gaus,option=W)(drawOpt=E, div=1)");
C->Draw();
In [17]:
//vertical orientation
C = new TCanvas("C", "C",980,450);
AliPainter::DivideTPad(C, "vertical[1,1]");
C->cd(1);
AliPainter::DrawHistogram(hisArray, "hisK0DMassQPtTgl(20,80,20:80:20:20,0,10)(0)(name=gaus,option=W)(drawOpt=E, div=1)");
C->Draw();
In [18]:
//horizontal for 2 by 2
C = new TCanvas("C", "C",980,450);
AliPainter::DivideTPad(C, "horizontal[2,2]");
C->cd(1);
AliPainter::DrawHistogram(hisArray, "hisK0DMassQPtTgl(20,80,0:80:20:20,0,10)(0)(name=gaus,option=W)(drawOpt=E, div=1)");
C->Draw();
In [19]:
//vertical for 2 by 1
C = new TCanvas("C", "C",980,450);
AliPainter::DivideTPad(C, "vertical[2m,1tpx50]");
C->cd(1);
AliPainter::DrawHistogram(hisArray, "hisK0DMassQPtTgl(20,80,0:80:20:20,0,10)(0)(name=gaus,option=W)(drawOpt=E, div=1)");
C->Draw();
In [20]:
canvasQA = new TCanvas("canvasQA", "canvasQA", 1200, 800);
AliPainter::DivideTPad(canvasQA,"horizontal[1,1,1,1]", "Canvas41");
AliPainter::GetNextPad(canvasQA);
//you can find this styles in your sources of AliRoot
AliDrawStyle::RegisterCssStyle("figTemplateHex", AliDrawStyle::ReadCSSFile("$AliRoot_SRC/STAT/test/figTemplateHex.css"));
AliPainter::DrawHistogram(hisArray, "hisPtAll(0,10)(0)()(div=1,drawOpt=E,class=PtAll)");
AliPainter::DrawHistogram(hisArray, "hisPtITS(0,10)(0)()(div=1,drawOpt=E,class=PtIts)");
AliPainter::DrawHistogram(hisArray, "hisK0DMassQPtTgl(1,1)(2)()(div=1,drawOpt=E,class=Tgl)");
AliPainter::DrawHistogram(hisArray, "hisK0DMassQPtTgl(20,80,40:80:20:20,0,10)(0)(name=gaus,option=W)(class=Mass,drawOpt=E)");
AliDrawStyle::ApplyCssStyle(canvasQA, "figTemplateHex");
canvasQA->Draw();
In [ ]: