ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/UHHAnalysis/SFramePlotter/SPlotter.cxx
Revision: 1.12
Committed: Tue May 14 13:14:27 2013 UTC (11 years, 11 months ago) by rkogler
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.11: +23 -4 lines
Log Message:
added normalisation uncertainty for different processes

File Contents

# Content
1 #include <iostream>
2 #include <iomanip>
3
4 #include <TObjArray.h>
5 #include <TObjString.h>
6 #include <TStyle.h>
7 #include <TROOT.h>
8 #include <TPaveText.h>
9 #include <TLegend.h>
10 #include <TLegendEntry.h>
11 #include <TLatex.h>
12 #include <TEllipse.h>
13 #include <TF1.h>
14 #include <TMath.h>
15 #include <TColor.h>
16 #include "SPlotter.h"
17
18 using namespace std;
19
20 SPlotter::SPlotter()
21 {
22 m_can = NULL;
23 m_ps = NULL;
24 m_ps_name = "default.ps";
25
26 m_pad1 = NULL;
27 m_pad2 = NULL;
28
29 m_rp1_top = NULL;
30 m_rp1 = NULL;
31 m_rp2_top = NULL;
32 m_rp2 = NULL;
33
34 m_page = 0;
35 m_lumi = 0;
36 m_syserr = -1;
37 debug = false;
38 bShapeNorm = false;
39 bPortrait = true;
40 bDrawEntries = false;
41 bDrawLumi = true;
42 bDrawLegend = true;
43 bPlotRatio = false;
44 bSingleEPS = false;
45 need_update = true;
46
47 }
48
49 SPlotter::~SPlotter()
50 {
51 Cleanup();
52 }
53
54 void SPlotter::SetPsFilename(TString name)
55 {
56 if (!name.EndsWith(".ps")){
57 cerr << "SPlotter::SetPsFilename, given filename: " << name
58 << " does not end with .ps, intention? Please correct steering." << endl;
59 exit(EXIT_FAILURE);
60 }
61 m_ps_name = name;
62
63 }
64
65 void SPlotter::DoStacking(vector<TObjArray*>& hists, TObjArray* StackNames)
66 {
67 if (hists.size()==0){
68 cerr << "SPlotter::DoStacking: Empty array of histograms. Aborting." << endl;
69 exit(EXIT_FAILURE);
70 }
71
72 if (!StackNames){ // trivial case: do nothing
73 return;
74 }
75
76 // loop over all histogram arrays
77 int narr = hists.size();
78 for (int i=narr-1; i>=0; --i){
79 TObjArray* ha = hists[i];
80 if (ha->GetEntries()<1) continue;
81 TString proc = ((SHist*)ha->At(0))->GetProcessName();
82 if (debug) cout << "SPlotter::DoStacking, hist array = " << i
83 << " process name = " << proc << endl;
84
85 // loop over all stack-names
86 for (int j=0; j<StackNames->GetEntries(); ++j){
87 TString sname = ((TObjString*)StackNames->At(j))->GetString();
88 if (debug) cout << " stack name = " << sname << endl;
89 if (proc.Contains(sname)){
90 if (debug) cout << " -> found match, stacking this array." << endl;
91 StackHists(hists, i);
92 break;
93 }
94 }
95 }
96
97 if (debug) cout << "SPlotter::DoStacking: Done." << endl;
98
99 return;
100
101 }
102
103 void SPlotter::StackHists(std::vector<TObjArray*>& hists, int index)
104 {
105 // stack histograms at position 'index' with an existing array of stacks
106 // in hists
107 // if the stacks don't exist, they are created and added to the array
108
109 // get the stack (create a new one if it doesn't exist yet)
110 TObjArray* stacks = GetStacks(hists, index);
111
112 // add the histograms at 'index' to the stack
113 for (int i=0; i<stacks->GetEntries(); ++i){
114 SHist* stack = (SHist*)stacks->At(i);
115 SHist* hist = (SHist*)hists[index]->At(i);
116 if (!stack || !hist){
117 cerr << "SPlotter::StackHists: stack or hist at position " << i
118 << " does not exist! Abort." << endl;
119 cerr << "index of hists = " << hists.size() << " histograms = " << hists[index]->GetEntries() << endl;
120 exit(EXIT_FAILURE);
121 }
122 // sanity check: compare names
123 TString stackname = stack->GetStack()->GetName();
124 TString histname = hist->GetHist()->GetName();
125 if (!stackname.Contains(histname)){
126 cerr << "SPlotter::StackHists: incompatible histograms at position " << i
127 << ", stackname = " << stackname << " histname = " << histname
128 << ". Prefer to exit because of consistency." << endl;
129 exit(EXIT_FAILURE);
130 }
131 // still here? do the stackin'!
132 hist->GetHist()->SetFillColor(hist->GetHist()->GetLineColor());
133 hist->GetHist()->SetFillStyle(1001);
134 stack->GetStack()->Add(hist->GetHist());
135 hist->SetIsUsedInStack(true);
136 hist->SetDoDraw(false);
137 stack->SetUnc(hist->GetUnc(), stack->GetStack()->GetHists()->GetSize()-1);
138 if (debug) cout << "stacking hist " << histname << " on " << stackname << " for process " << hist->GetProcessName()
139 << " (dir = " << stack->GetDir() << ")" << endl;
140 if (i==0){
141 cout << "stacking process " << hist->GetProcessName() << " with weight " << hist->GetWeight() << " and uncertainty " << hist->GetUnc() << endl;
142 }
143 }
144
145 return;
146
147 }
148
149 TObjArray* SPlotter::GetStacks(std::vector<TObjArray*>& hists, int index)
150 {
151 // get the array of stacks from the input hists
152 // if it doesn't exist, a new array will be created if index>0
153 // and the hists at position 'index' will be used as blue-print
154
155 // try to find a stack in the array
156 TObjArray* arr = NULL;
157 int narr = hists.size();
158 for (int i=0; i<narr; ++i){
159 if (hists[i]->GetEntries()==0){
160 cerr << "SPlotter::GetStacks: Got no histograms in array " << i
161 << " unexpected behaviour - abort." << endl;
162 exit(EXIT_FAILURE);
163 }
164
165 arr = hists[i];
166 SHist* sh = (SHist*) arr->At(i);
167 if (sh->IsStack()){
168 if (debug) cout << "SPlotter::GetStacks: Found stack at position " << i << endl;
169 return arr;
170 }
171 }
172
173 // no stack found, create a new array with THStacks -> use position 'index'
174 // in the array as a blue-print
175 if (index>-1){
176 if (debug) cout << "SPlotter::GetStacks: Creating new array of THStacks "
177 << "using position " << index << " as blueprint." << endl;
178 if (index>narr){
179 cerr << "SPlotter::GetStacks: Can not create an array of stacks from array"
180 << " index " << index << ", since size is only " << hists.size()
181 << ". Unexpected behaviour - abort." << endl;
182 exit(EXIT_FAILURE);
183 }
184
185 arr = new TObjArray();
186 for (int i=0; i<hists[index]->GetEntries();++i){
187 TString hname = ((SHist*)hists[index]->At(i))->GetHist()->GetName();
188 TString name = hname + "_stack";
189 THStack* st = new THStack(name, "");
190 SHist* sh = new SHist(st);
191 sh->SetDir(((SHist*)hists[index]->At(i))->GetDir());
192 sh->SetProcessName("SM");
193 sh->SetDoDraw(true);
194 arr->Add(sh);
195 if (debug) cout << "SPlotter::GetStacks: Adding stack with name " << name
196 << " in directory " << sh->GetDir() << " at position " << i << endl;
197 }
198
199 hists.push_back(arr);
200 if (debug) cout << "SPlotter::GetStacks: Added stack array to collection. "
201 << "New size = " << hists.size() << ", old = " << narr << endl;
202 }
203
204 return arr;
205
206 }
207
208 void SPlotter::CopyStyle(TH1& h1, TH1* h2)
209 {
210 // copy the style from hist2 to hist1
211 h1.SetMarkerStyle(h2->GetMarkerStyle());
212 h1.SetMarkerSize(h2->GetMarkerSize());
213 h1.SetMarkerColor(h2->GetMarkerColor());
214 h1.SetLineWidth(h2->GetLineWidth());
215 h1.SetLineStyle(h2->GetLineStyle());
216 h1.SetLineColor(h2->GetLineColor());
217 h1.SetFillColor(h2->GetFillColor());
218 return;
219 }
220
221 void SPlotter::SetupGlobalStyle()
222 {
223 // general appearance and style
224
225 gROOT->SetStyle("Plain");
226 gStyle->SetOptStat(0);
227 gStyle -> SetPadTickX(1);
228 gStyle -> SetPadTickY(1);
229
230 gStyle->SetPadBorderMode(0);
231 gStyle->SetPadColor(kWhite);
232 gStyle->SetPadGridX(false);
233 gStyle->SetPadGridY(false);
234 gStyle->SetGridColor(0);
235 gStyle->SetGridStyle(3);
236 gStyle->SetGridWidth(1);
237
238 gStyle->SetFrameBorderMode(0);
239 gStyle->SetFrameBorderSize(1);
240 gStyle->SetFrameFillColor(0);
241 gStyle->SetFrameFillStyle(0);
242 gStyle->SetFrameLineColor(1);
243 gStyle->SetFrameLineStyle(1);
244 gStyle->SetFrameLineWidth(1);
245
246 gStyle->SetTitleFont(42, "XYZ");
247 gStyle->SetLabelFont(42, "XYZ");
248
249 gStyle->SetAxisColor(1, "XYZ");
250 gStyle->SetStripDecimals(kTRUE);
251 gStyle->SetTickLength(0.03, "XYZ");
252 gStyle->SetNdivisions(510, "XYZ");
253
254 gStyle->UseCurrentStyle();
255
256 }
257
258 void SPlotter::Cleanup()
259 {
260 // do what the name suggests
261
262 ClosePostscript();
263 if (m_can){
264 delete m_can;
265 m_can = NULL;
266 }
267 }
268
269 void SPlotter::SetupCanvas()
270 {
271 // set up a canvas, different possibilities
272 // to take into account portrait/landscape
273 // and ratio/no ratio plots
274
275 Int_t CanWidth;
276 Int_t CanHeight;
277 if (bPortrait){
278 CanWidth = 600;
279 CanHeight = 830;
280 } else {
281 CanWidth = 800;
282 CanHeight = 600;
283 }
284
285 // set up the canvas
286 m_can = new TCanvas("canvas","Control Plots", CanWidth, CanHeight);
287
288 Float_t yplot = 0.3;
289 Float_t yratio = 0.17;
290
291 // coordinates:
292 //
293 // set up the coordinates of the two pads: // y6 +-------------+
294 Float_t y1, y2, y3, y4, y5, y6; // | |
295 y6 = 0.97; // | pad1 |
296 y5 = y6-yplot; // y5 |-------------|
297 y4 = y5-yratio; // | rp1 |
298 y3 = 0.49; // y4 +-------------+
299 y2 = y3-yplot; //
300 y1 = y2-yratio; // y3 +-------------+
301 Float_t x1, x2; // | |
302 x1 = 0.01; // | pad2 |
303 x2 = 0.99; // y2 |-------------|
304 // | rp2 |
305 // y1 +-------------+
306 // x1 x2
307
308
309
310 m_rp1_top = new TPad("pad1", "Control Plots 1", x1, y5, x2, y6);
311 m_rp1 = new TPad("rp1", "Ratio1", x1, y4, x2, y5);
312
313 m_rp2_top = new TPad("pad2", "Control Plots 2", x1, y2, x2, y3);
314 m_rp2 = new TPad("rp2", "Ratio2", x1, y1, x2, y2);
315
316
317 m_pad1 = new TPad("pad1", "Control Plots 1", x1, y4, x2, y6);
318 m_pad2 = new TPad("pad2", "Control Plots 2", x1, y1, x2, y3);
319
320 // set margins for portrait mode
321 if (bPortrait){
322
323 m_pad1->SetTopMargin(0.05); m_pad1->SetBottomMargin(0.16); m_pad1->SetLeftMargin(0.19); m_pad1->SetRightMargin(0.05);
324 m_pad2->SetTopMargin(0.05); m_pad2->SetBottomMargin(0.16); m_pad2->SetLeftMargin(0.19); m_pad2->SetRightMargin(0.05);
325
326 m_rp1_top->SetTopMargin(0.065); m_rp1_top->SetBottomMargin(0.0); m_rp1_top->SetLeftMargin(0.19); m_rp1_top->SetRightMargin(0.05);
327 m_rp2_top->SetTopMargin(0.065); m_rp2_top->SetBottomMargin(0.0); m_rp2_top->SetLeftMargin(0.19); m_rp2_top->SetRightMargin(0.05);
328 m_rp1->SetTopMargin(0.0); m_rp1->SetBottomMargin(0.35); m_rp1->SetLeftMargin(0.19); m_rp1->SetRightMargin(0.05);
329 m_rp2->SetTopMargin(0.0); m_rp2->SetBottomMargin(0.35); m_rp2->SetLeftMargin(0.19); m_rp2->SetRightMargin(0.05);
330
331 // margins for landscape
332 } else {
333
334 m_rp1_top->SetTopMargin(0.065); m_rp1_top->SetBottomMargin(0.0); m_rp1_top->SetLeftMargin(0.13); m_rp1_top->SetRightMargin(0.05);
335 m_rp2_top->SetTopMargin(0.065); m_rp2_top->SetBottomMargin(0.0); m_rp2_top->SetLeftMargin(0.13); m_rp2_top->SetRightMargin(0.05);
336
337 if (bPlotRatio){
338 m_rp1->SetTopMargin(0.0); m_rp1->SetBottomMargin(0.35); m_rp1->SetLeftMargin(0.13); m_rp1->SetRightMargin(0.05);
339 m_rp2->SetTopMargin(0.0); m_rp2->SetBottomMargin(0.35); m_rp2->SetLeftMargin(0.13); m_rp2->SetRightMargin(0.05);
340 }
341 }
342
343
344 if (debug){
345 m_rp1_top->SetFillColor(kYellow);
346 m_rp2_top->SetFillColor(kOrange);
347 if (bPlotRatio){
348 m_rp1->SetFillColor(kGray);
349 m_rp2->SetFillColor(kGray);
350 }
351 }
352
353 m_pad1->Draw();
354 m_pad2->Draw();
355
356 m_rp1_top->Draw();
357 m_rp2_top->Draw();
358
359 if (bPlotRatio){
360 m_rp1->Draw();
361 m_rp2->Draw();
362 }
363
364 return;
365
366 }
367
368 void SPlotter::SetupCanvasForEPS()
369 {
370 // set up a canvas for single EPS files
371 // optimised plots for including in theses or publications and documents
372 // different possibilities
373 // ratio/no ratio plots
374
375 Int_t CanWidth;
376 Int_t CanHeight;
377 CanWidth = 400;
378 CanHeight = 400;
379
380 // set up the canvas
381 m_can = new TCanvas("canvas","Control Plots", CanWidth, CanHeight);
382
383 Float_t yplot = 0.65;
384 Float_t yratio = 0.34;
385
386 // coordinates:
387 // set up the coordinates of the two pads: //
388 Float_t y1, y2, y3; // y3 +-------------+
389 y3 = 0.99; // | |
390 y2 = y3-yplot; // | pad1 |
391 y1 = y2-yratio; // y2 |-------------|
392 Float_t x1, x2; // | rp1 |
393 x1 = 0.01; // y1 +-------------+
394 x2 = 0.99; // x1 x2
395 //
396 // No Pad 2!
397
398
399 m_rp1_top = new TPad("pad1", "Control Plots 2", x1, y2, x2, y3);
400 m_rp1 = new TPad("rp1", "Ratio2", x1, y1, x2, y2);
401 m_pad1 = new TPad("pad1", "Control Plots 2", x1, y1, x2, y3);
402
403 m_rp2_top = new TPad("pad1", "Control Plots 2", x1, y2, x2, y3);
404 m_rp2 = new TPad("rp1", "Ratio2", x1, y1, x2, y2);
405 m_pad2 = new TPad("pad1", "Control Plots 2", x1, y1, x2, y3);
406
407
408 m_pad1->SetTopMargin(0.05); m_pad1->SetBottomMargin(0.16); m_pad1->SetLeftMargin(0.19); m_pad1->SetRightMargin(0.05);
409 m_pad2->SetTopMargin(0.05); m_pad2->SetBottomMargin(0.16); m_pad2->SetLeftMargin(0.19); m_pad2->SetRightMargin(0.05);
410
411 m_rp1_top->SetTopMargin(0.065); m_rp1_top->SetBottomMargin(0.0); m_rp1_top->SetLeftMargin(0.19); m_rp1_top->SetRightMargin(0.05);
412 m_rp2_top->SetTopMargin(0.065); m_rp2_top->SetBottomMargin(0.0); m_rp2_top->SetLeftMargin(0.19); m_rp2_top->SetRightMargin(0.05);
413 m_rp1->SetTopMargin(0.0); m_rp1->SetBottomMargin(0.35); m_rp1->SetLeftMargin(0.19); m_rp1->SetRightMargin(0.05);
414 m_rp2->SetTopMargin(0.0); m_rp2->SetBottomMargin(0.35); m_rp2->SetLeftMargin(0.19); m_rp2->SetRightMargin(0.05);
415
416 if (debug){
417 m_rp1_top->SetFillColor(kYellow);
418 m_rp2_top->SetFillColor(kOrange);
419 if (bPlotRatio){
420 m_rp1->SetFillColor(kGray);
421 m_rp2->SetFillColor(kGray);
422 }
423 }
424
425 m_pad1->Draw();
426 m_pad2->Draw();
427
428 m_rp1_top->Draw();
429 m_rp2_top->Draw();
430
431 if (bPlotRatio){
432 m_rp1->Draw();
433 m_rp2->Draw();
434 }
435
436 return;
437
438 }
439
440 void SPlotter::OpenPostscript(TString dir, TString hname)
441 {
442 // create a new ps file with the directory in the name
443 // optional: for EPS files add the name of the histogram
444
445 TString filename(m_ps_name);
446 filename.ReplaceAll(".ps","");
447 filename.Append("_");
448 filename.Append(dir);
449 filename.Append(".ps");
450
451 if (bSingleEPS){
452 filename.ReplaceAll(".ps","");
453 filename.Append("_");
454 filename.Append(hname);
455 filename.Append(".eps");
456
457 } else {
458
459 TString text(dir);
460 text.Prepend("Plotting all histograms in directory ");
461 cout << "\n+-------------------------- SFrame Plotter ---------------------------+" << endl;
462 cout << "| " << setw(60)<< text << " |" << endl;
463 cout << "+---------------------------------------------------------------------+" << endl;
464 m_page = 0;
465 }
466
467 m_ps = NULL;
468 if (bSingleEPS){
469 m_ps = new TPostScript(filename, 113); // eps output
470 } else {
471 if (bPortrait){
472 m_ps = new TPostScript(filename, 111); // ps output
473 m_ps->Range(20.0, 30.0);
474 } else {
475 m_ps = new TPostScript(filename, 112); // ps output
476 m_ps->Range(27.0, 18.0);
477 }
478 }
479
480 }
481
482 void SPlotter::ClosePostscript()
483 {
484 // close the ps file and set page number to 0
485 if (m_ps){
486 m_ps->Close();
487 delete m_ps;
488 m_ps = NULL;
489 }
490 m_page = 0;
491 }
492
493 void SPlotter::ProcessAndPlot(std::vector<TObjArray*> histarr)
494 {
495 // loop over all arrays in the input array and plot them
496
497 if (histarr.size()<1){
498 cerr << "SPlotter::ProcessAndPlot: No arrays of histograms given. Abort." << endl;
499 exit(EXIT_FAILURE);
500 }
501
502 if (histarr[0]->GetEntries()<1){
503 cerr << "SPlotter::ProcessAndPlot: No histograms given. Abort." << endl;
504 exit(EXIT_FAILURE);
505 }
506
507 if (bPlotRatio && histarr.size()==1){
508 cerr << "SPlotter::ProcessAndPlot: Only one process given, can not plot "
509 << " ratio. Steering correct?" << endl;
510 exit(EXIT_FAILURE);
511 }
512
513 SetupGlobalStyle();
514
515 TString psname = m_ps_name;
516 TString current_dir = "";
517
518 // loop over all histograms and plot them!
519 int iplot = 1;
520 bool bleg = true;
521 for (int i=0; i<histarr[0]->GetEntries(); ++i){
522
523 // get the histograms for the different processes
524 vector<SHist*> hists = GetPlottableHists(histarr, i);
525
526 // no plottable hists found at position i
527 if (debug) cout << "Number of plottable hists at index " << i << " = " << hists.size() << endl;
528 if (hists.size()==0) continue;
529
530 if (bShapeNorm) ShapeNormalise(hists);
531
532 int ipad = GetCurrentPad(iplot);
533
534 if (debug) cout << "Plotting histograms " << hists[0]->GetName()
535 << " iplot = " << iplot << " ipad = " << ipad << endl;
536
537 // new directory? create new ps file for ps-book!
538 if (!bSingleEPS){
539 TString dir = hists[0]->GetDir();
540 if (dir.CompareTo(current_dir)!=0){
541 if (iplot!=1) DrawPageNum();
542 Cleanup();
543 SetupCanvas();
544 OpenPostscript(dir);
545 current_dir = dir;
546 iplot = 1;
547 bleg = true;
548 }
549
550 // new page every second plot
551 if (iplot%2==1){
552 if (debug) cout << "Creating new page with number " << m_page << endl;
553 DrawPageNum();
554 if (need_update) m_can->Update();
555 m_ps->NewPage();
556 ++m_page;
557 }
558
559 // new file for each plot in single EPS mode
560 } else {
561 TString dir = hists[0]->GetDir();
562 TString hname = hists[0]->GetName();
563 Cleanup();
564 SetupCanvasForEPS();
565 if (debug) cout << "Creating new eps file with name " << dir << "_" << hname << endl;
566 OpenPostscript(dir, hname);
567 current_dir = dir;
568 iplot = 1;
569 bleg = true;
570 }
571
572 // cosmetics
573 DoCosmetics(hists);
574
575 // ---------- do what we set out to do: plot! ----------------
576
577 if (hists[0]->IsYieldPlot()){ // special treatment for lumi yield plot
578
579 PlotLumiYield(hists[0], ipad);
580
581 } else { // usual plots
582
583 PlotHists(hists, ipad);
584 // draw a legend
585 if (bleg){
586 DrawLegend(GetHistsAtIndex(histarr, i));
587 if (!bDrawLegend) bleg = false;
588 }
589 // draw lumi information
590 if (bDrawLumi) DrawLumi();
591 // draw the ratio
592 if (bPlotRatio) PlotRatios(hists, ipad);
593
594 }
595
596 ++iplot;
597 }
598
599 // done!
600 DrawPageNum();
601 if (need_update) m_can->Update();
602 Cleanup();
603
604 }
605
606 void SPlotter::PlotLumiYield(SHist* hist, int ipad)
607 {
608 // plot the lumi yield histogram
609
610 if (ipad==1) m_pad1->cd();
611 if (ipad==2) m_pad2->cd();
612
613 hist->Draw();
614
615 // calculate the average
616 TH1* h = hist->GetHist();
617 double sum=0;
618 int bins=0;
619 for (int i=1; i<h->GetNbinsX()+1; ++i){
620 if (h->GetBinContent(i)>0){
621 sum += h->GetBinContent(i);
622 bins++;
623 }
624 }
625 double av = sum / bins;
626
627 // calculate average with outlier-rejection (4sigma)
628 sum=0;
629 bins=0;
630 for (int i=1; i<h->GetNbinsX()+1; ++i){
631 if (h->GetBinContent(i)>0){
632 double dev = TMath::Abs( (h->GetBinContent(i) - av)/h->GetBinError(i) );
633 if (dev<4){
634 sum += h->GetBinContent(i);
635 bins++;
636 } else {
637 cout << "Lumi yield: outlier in bin " << i << " with content " << h->GetBinContent(i) << " average = " << av << endl;
638 }
639 }
640 }
641 av = sum / bins;
642
643 // calculate error on mean and chi2
644 double dev = 0;
645 double chi2 = 0;
646 for (int i=1; i<h->GetNbinsX()+1; ++i){
647 if (h->GetBinContent(i)>0){
648 double pull = (h->GetBinContent(i) - av)/h->GetBinError(i);
649 if (TMath::Abs(pull)<4){
650 dev += TMath::Power(h->GetBinContent(i)-av, 2);
651 chi2 += pull*pull;
652 }
653 }
654 }
655 double err = TMath::Sqrt(dev/bins);
656
657 // highlight points with deviations of more than 3, 4 and 5 sigma
658 double xr = h->GetXaxis()->GetXmax() - h->GetXaxis()->GetXmin();
659 double wi = gPad->GetAbsWNDC() * (1 - gPad->GetLeftMargin() - gPad->GetRightMargin());
660 double he = gPad->GetAbsHNDC() * (1 - gPad->GetTopMargin() - gPad->GetBottomMargin());
661 double ar = wi/he;
662 double fudge = 1.;
663 if (bSingleEPS) fudge = 1.2;
664 double r1 = 0.02*xr*fudge;
665 double yr = h->GetMaximum()-h->GetMinimum();
666 double r2 = 0.016*yr*ar*fudge;
667 for (int i=1; i<h->GetNbinsX()+1; ++i){
668 if (h->GetBinContent(i)>0){
669 double pull = (h->GetBinContent(i) - av)/h->GetBinError(i);
670 if (TMath::Abs(pull)>5){
671 TEllipse* circ = new TEllipse(h->GetXaxis()->GetBinCenter(i), h->GetBinContent(i), r1, r2);
672 circ->SetFillColor(kWhite);
673 circ->SetLineColor(kRed);
674 circ->Draw();
675 } else if (TMath::Abs(pull)>4){
676 TEllipse* circ = new TEllipse(h->GetXaxis()->GetBinCenter(i), h->GetBinContent(i), r1, r2);
677 circ->SetFillColor(kWhite);
678 circ->SetLineColor(kOrange);
679 circ->Draw();
680 } else if (TMath::Abs(pull)>3){
681 TEllipse* circ = new TEllipse(h->GetXaxis()->GetBinCenter(i), h->GetBinContent(i), r1, r2);
682 circ->SetFillColor(kWhite);
683 circ->SetLineColor(kSpring);
684 circ->Draw();
685 }
686 }
687 }
688
689 // draw the average
690 TF1* f = new TF1("average", "[0]", h->GetXaxis()->GetXmin(), h->GetXaxis()->GetXmax());
691 f->SetLineColor(kAzure+1);
692 f->SetLineWidth(1);
693 f->SetParameter(0, av);
694 f->Draw("same");
695
696
697 TF1* fup = new TF1("up", "[0]", h->GetXaxis()->GetXmin(), h->GetXaxis()->GetXmax());
698 TF1* fdown = new TF1("down", "[0]", h->GetXaxis()->GetXmin(), h->GetXaxis()->GetXmax());
699 fup->SetParameter(0, av+err);
700 fdown->SetParameter(0, av-err);
701 fup->SetLineColor(kAzure+1);
702 fdown->SetLineColor(kAzure+1);
703 fup->SetLineWidth(1);
704 fdown->SetLineWidth(1);
705 fup->SetLineStyle(kDashed);
706 fdown->SetLineStyle(kDashed);
707 fup->Draw("same");
708 fdown->Draw("same");
709
710 TLatex* text = new TLatex();
711 text->SetTextFont(42);
712 text->SetNDC();
713 text->SetTextColor(kBlack);
714 text->SetTextSize(0.05);
715 if (bSingleEPS) text->SetTextSize(0.04);
716 text->SetTextAlign(11);
717 TString info = TString::Format("#chi^{2} / ndf");
718 text->DrawLatex(0.5, 0.30, info.Data());
719 info = TString::Format("%3.1f / %d", chi2, bins-1);
720 text->DrawLatex(0.65, 0.30, info.Data());
721 info = TString::Format("average");
722 text->DrawLatex(0.5, 0.23, info.Data());
723 info = TString::Format("%4.1f #pm %4.1f", av, err);
724 text->DrawLatex(0.65, 0.23, info.Data());
725
726 hist->Draw("same");
727
728 return;
729
730 }
731
732
733 void SPlotter::PlotHists(vector<SHist*> hists, int ipad)
734 {
735 // plot all histograms in the array
736
737 if (ipad==1){
738 if (bPlotRatio) m_rp1_top->cd();
739 else m_pad1->cd();
740 }
741 if (ipad==2){
742 if (bPlotRatio) m_rp2_top->cd();
743 else m_pad2->cd();
744 }
745
746 bool isok = SetMinMax(hists);
747 if (isok) SetLogAxes(hists);
748
749 // first get some basic histograms
750 SHist* sstack = SelStack(hists);
751 SHist* sdata = SelData(hists);
752
753 // first, draw data if it exists
754 int ndrawn = 0;
755 if (sdata){
756 sdata->Draw();
757 ++ndrawn;
758 }
759
760 if (debug){
761 if (sdata){
762 cout << "\nHist name = " << sdata->GetName() << " process = " << sdata->GetProcessName() << endl;
763 cout << "hists, entries = " << hists.size() << endl;
764 cout << "Data entries = " << sdata->GetHist()->Integral() << endl;
765 }
766 if (sstack){
767 double stack_entries = 0;
768 TObjArray* arr = sstack->GetStack()->GetStack();
769 TH1* h = (TH1*)arr->At(arr->GetEntries()-1);
770 stack_entries = h->Integral();
771 cout << "Stack entries = " << stack_entries << endl;
772 TList* hists = sstack->GetStack()->GetHists();
773 // calculate individual area
774 for (int i=0; i<hists->GetSize(); ++i){
775 TH1* h = (TH1*) hists->At(i);
776 int iend = h->GetNbinsX();
777 double area = h->Integral(1,iend);
778 cout << " entries of histogram " << i << " in stack = " << area << endl;
779 }
780 }
781 }
782
783 // first round
784 int nh = hists.size();
785
786 for (int i=0; i<nh; ++i){
787 SHist* sh = hists[i];
788 if (sh->IsStack()) continue;
789 if (sh==sdata) continue;
790 if (ndrawn==0) sh->Draw();
791 else sh->Draw("same");
792 ++ndrawn;
793 }
794
795 // now draw the stack
796 if (sstack){
797 if (ndrawn==0){
798 sstack->Draw();
799 need_update = false;
800 } else {
801 sstack->Draw("same");
802 }
803 }
804
805 // second round
806 for (int i=0; i<nh; ++i){
807 SHist* sh = hists[i];
808 if (sh->IsStack()) continue;
809 if (sh==sdata) continue;
810 sh->Draw("same");
811 }
812
813 // draw normalisation error if it is given
814 if (sstack){
815 DrawNormError(sstack);
816 }
817
818 // draw data on top
819 if (sdata) sdata->Draw("same");
820
821 gPad->RedrawAxis();
822
823 }
824
825 void SPlotter::DrawNormError(SHist* stack)
826 {
827 // plot an error band corresponding to the overall
828 // normalisation error
829 TH1* h = (TH1*) stack->GetStack()->GetStack()->At( stack->GetStack()->GetStack()->GetEntries()-1 );
830 TH1* e = (TH1*) h->Clone();
831 for (Int_t i=1; i<e->GetNbinsX()+1; ++i){
832 Double_t sys = 0;
833 if (m_syserr>0) sys = m_syserr*e->GetBinContent(i);
834 Double_t stat = e->GetBinError(i);
835 Double_t norm_err = CalcNormErrorForBin(stack, i);
836 Double_t err = TMath::Sqrt(norm_err*norm_err + sys*sys + stat*stat);
837 e->SetBinError(i, err);
838 }
839 static Int_t LightGray = TColor::GetColor( "#aaaaaa" );
840 //e->SetFillColor(kGray+2);
841 e->SetFillColor(LightGray);
842 e->SetLineWidth(1);
843 e->SetFillStyle(3245);
844 e->Draw("E2 same");
845
846 }
847
848 double SPlotter::CalcNormErrorForBin(SHist* stack, int ibin)
849 {
850 // calculate the normalisation uncertainty of a single bin in the stack
851 // due to normalisation uncertainty on different processes
852
853 double err = 0;
854 for (int i=0; i<stack->GetStack()->GetStack()->GetEntries(); ++i){
855 TH1* h = (TH1*) stack->GetStack()->GetHists()->At(i);
856 err += h->GetBinContent(ibin)*stack->GetUnc(i);
857 }
858 return err;
859 }
860
861 void SPlotter::PlotRatios(vector<SHist*> hists, int ipad)
862 {
863 // plot all histograms in the array
864
865 if (ipad==1) m_rp1->cd();
866 if (ipad==2) m_rp2->cd();
867
868 // calculate ratios
869 vector<SHist*> ratios = CalcRatios(hists);
870
871 gPad->SetLogx(0);
872 gPad->SetLogy(0);
873
874 int ndrawn = 0;
875 int nh = ratios.size();
876 for (int i=0; i<nh; ++i){
877 SHist* rh = ratios[i];
878 TString name = rh->GetName();
879 if (name.Contains("_lx")) gPad->SetLogx(1);
880 if (ndrawn==0) rh->Draw();
881 else rh->Draw("same");
882 ++ndrawn;
883 }
884
885 gPad->RedrawAxis();
886
887 }
888
889 vector<SHist*> SPlotter::CalcRatios(vector<SHist*> hists)
890 {
891 // build ratios from the array 'hists'
892 // by default it is checked if a data histogram exists,
893 // which is then divided by the stack
894 // steerable: which histograms should be calculated for the ratio
895
896 // first get the basic histograms
897 SHist* sstack = SelStack(hists);
898 SHist* sdata = SelData(hists);
899
900 vector<SHist*> ratios;
901
902 // TODO: ratio if neither stack nor data exist
903 if (!sstack || !sdata){
904 return ratios;
905 }
906
907 SHist* rd = (SHist*) sdata->Duplicate();
908 TH1D* rdhist = (TH1D*) rd->GetHist();
909
910 // get the denominator: the last element in the stack is the sum of all
911 TObjArray* arr = sstack->GetStack()->GetStack();
912 TH1D* denom = (TH1D*) arr->At(arr->GetEntries()-1);
913
914 rdhist->Divide(denom);
915 // set the error to display only the error on the data
916 for (Int_t ibin=1;ibin<denom->GetNbinsX()+1; ++ibin){
917 Double_t val = sdata->GetHist()->GetBinContent(ibin);
918 Double_t err = sdata->GetHist()->GetBinError(ibin);
919 Double_t rel_err = err / val;
920 rdhist->SetBinError(ibin, rel_err * rdhist->GetBinContent(ibin) );
921 }
922 rdhist->GetYaxis()->SetTitle(rd->GetProcessName() + " / MC");
923 if (bSingleEPS){
924 SingleEPSRatioCosmetics(rdhist);
925 } else {
926 RatioCosmetics(rdhist);
927 }
928
929 // one histogram for the MC statistical error and one for the total error
930 SHist* mcerr = new SHist(rdhist);
931 mcerr->GetHist()->SetName("MCstat");
932 mcerr->SetProcessName("MCstat");
933 TH1D* MCstat = (TH1D*)mcerr->GetHist();
934
935 SHist* mctot = new SHist(rdhist);
936 mctot->GetHist()->SetName("MCtot");
937 mctot->SetProcessName("MCtot");
938 TH1D* MCtot = (TH1D*)mctot->GetHist();
939
940 for (Int_t ibin=1;ibin<denom->GetNbinsX()+1; ++ibin){
941 Double_t val = denom->GetBinContent(ibin);
942 Double_t err = denom->GetBinError(ibin);
943 MCstat->SetBinContent(ibin, 1.0);
944 MCstat->SetBinError(ibin, err/val);
945
946 Double_t sys = 0;
947 if (m_syserr>0) sys = m_syserr;
948 Double_t norm_err = CalcNormErrorForBin(sstack, ibin)/val;
949 Double_t tot = TMath::Sqrt(norm_err*norm_err + sys*sys + err/val*err/val);
950 MCtot->SetBinContent(ibin, 1.0);
951 MCtot->SetBinError(ibin, tot);
952 }
953
954 //static Int_t VLightGray = TColor::GetColor( "#eeeeee" );
955 static Int_t MLightGray = TColor::GetColor( "#dddddd" );
956 static Int_t LightGray = TColor::GetColor( "#aaaaaa" );
957 //static Int_t Gray = TColor::GetColor( "#888888" );
958
959 MCstat->SetMarkerStyle(0);
960 MCstat->SetMarkerSize(0);
961 MCstat->SetLineColor(LightGray);
962 MCstat->SetFillColor(LightGray);
963
964 MCtot->SetMarkerStyle(0);
965 MCtot->SetMarkerSize(0);
966 MCtot->SetLineColor(MLightGray);
967 MCtot->SetFillColor(MLightGray);
968
969 ratios.push_back(mctot);
970 ratios.push_back(mcerr);
971 ratios.push_back(rd);
972
973 return ratios;
974
975 }
976
977 void SPlotter::DrawLegend(vector<SHist*> hists)
978 {
979 // draw a legend
980
981 int narr = hists.size();
982 float yfrac = 0.06;
983 if (!bPlotRatio) yfrac = 0.05;
984
985 float top = 0.89;
986 if (!bPlotRatio && bDrawLumi) top = 0.86;
987 if (bSingleEPS){
988 top = 0.92;
989 if (bPlotRatio) top = 0.88;
990 if (bDrawLumi) top = 0.84;
991 }
992 float ysize = yfrac*narr;
993 float xleft = 0.7;
994 if (bSingleEPS) xleft = 0.6;
995 float xright = 0.92;
996 if (!bPortrait){
997 top = 0.99;
998 ysize = 0.07*narr;
999 xleft = 0.72;
1000 xright = 0.96;
1001 }
1002
1003 TLegend *leg = new TLegend(xleft,top-ysize,xright,top, NULL,"brNDC");
1004 leg->SetFillColor(0);
1005 leg->SetLineColor(1);
1006 leg->SetBorderSize(0);
1007 leg->SetTextFont(42);
1008 leg->SetFillStyle(0);
1009 if (bSingleEPS) leg->SetTextSize(0.045);
1010
1011 for (Int_t i=0; i<narr; ++i){
1012 SHist* sh = hists[i];
1013 if (sh->IsStack()) continue;
1014
1015 TString legname = TString::Format("leg_entry_%i",i);
1016 TString legtitle = sh->GetLegName();
1017 TLegendEntry* entry = NULL;
1018 int marker = sh->GetHist()->GetMarkerStyle();
1019 int lstyle = sh->GetHist()->GetLineStyle();
1020
1021 if (marker>0){
1022 entry = leg->AddEntry(legname, legtitle, "lp");
1023 entry->SetLineWidth(1);
1024 entry->SetLineColor(sh->GetHist()->GetLineColor());
1025 entry->SetMarkerColor(sh->GetHist()->GetLineColor());
1026 entry->SetMarkerStyle(marker);
1027 entry->SetMarkerSize(1.0);
1028 if (bSingleEPS) entry->SetMarkerSize(0.8);
1029 } else {
1030
1031 if (sh->IsUsedInStack()){
1032 entry = leg->AddEntry(legname, legtitle, "f");
1033 entry->SetLineWidth(1);
1034 entry->SetLineColor(sh->GetHist()->GetLineColor());
1035 entry->SetFillColor(sh->GetHist()->GetLineColor());
1036 entry->SetFillStyle(1001);
1037
1038 } else {
1039 entry = leg->AddEntry(legname, legtitle, "l");
1040 entry->SetLineColor(sh->GetHist()->GetLineColor());
1041 entry->SetMarkerStyle(0);
1042 entry->SetMarkerSize(0);
1043 entry->SetMarkerColor(sh->GetHist()->GetLineColor());
1044 entry->SetLineWidth(2);
1045 entry->SetLineStyle(lstyle);
1046
1047 }
1048 entry->SetTextAlign(12);
1049 //entry->SetTextColor(fSampleColors.At(i));
1050 }
1051 }
1052 leg->Draw();
1053
1054 }
1055
1056
1057 void SPlotter::DrawLumi()
1058 {
1059 TString infotext = TString::Format("CMS Preliminary, %3.1f fb^{-1} at #sqrt{s} = 8 TeV", m_lumi);
1060 TLatex *text1 = new TLatex(3.5, 24, infotext);
1061 text1->SetNDC();
1062 text1->SetTextAlign(13);
1063 text1->SetX(0.22);
1064 text1->SetTextFont(42);
1065 if (bPlotRatio){
1066 text1->SetTextSize(0.06);
1067 text1->SetY(0.89);
1068 } else {
1069 text1->SetTextSize(0.045);
1070 text1->SetY(0.92);
1071 }
1072 text1->Draw();
1073
1074 }
1075
1076 void SPlotter::DoCosmetics(vector<SHist*> hists)
1077 {
1078
1079 // loop over all histograms and make them pretty
1080 int nh = hists.size();
1081 for (int i=0; i<nh; ++i){
1082 SHist* sh = hists[i];
1083 if (sh->IsStack()) continue;
1084 GeneralCosmetics(sh->GetHist());
1085 if (bPortrait) PortraitCosmetics(sh->GetHist());
1086 if (!bPortrait) LandscapeCosmetics(sh->GetHist());
1087 if (bSingleEPS) SingleEPSCosmetics(sh->GetHist());
1088 if (sh->IsYieldPlot()) YieldCosmetics(sh->GetHist());
1089 }
1090
1091 }
1092
1093 SHist* SPlotter::SelStack(vector<SHist*> hists)
1094 {
1095 // select the stack histogram from the array
1096 int narr = hists.size();
1097 SHist* h = NULL;
1098 for (int i=0; i<narr; ++i){
1099 if (hists[i]->IsStack()){
1100 h=hists[i];
1101 break;
1102 }
1103 }
1104 return h;
1105 }
1106
1107 SHist* SPlotter::SelData(vector<SHist*> hists)
1108 {
1109 // select the data histogram from the array
1110 int narr = hists.size();
1111 SHist* h = NULL;
1112 TString process;
1113 for (int i=0; i<narr; ++i){
1114 process = hists[i]->GetProcessName();
1115 if (process.Contains("data", TString::kIgnoreCase)){
1116 h = hists[i];
1117 break;
1118 }
1119 }
1120 return h;
1121 }
1122
1123 bool SPlotter::SetMinMax(vector<SHist*> hists)
1124 {
1125 // set minimum and maximum of all histograms
1126 int narr = hists.size();
1127 TString name = hists[0]->GetName();
1128 double max = 0;
1129 double min = FLT_MAX;
1130 for (int i=0; i<narr; ++i){
1131 if (max<hists[i]->GetMaximum()) max = hists[i]->GetMaximum();
1132 if (min>hists[i]->GetMinimum(1e-6)) min = hists[i]->GetMinimum(1e-6);
1133 double imin = hists[i]->GetMinimum(1e-10);
1134 if (min>imin){
1135 if (imin>1e-10){
1136 min = imin;
1137 }
1138 }
1139 }
1140
1141 bool isok = true;
1142 if (max<1e-6){
1143 isok = false;
1144 return isok;
1145 }
1146
1147 bool islog = false;
1148 double uscale = 1.2;
1149 if (name.Contains("_lxy") || name.Contains("_ly")){
1150 islog = true;
1151 uscale = 12.;
1152 }
1153
1154 for (int i=0; i<narr; ++i){
1155 SHist* h = hists[i];
1156 if (h->IsStack()){
1157 if (!islog){
1158 h->GetStack()->SetMinimum(0.001);
1159 } else {
1160 if (min>1e-10){
1161 if (min<0.1){
1162 h->GetStack()->SetMinimum(0.04);
1163 } else {
1164 h->GetStack()->SetMinimum(min);
1165 }
1166 }
1167 }
1168 h->GetStack()->SetMaximum(uscale*max);
1169 } else {
1170 if (!islog){
1171 h->GetHist()->SetMinimum(0.001);
1172 } else {
1173 if (min>1e-10){
1174 if (min<0.1){
1175 h->GetHist()->SetMinimum(0.04);
1176 } else {
1177 h->GetHist()->SetMinimum(min);
1178 }
1179 }
1180 }
1181 h->GetHist()->SetMaximum(uscale*max);
1182 }
1183 }
1184
1185 return isok;
1186 }
1187
1188 void SPlotter::SetLogAxes(vector<SHist*> hists)
1189 {
1190 // set log axes
1191 TString name = hists[0]->GetName();
1192 gPad->SetLogx(0);
1193 gPad->SetLogy(0);
1194 if (name.Contains("_lxy")){
1195 gPad->SetLogx(1);
1196 gPad->SetLogy(1);
1197 } else if (name.Contains("_lx")){
1198 gPad->SetLogx(1);
1199 } else if (name.Contains("_ly")){
1200 gPad->SetLogy(1);
1201 } else {
1202 // do nothing, all fine
1203 }
1204 return;
1205 }
1206
1207 int SPlotter::GetCurrentPad(int np)
1208 {
1209 // get the current pad, depending on the number of
1210 // already processed plots
1211 int ipad = 1;
1212 int rest = np%2;
1213 if (rest==0) ipad=2;
1214 return ipad;
1215 }
1216
1217 vector<SHist*> SPlotter::GetHistsAtIndex(std::vector<TObjArray*> histarr, int index)
1218 {
1219 // fill an array with histograms at position index.
1220
1221 vector<SHist*> hists;
1222 int narr = histarr.size();
1223 for (int i=0; i<narr; ++i){
1224 SHist* hist = (SHist*)histarr[i]->At(index);
1225 hists.push_back(hist);
1226 }
1227
1228 return hists;
1229
1230 }
1231
1232 vector<SHist*> SPlotter::GetPlottableHists(std::vector<TObjArray*> histarr, int index)
1233 {
1234 // fill an array with plottable histograms at position index.
1235 // if the first histogram in the array should be plotted (DoPlot flag),
1236 // then take at first position in the array
1237 // otherwise look for the stack and plot it first
1238 // only then all other histograms are added
1239
1240 if (debug) cout << "\nSPlotter: Collecting plottable hists for index " << index << endl;
1241 vector<SHist*> hists;
1242 bool gotstack = false;
1243 SHist* hist = (SHist*)histarr[0]->At(index);
1244
1245 // check if the histogram is a 2D or 3D histogram,
1246 // plotting not supported yet, to come
1247 if (hist->GetHist()->InheritsFrom(TH2::Class())){
1248 if (debug) cout << "Hist inherits from TH2, return without adding any to the array " << endl;
1249 return hists;
1250 }
1251
1252 TString name = hist->GetName();
1253 TString process = hist->GetProcessName();
1254 if (process.Contains("data",TString::kIgnoreCase)
1255 && name.Contains("_perlumibin", TString::kIgnoreCase)){
1256 hist->SetIsYieldPlot(true);
1257 hists.push_back(hist);
1258 return hists;
1259 }
1260
1261 if (hist->DoDraw()){ // take first hist
1262 hists.push_back(hist);
1263 gotstack = false;
1264 if (debug) cout << "Adding hist " << hist->GetHist()->GetName()
1265 << " from process " << hist->GetProcessName()
1266 << " and directory " << hist->GetDir() << " to array." << endl;
1267 } else { // try if stack exists
1268 TObjArray* stacks = GetStacks(histarr);
1269 if (stacks){
1270 hist = (SHist*)stacks->At(index);
1271 hists.push_back(hist);
1272 gotstack = true;
1273 if (debug) cout << "Adding stack " << hist->GetStack()->GetName()
1274 << " from process " << hist->GetProcessName()
1275 << " and directory " << hist->GetDir() << " to array." << endl;
1276 }
1277 }
1278
1279 // loop over the rest and add them to the array
1280 int narr = histarr.size();
1281 for (int i=1; i<narr; ++i){
1282
1283 SHist* hist = (SHist*)histarr[i]->At(index);
1284
1285 if (hist->DoDraw()){ // take it if it should be drawn
1286
1287 if (hist->IsStack()){
1288 if (!gotstack){ // take the stack only if not already added
1289 hists.push_back(hist);
1290 if (debug) cout << "Adding stack " << hist->GetStack()->GetName()
1291 << " from process " << hist->GetProcessName()
1292 << " and directory " << hist->GetDir() << " to array." << endl;
1293 }
1294 } else { // take the histogram if it's not the stack hist
1295 hists.push_back(hist);
1296 if (debug) cout << "Adding hist " << hist->GetHist()->GetName()
1297 << " from process " << hist->GetProcessName()
1298 << " and directory " << hist->GetDir() << " to array." << endl;
1299 }
1300 }
1301 }
1302
1303 if (debug) cout << "SPlotter: Done with collecting plottable hists for index "
1304 << index << ", got " << hists.size() << " histograms" << endl;
1305
1306 return hists;
1307
1308 }
1309
1310 void SPlotter::DrawPageNum()
1311 {
1312
1313 m_can->cd();
1314 TPaveText* text;
1315 TString s;
1316 s.Form("%i",m_page);
1317 if (bPortrait){
1318 text = new TPaveText(0.93, 0.00, 0.97, 0.03, "NDC");
1319 } else {
1320 text = new TPaveText(0.03,0.00, 0.06, 0.03, "NDC");
1321 }
1322 text->SetBorderSize(0);
1323 text->SetFillColor(0);
1324 text->AddText(s.Data());
1325 text->Draw("same");
1326
1327 }
1328
1329 void SPlotter::GeneralCosmetics(TH1* hist)
1330 {
1331 // set Y-axis title
1332 hist->GetYaxis()->SetTitle("Events");
1333
1334 // set X-axis title
1335 hist->GetXaxis()->SetTitle(hist->GetTitle());
1336
1337 hist->SetTitle("");
1338
1339 if (bShapeNorm) {
1340 hist->GetYaxis()->SetTitle("#DeltaN/N");
1341 }
1342
1343 hist->GetXaxis()->SetTitleFont(42);
1344 hist->GetXaxis()->SetLabelFont(42);
1345 hist->GetYaxis()->SetTitleFont(42);
1346 hist->GetYaxis()->SetLabelFont(42);
1347
1348 }
1349
1350 void SPlotter::PortraitCosmetics(TH1* hist)
1351 {
1352
1353 // top histogram of the ratio plot
1354 if (bPlotRatio){
1355
1356 // x-axis
1357 hist->GetXaxis()->SetTickLength(0.05);
1358
1359 // y-axis
1360 hist->GetYaxis()->SetTitleSize(0.07);
1361 hist->GetYaxis()->SetLabelSize(0.062);
1362 hist->GetYaxis()->SetLabelOffset(0.01);
1363 hist->GetYaxis()->SetTitleOffset(0.8);
1364 hist->GetYaxis()->SetTickLength(0.02);
1365
1366 // only this histogram
1367 } else {
1368
1369 hist->GetXaxis()->SetLabelSize(0.05);
1370 hist->GetXaxis()->SetLabelOffset(0.008);
1371 hist->GetXaxis()->SetTickLength(0.03);
1372 hist->GetXaxis()->SetTitleSize(0.05);
1373 hist->GetXaxis()->SetTitleOffset(1.2);
1374
1375 hist->GetYaxis()->SetTitleOffset(1.2);
1376 hist->GetYaxis()->SetTitleSize(0.06);
1377 hist->GetYaxis()->SetLabelSize(0.045);
1378 hist->GetYaxis()->SetTickLength(0.02);
1379 hist->GetYaxis()->SetLabelOffset(0.011);
1380
1381 }
1382
1383 }
1384
1385 void SPlotter::SingleEPSCosmetics(TH1* hist)
1386 {
1387
1388 // top histogram of the ratio plot
1389 if (bPlotRatio){
1390
1391 // x-axis
1392 hist->GetXaxis()->SetTickLength(0.05);
1393
1394 // y-axis
1395 hist->GetYaxis()->SetTitleSize(0.07);
1396 hist->GetYaxis()->SetLabelSize(0.062);
1397 hist->GetYaxis()->SetLabelOffset(0.01);
1398 hist->GetYaxis()->SetTitleOffset(1.15);
1399 hist->GetYaxis()->SetTickLength(0.02);
1400
1401 // only this histogram
1402 } else {
1403
1404 hist->GetXaxis()->SetLabelSize(0.05);
1405 hist->GetXaxis()->SetLabelOffset(0.008);
1406 hist->GetXaxis()->SetTickLength(0.03);
1407 hist->GetXaxis()->SetTitleSize(0.05);
1408 hist->GetXaxis()->SetTitleOffset(1.2);
1409
1410 hist->GetYaxis()->SetTitleOffset(1.8);
1411 hist->GetYaxis()->SetTitleSize(0.05);
1412 hist->GetYaxis()->SetLabelSize(0.045);
1413 hist->GetYaxis()->SetTickLength(0.02);
1414 hist->GetYaxis()->SetLabelOffset(0.011);
1415
1416 }
1417
1418 }
1419
1420 void SPlotter::SingleEPSRatioCosmetics(TH1* hist)
1421 {
1422
1423 //hist->GetYaxis()->SetRangeUser(0.3, 1.7);
1424 hist->GetYaxis()->SetRangeUser(0.05, 1.95);
1425 hist->SetMarkerSize(0.7);
1426
1427 // cosmetics for portrait mode
1428 if (bPortrait){
1429 hist->SetTitle("");
1430
1431 // x-axis
1432 hist->GetXaxis()->SetLabelSize(0.12);
1433 hist->GetXaxis()->SetTickLength(0.08);
1434 hist->GetXaxis()->SetTitleSize(0.12);
1435 hist->GetXaxis()->SetTitleOffset(1.25);
1436
1437 // y-axis
1438 hist->GetYaxis()->CenterTitle();
1439 hist->GetYaxis()->SetTitleSize(0.12);
1440 hist->GetYaxis()->SetTitleOffset(0.66);
1441 hist->GetYaxis()->SetLabelSize(0.11);
1442 //hist->GetYaxis()->SetNdivisions(210);
1443 hist->GetYaxis()->SetNdivisions(505);
1444 hist->GetYaxis()->SetTickLength(0.02);
1445 hist->GetYaxis()->SetLabelOffset(0.011);
1446
1447 // cosmetics for landscape mode
1448 } else {
1449
1450 hist->SetTitle("");
1451 hist->SetTitleOffset(1.1, "X");
1452 hist->SetTitleOffset(0.5, "Y");
1453 hist->SetLabelOffset(0.02, "X");
1454 hist->SetLabelOffset(0.01, "Y");
1455
1456 hist->GetXaxis()->SetLabelSize(0.14);
1457 hist->GetXaxis()->SetTickLength(0.07);
1458 hist->GetXaxis()->SetTitleSize(0.15);
1459
1460 hist->GetYaxis()->CenterTitle();
1461 hist->GetYaxis()->SetTitleSize(0.11);
1462 hist->GetYaxis()->SetLabelSize(0.12);
1463 hist->GetYaxis()->SetNdivisions(505);
1464 hist->GetYaxis()->SetTickLength(0.03);
1465
1466 }
1467
1468 }
1469
1470
1471 void SPlotter::YieldCosmetics(TH1* hist)
1472 {
1473 // cosmetics for the lumi yield histogram
1474 hist->GetXaxis()->SetLabelSize(0.05);
1475 hist->GetXaxis()->SetLabelOffset(0.008);
1476 hist->GetXaxis()->SetTickLength(0.03);
1477 hist->GetXaxis()->SetTitleSize(0.05);
1478 hist->GetXaxis()->SetTitleOffset(1.2);
1479
1480 hist->GetYaxis()->SetTitleOffset(1.2);
1481 hist->GetYaxis()->SetTitleSize(0.06);
1482 hist->GetYaxis()->SetLabelSize(0.045);
1483 hist->GetYaxis()->SetTickLength(0.02);
1484 hist->GetYaxis()->SetLabelOffset(0.011);
1485
1486 if (bSingleEPS){
1487 hist->GetYaxis()->SetTitleOffset(1.8);
1488 hist->GetYaxis()->SetTitleSize(0.055);
1489 hist->GetYaxis()->SetLabelSize(0.05);
1490 hist->GetYaxis()->SetTickLength(0.02);
1491 hist->GetYaxis()->SetLabelOffset(0.011);
1492 }
1493
1494 hist->GetXaxis()->SetTitle("integrated luminosity [fb^{-1}]");
1495 double dlum = hist->GetXaxis()->GetBinWidth(1);
1496 TString xtit = TString::Format("events per %3.1f fb^{-1}", dlum);
1497 hist->GetYaxis()->SetTitle(xtit);
1498 }
1499
1500
1501
1502 void SPlotter::LandscapeCosmetics(TH1* hist)
1503 {
1504
1505
1506
1507 }
1508
1509 void SPlotter::RatioCosmetics(TH1* hist)
1510 {
1511
1512 //hist->GetYaxis()->SetRangeUser(0.3, 1.7);
1513 hist->GetYaxis()->SetRangeUser(0.05, 1.95);
1514 hist->SetMarkerSize(0.7);
1515
1516 // cosmetics for portrait mode
1517 if (bPortrait){
1518 hist->SetTitle("");
1519
1520 // x-axis
1521 hist->GetXaxis()->SetLabelSize(0.12);
1522 hist->GetXaxis()->SetTickLength(0.08);
1523 hist->GetXaxis()->SetTitleSize(0.12);
1524 hist->GetXaxis()->SetTitleOffset(1.25);
1525
1526 // y-axis
1527 hist->GetYaxis()->CenterTitle();
1528 hist->GetYaxis()->SetTitleSize(0.12);
1529 hist->GetYaxis()->SetTitleOffset(0.46);
1530 hist->GetYaxis()->SetLabelSize(0.11);
1531 //hist->GetYaxis()->SetNdivisions(210);
1532 hist->GetYaxis()->SetNdivisions(505);
1533 hist->GetYaxis()->SetTickLength(0.02);
1534 hist->GetYaxis()->SetLabelOffset(0.011);
1535
1536 // cosmetics for landscape mode
1537 } else {
1538
1539 hist->SetTitle("");
1540 hist->SetTitleOffset(1.1, "X");
1541 hist->SetTitleOffset(0.5, "Y");
1542 hist->SetLabelOffset(0.02, "X");
1543 hist->SetLabelOffset(0.01, "Y");
1544
1545 hist->GetXaxis()->SetLabelSize(0.14);
1546 hist->GetXaxis()->SetTickLength(0.07);
1547 hist->GetXaxis()->SetTitleSize(0.15);
1548
1549 hist->GetYaxis()->CenterTitle();
1550 hist->GetYaxis()->SetTitleSize(0.11);
1551 hist->GetYaxis()->SetLabelSize(0.12);
1552 hist->GetYaxis()->SetNdivisions(505);
1553 hist->GetYaxis()->SetTickLength(0.03);
1554
1555 }
1556
1557 }
1558
1559 void SPlotter::ShapeNormalise(std::vector<SHist*> hists)
1560 {
1561 for (unsigned int i=0; i<hists.size(); ++i){
1562 hists[i]->NormaliseToArea();
1563 }
1564 }
1565