source: trunk/MagicSoft/Mars/mhbase/MH.cc@ 9150

Last change on this file since 9150 was 8957, checked in by tbretz, 16 years ago
*** empty log message ***
File size: 47.6 KB
Line 
1/* ======================================================================== *\
2! $Name: not supported by cvs2svn $:$Id: MH.cc,v 1.39 2008-06-14 15:55:52 tbretz Exp $
3! --------------------------------------------------------------------------
4!
5! *
6! * This file is part of MARS, the MAGIC Analysis and Reconstruction
7! * Software. It is distributed to you in the hope that it can be a useful
8! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
9! * It is distributed WITHOUT ANY WARRANTY.
10! *
11! * Permission to use, copy, modify and distribute this software and its
12! * documentation for any purpose is hereby granted without fee,
13! * provided that the above copyright notice appear in all copies and
14! * that both that copyright notice and this permission notice appear
15! * in supporting documentation. It is provided "as is" without express
16! * or implied warranty.
17! *
18!
19!
20! Author(s): Thomas Bretz 07/2001 <mailto:tbretz@astro.uni-wuerzburg.de>
21!
22! Copyright: MAGIC Software Development, 2000-2008
23!
24!
25\* ======================================================================== */
26
27//////////////////////////////////////////////////////////////////////////////
28// //
29// MH //
30// //
31// This is a base tasks for mars histograms. It defines a common interface //
32// for filling the histograms with events (MH::Fill) which is used by a //
33// common 'filler' And a SetupFill member function which may be used //
34// by MFillH. The idea is: //
35// 1) If your Histogram can become filled by one single container //
36// (like MHHillas) you overload MH::Fill and it gets called with //
37// a pointer to the container with which it should be filled. //
38// //
39// 2) You histogram needs several containers to get filled. Than you //
40// have to overload MH::SetupFill and get the necessary objects from //
41// the parameter list. Use this objects in Fill to fill your //
42// histogram. //
43// //
44// If you want to create your own histogram class the new class must be //
45// derived from MH (instead of the base MParContainer) and you must //
46// the fill function of MH. This is the function which is called to fill //
47// the histogram(s) by the data of a corresponding parameter container. //
48// //
49// Remark: the static member function (eg MakeDefCanvas) can be called //
50// from everywhere using: MH::MakeDefCanvas(...) //
51// //
52//////////////////////////////////////////////////////////////////////////////
53
54#include "MH.h"
55
56#include <TH1.h>
57#include <TH2.h>
58#include <TH3.h>
59#include <TColor.h>
60#include <TMath.h>
61#include <TClass.h>
62#include <TStyle.h> // TStyle::GetScreenFactor
63#include <TGaxis.h>
64#include <TCanvas.h>
65#include <TLegend.h>
66#include <TPaveStats.h>
67#include <TBaseClass.h>
68#include <THashList.h>
69#if ROOT_VERSION_CODE > ROOT_VERSION(3,04,01)
70#include <THLimitsFinder.h>
71#endif
72
73#include "MLog.h"
74#include "MLogManip.h"
75
76#include "MParList.h"
77#include "MParContainer.h"
78
79#include "MBinning.h"
80
81#include "MArrayD.h"
82#include "MArrayF.h"
83
84ClassImp(MH);
85
86using namespace std;
87
88// --------------------------------------------------------------------------
89//
90// Default Constructor. It sets name and title only. Typically you won't
91// need to change this.
92//
93MH::MH(const char *name, const char *title)
94 : fSerialNumber(0), fNumExecutions(0)
95
96{
97 //
98 // set the name and title of this object
99 //
100 fName = name ? name : "MH";
101 fTitle = title ? title : "Base class for Mars histograms";
102}
103
104// --------------------------------------------------------------------------
105//
106// If you want to use the automatic filling of your derived class you
107// must overload this function. If it is not overloaded you cannot use
108// FillH with this class. The argument is a pointer to a container
109// in your paremeter list which is specified in the MFillH constructor.
110// If you are not going to use it you should at least add
111// Bool_t MH::Fill(const MParContainer *) { return kTRUE; }
112// to your class definition.
113//
114Bool_t MH::Fill(const MParContainer *par, const Stat_t w)
115{
116 *fLog << warn << GetDescriptor() << ": Fill not overloaded! Can't be used!" << endl;
117 return kFALSE;
118}
119
120// --------------------------------------------------------------------------
121//
122// This virtual function is ment as a generalized interface to retrieve
123// a pointer to a root histogram from the MH-derived class.
124//
125TH1 *MH::GetHistByName(const TString name) const
126{
127 *fLog << warn << GetDescriptor() << ": GetHistByName not overloaded! Can't be used!" << endl;
128 return NULL;
129}
130
131// --------------------------------------------------------------------------
132//
133// This is a function which should replace the creation of default
134// canvases like root does. Because this is inconvinient in some aspects.
135// need to change this.
136// You can specify a name for the default canvas and a title. Also
137// width and height can be given.
138// MakeDefCanvas looks for a canvas with the given name. If now name is
139// given the DefCanvasName of root is used. If no such canvas is existing
140// it is created and returned. If such a canvas already exists a new canvas
141// with a name plus anumber is created (the number is calculated by the
142// number of all existing canvases plus one)
143//
144// Normally the canvas size is scaled with gStyle->GetScreenFactor() so
145// that on all screens it looks like the same part of the screen.
146// To suppress this scaling use usescreenfactor=kFALSE. In this case
147// you specify directly the size of the embedded pad.
148//
149TCanvas *MH::MakeDefCanvas(TString name, const char *title,
150 UInt_t w, UInt_t h, Bool_t usescreenfactor)
151{
152 const TList *list = (TList*)gROOT->GetListOfCanvases();
153
154 if (name.IsNull())
155 name = gROOT->GetDefCanvasName();
156
157 if (list->FindObject(name))
158 name += Form(" <%d>", list->GetSize()+1);
159
160 if (!usescreenfactor)
161 {
162 const Float_t cx = gStyle->GetScreenFactor();
163 w += 4;
164 h += 28;
165 w = (int)(w/cx+1);
166 h = (int)(h/cx+1);
167 }
168
169 return new TCanvas(name, title, w, h);
170}
171
172// --------------------------------------------------------------------------
173//
174// This function works like MakeDefCanvas(name, title, w, h) but name
175// and title are retrieved from the given TObject.
176//
177// Normally the canvas size is scaled with gStyle->GetScreenFactor() so
178// that on all screens it looks like the same part of the screen.
179// To suppress this scaling use usescreenfactor=kFALSE. In this case
180// you specify directly the size of the embedded pad.
181//
182TCanvas *MH::MakeDefCanvas(const TObject *obj,
183 UInt_t w, UInt_t h, Bool_t usescreenfactor)
184{
185 if (!usescreenfactor)
186 {
187 const Float_t cx = gStyle->GetScreenFactor();
188 w += 4;
189 h += 28;
190 h = (int)(h/cx+1);
191 w = (int)(w/cx+1);
192 }
193
194 return MakeDefCanvas(obj->GetName(), obj->GetTitle(), w, h);
195}
196
197// --------------------------------------------------------------------------
198//
199// Search in gPad for all objects with the name name and remove all of them
200// (TList::Remove)
201//
202void MH::RemoveFromPad(const char *name)
203{
204 if (!gPad)
205 return;
206
207 TList *list = gPad->GetListOfPrimitives();
208 if (!list)
209 return;
210
211 TObject *obj = 0;
212 while ((obj = gPad->FindObject(name)))
213 list->Remove(obj);
214}
215
216// --------------------------------------------------------------------------
217//
218// If labels are set for this axis the correct MBinning corresponding
219// to the existing label range is returned (this is necessary to
220// maintain the correct number of bins in the histogram)
221// otherwise the given binning is returned.
222//
223MBinning MH::GetBinningForLabels(TAxis &x, const MBinning *bins)
224{
225 if (!x.GetLabels())
226 return *bins;
227
228 const Int_t n = TMath::Max(x.GetLabels()->GetEntries(), 1);
229 return MBinning(n, 0, n);
230}
231
232// --------------------------------------------------------------------------
233//
234// If Labels are set this function deletes the fXbins Array from
235// the axis (which makes the axis a variable bin-size axis)
236// and sets the Nbins, Xmin and Xmax according to the number of labels.
237//
238void MH::RestoreBinningForLabels(TAxis &x)
239{
240 if (!x.GetLabels())
241 return;
242
243 const Int_t n = TMath::Max(x.GetLabels()->GetEntries(), 1);
244 x.Set(n, 0, n);
245
246 const_cast<TArrayD*>(x.GetXbins())->Set(0);
247}
248
249// --------------------------------------------------------------------------
250//
251// Applies a given binning to a 1D-histogram. In case the axis has labels
252// (e.g. GetXaxis()->GetLabels()) the binning is set according to the
253// labels.
254//
255void MH::SetBinning(TH1 *h, const MBinning *binsx)
256{
257 //
258 // Another strange behaviour: TAxis::Set deletes the axis title!
259 //
260 TAxis &x = *h->GetXaxis();
261
262#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
263 TString xtitle = x.GetTitle();
264#endif
265
266#if ROOT_VERSION_CODE < ROOT_VERSION(5,12,00)
267 // All this is reset by TAxis::Set
268 const TAttAxis att(x);
269 const Bool_t tm(x.GetTimeDisplay());
270 const TString tf(x.GetTimeFormat());
271
272 //
273 // This is a necessary workaround if one wants to set
274 // non-equidistant bins after the initialization
275 // TH1D::fNcells must be set correctly.
276 //
277 h->SetBins(binsx->GetNumBins(), 0, 1);
278
279 //
280 // Set the binning of the current histogram to the binning
281 // in one of the two given histograms
282 //
283 x.Set(binsx->GetNumBins(), binsx->GetEdges());
284
285 // All this is reset by TAxis::Set
286 att.Copy(x);
287 x.SetTimeDisplay(tm);
288 x.SetTimeFormat(tf);
289#else
290 if (!x.GetLabels())
291 h->SetBins(binsx->GetNumBins(), binsx->GetEdges());
292#endif
293
294
295#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
296 x.SetTitle(xtitle);
297#endif
298}
299
300// --------------------------------------------------------------------------
301//
302// Applies given binnings to the two axis of a 2D-histogram.
303// In case the axis has labels (e.g. GetXaxis()->GetLabels())
304// the binning is set according to the labels.
305//
306void MH::SetBinning(TH2 *h, const MBinning *binsx, const MBinning *binsy)
307{
308 TAxis &x = *h->GetXaxis();
309 TAxis &y = *h->GetYaxis();
310
311 const MBinning bx(GetBinningForLabels(x, binsx));
312 const MBinning by(GetBinningForLabels(y, binsy));
313
314 //
315 // Another strange behaviour: TAxis::Set deletes the axis title!
316 //
317#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
318 TString xtitle = x.GetTitle();
319 TString ytitle = y.GetTitle();
320#endif
321
322#if ROOT_VERSION_CODE < ROOT_VERSION(5,12,00)
323 // All this is reset by TAxis::Set
324 const TAttAxis attx(x);
325 const TAttAxis atty(y);
326 const Bool_t tmx(x.GetTimeDisplay());
327 const Bool_t tmy(y.GetTimeDisplay());
328 const TString tfx(x.GetTimeFormat());
329 const TString tfy(y.GetTimeFormat());
330
331 //
332 // This is a necessary workaround if one wants to set
333 // non-equidistant bins after the initialization
334 // TH1D::fNcells must be set correctly.
335 //
336 h->SetBins(bx.GetNumBins(), 0, 1,
337 by.GetNumBins(), 0, 1);
338
339 //
340 // Set the binning of the current histogram to the binning
341 // in one of the two given histograms
342 //
343 x.Set(bx.GetNumBins(), bx.GetEdges());
344 y.Set(by.GetNumBins(), by.GetEdges());
345
346 // All this is reset by TAxis::Set
347 attx.Copy(x);
348 atty.Copy(y);
349 x.SetTimeDisplay(tmx);
350 y.SetTimeDisplay(tmy);
351 x.SetTimeFormat(tfx);
352 y.SetTimeFormat(tfy);
353#else
354 h->SetBins(bx.GetNumBins(), bx.GetEdges(),
355 by.GetNumBins(), by.GetEdges());
356#endif
357
358 RestoreBinningForLabels(x);
359 RestoreBinningForLabels(y);
360
361#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
362 x.SetTitle(xtitle);
363 y.SetTitle(ytitle);
364#endif
365}
366
367// --------------------------------------------------------------------------
368//
369// Applies given binnings to the three axis of a 3D-histogram
370// In case the axis has labels (e.g. GetXaxis()->GetLabels())
371// the binning is set according to the labels.
372//
373void MH::SetBinning(TH3 *h, const MBinning *binsx, const MBinning *binsy, const MBinning *binsz)
374{
375 //
376 // Another strange behaviour: TAxis::Set deletes the axis title!
377 //
378 TAxis &x = *h->GetXaxis();
379 TAxis &y = *h->GetYaxis();
380 TAxis &z = *h->GetZaxis();
381
382 const MBinning bx(GetBinningForLabels(x, binsx));
383 const MBinning by(GetBinningForLabels(y, binsy));
384 const MBinning bz(GetBinningForLabels(z, binsz));
385
386#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
387 TString xtitle = x.GetTitle();
388 TString ytitle = y.GetTitle();
389 TString ztitle = z.GetTitle();
390#endif
391
392#if ROOT_VERSION_CODE < ROOT_VERSION(5,12,00)
393 // All this is reset by TAxis::Set
394 const TAttAxis attx(x);
395 const TAttAxis atty(y);
396 const TAttAxis attz(z);
397 const Bool_t tmx(x.GetTimeDisplay());
398 const Bool_t tmy(y.GetTimeDisplay());
399 const Bool_t tmz(z.GetTimeDisplay());
400 const TString tfx(x.GetTimeFormat());
401 const TString tfy(y.GetTimeFormat());
402 const TString tfz(z.GetTimeFormat());
403#endif
404
405 //
406 // This is a necessary workaround if one wants to set
407 // non-equidistant bins after the initialization
408 // TH1D::fNcells must be set correctly.
409 //
410 h->SetBins(bx.GetNumBins(), 0, 1,
411 by.GetNumBins(), 0, 1,
412 bz.GetNumBins(), 0, 1);
413
414 //
415 // Set the binning of the current histogram to the binning
416 // in one of the two given histograms
417 //
418 x.Set(bx.GetNumBins(), bx.GetEdges());
419 y.Set(by.GetNumBins(), by.GetEdges());
420 z.Set(bz.GetNumBins(), bz.GetEdges());
421
422 RestoreBinningForLabels(x);
423 RestoreBinningForLabels(y);
424 RestoreBinningForLabels(z);
425
426#if ROOT_VERSION_CODE < ROOT_VERSION(5,12,00)
427 // All this is reset by TAxis::Set
428 attx.Copy(x);
429 atty.Copy(y);
430 attz.Copy(z);
431 x.SetTimeDisplay(tmx);
432 y.SetTimeDisplay(tmy);
433 z.SetTimeDisplay(tmz);
434 x.SetTimeFormat(tfx);
435 y.SetTimeFormat(tfy);
436 z.SetTimeFormat(tfz);
437#endif
438
439#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
440 x.SetTitle(xtitle);
441 y.SetTitle(ytitle);
442 z.SetTitle(ztitle);
443#endif
444}
445
446// --------------------------------------------------------------------------
447//
448// Applies given binning (the n+1 edges) to the axis of a 1D-histogram
449//
450void MH::SetBinning(TH1 *h, const TArrayD &binsx)
451{
452 MBinning bx;
453 bx.SetEdges(binsx);
454 SetBinning(h, &bx);
455}
456
457// --------------------------------------------------------------------------
458//
459// Applies given binning (the n+1 edges) to the two axis of a
460// 2D-histogram
461//
462void MH::SetBinning(TH2 *h, const TArrayD &binsx, const TArrayD &binsy)
463{
464 MBinning bx;
465 MBinning by;
466 bx.SetEdges(binsx);
467 by.SetEdges(binsy);
468 SetBinning(h, &bx, &by);
469}
470
471// --------------------------------------------------------------------------
472//
473// Applies given binning (the n+1 edges) to the three axis of a
474// 3D-histogram
475//
476void MH::SetBinning(TH3 *h, const TArrayD &binsx, const TArrayD &binsy, const TArrayD &binsz)
477{
478 MBinning bx;
479 MBinning by;
480 MBinning bz;
481 bx.SetEdges(binsx);
482 by.SetEdges(binsy);
483 bz.SetEdges(binsz);
484 SetBinning(h, &bx, &by, &bz);
485}
486
487// --------------------------------------------------------------------------
488//
489// Applies the binning of a TAxis (eg from a root histogram) to the axis
490// of a 1D-histogram
491//
492void MH::SetBinning(TH1 *h, const TAxis *binsx)
493{
494 const Int_t nx = binsx->GetNbins();
495
496 TArrayD bx(nx+1);
497 for (int i=0; i<nx; i++) bx[i] = binsx->GetBinLowEdge(i+1);
498 bx[nx] = binsx->GetXmax();
499
500 SetBinning(h, bx);
501}
502
503// --------------------------------------------------------------------------
504//
505// Applies the binnings of the TAxis' (eg from a root histogram) to the
506// two axis' of a 2D-histogram
507//
508void MH::SetBinning(TH2 *h, const TAxis *binsx, const TAxis *binsy)
509{
510 const Int_t nx = binsx->GetNbins();
511 const Int_t ny = binsy->GetNbins();
512
513 TArrayD bx(nx+1);
514 TArrayD by(ny+1);
515 for (int i=0; i<nx; i++) bx[i] = binsx->GetBinLowEdge(i+1);
516 for (int i=0; i<ny; i++) by[i] = binsy->GetBinLowEdge(i+1);
517 bx[nx] = binsx->GetXmax();
518 by[ny] = binsy->GetXmax();
519
520 SetBinning(h, bx, by);
521}
522
523// --------------------------------------------------------------------------
524//
525// Applies the binnings of the TAxis' (eg from a root histogram) to the
526// three axis' of a 3D-histogram
527//
528void MH::SetBinning(TH3 *h, const TAxis *binsx, const TAxis *binsy, const TAxis *binsz)
529{
530 const Int_t nx = binsx->GetNbins();
531 const Int_t ny = binsy->GetNbins();
532 const Int_t nz = binsz->GetNbins();
533
534 TArrayD bx(nx+1);
535 TArrayD by(ny+1);
536 TArrayD bz(nz+1);
537 for (int i=0; i<nx; i++) bx[i] = binsx->GetBinLowEdge(i+1);
538 for (int i=0; i<ny; i++) by[i] = binsy->GetBinLowEdge(i+1);
539 for (int i=0; i<nz; i++) bz[i] = binsz->GetBinLowEdge(i+1);
540 bx[nx] = binsx->GetXmax();
541 by[ny] = binsy->GetXmax();
542 bz[nz] = binsz->GetXmax();
543
544 SetBinning(h, bx, by, bz);
545}
546
547// --------------------------------------------------------------------------
548//
549// Applies the binnings of one root-histogram x to another one h
550// Both histograms must be of the same type: TH1, TH2 or TH3
551//
552void MH::SetBinning(TH1 *h, const TH1 *x)
553{
554 if (h->InheritsFrom(TH3::Class()) && x->InheritsFrom(TH3::Class()))
555 {
556 SetBinning((TH3*)h, x->GetXaxis(), x->GetYaxis(), x->GetZaxis());
557 return;
558 }
559 if (h->InheritsFrom(TH3::Class()) || x->InheritsFrom(TH3::Class()))
560 return;
561 if (h->InheritsFrom(TH2::Class()) && x->InheritsFrom(TH2::Class()))
562 {
563 SetBinning((TH2*)h, x->GetXaxis(), x->GetYaxis());
564 return;
565 }
566 if (h->InheritsFrom(TH2::Class()) || x->InheritsFrom(TH2::Class()))
567 return;
568 if (h->InheritsFrom(TH1::Class()) && x->InheritsFrom(TH1::Class()))
569 {
570 SetBinning(h, x->GetXaxis());
571 return;
572 }
573}
574
575void MH::RemoveFirstBin(TH1 &h)
576{
577 if (h.InheritsFrom(TH2::Class()) || h.InheritsFrom(TH3::Class()))
578 return;
579
580 const Bool_t haserr = h.GetSumw2N()>0;
581
582 const Int_t n0 = h.GetNbinsX();
583 if (n0<2)
584 return;
585
586 TArrayD val(n0-1);
587 TArrayD er(haserr ? n0-1 : 0);
588 for (int i=1; i<n0; i++)
589 {
590 val[i-1] = h.GetBinContent(i+1);
591 if (haserr)
592 er[i-1] = h.GetBinError(i+1);
593 }
594
595 MBinning bins;
596 bins.SetEdges(h, 'x');
597 bins.RemoveFirstEdge();
598 bins.Apply(h);
599
600 h.Reset();
601
602 for (int i=1; i<n0; i++)
603 {
604 h.SetBinContent(i, val[i-1]);
605 if (haserr)
606 h.SetBinError(i, er[i-1]);
607 }
608}
609
610// --------------------------------------------------------------------------
611//
612// Multiplies all entries in a TArrayD by a float f
613//
614void MH::ScaleArray(TArrayD &bins, Double_t f)
615{
616 for (int i=0; i<bins.GetSize(); i++)
617 bins[i] *= f;
618}
619
620// --------------------------------------------------------------------------
621//
622// Scales the binning of a TAxis by a float f
623//
624TArrayD MH::ScaleAxis(TAxis &axe, Double_t f)
625{
626 TArrayD arr(axe.GetNbins()+1);
627
628 for (int i=1; i<=axe.GetNbins()+1; i++)
629 arr[i-1] = axe.GetBinLowEdge(i);
630
631 ScaleArray(arr, f);
632
633 return arr;
634}
635
636// --------------------------------------------------------------------------
637//
638// Scales the binning of one, two or three axis of a histogram by a float f
639//
640void MH::ScaleAxis(TH1 *h, Double_t fx, Double_t fy, Double_t fz)
641{
642 if (h->InheritsFrom(TH3::Class()))
643 {
644 SetBinning((TH3*)h,
645 ScaleAxis(*h->GetXaxis(), fx),
646 ScaleAxis(*h->GetYaxis(), fy),
647 ScaleAxis(*h->GetZaxis(), fz));
648 return;
649 }
650
651 if (h->InheritsFrom(TH2::Class()))
652 {
653 SetBinning((TH2*)h,
654 ScaleAxis(*h->GetXaxis(), fx),
655 ScaleAxis(*h->GetYaxis(), fy));
656 return;
657 }
658
659 if (h->InheritsFrom(TH1::Class()))
660 SetBinning(h, ScaleAxis(*h->GetXaxis(), fx));
661}
662
663// --------------------------------------------------------------------------
664//
665// Tries to find a MBinning container with the name "Binning"+name
666// in the given parameter list. If it was found it is applied to the
667// given histogram. This is only valid for 1D-histograms.
668// If the binning is found, but it IsDefault() kTRUE is returned, but
669// no binning is applied.
670//
671Bool_t MH::ApplyBinning(const MParList &plist, TString name, TH1 *h)
672{
673 if (h->InheritsFrom(TH2::Class()) || h->InheritsFrom(TH3::Class()))
674 {
675 gLog << warn << "MH::ApplyBinning: '" << h->GetName() << "' is not a basic TH1 object... no binning applied." << endl;
676 return kFALSE;
677 }
678
679 const MBinning *bins = (MBinning*)plist.FindObject("Binning"+name);
680 if (!bins)
681 {
682 gLog << inf << "Object 'Binning" << name << "' [MBinning] not found... no binning applied." << endl;
683 return kFALSE;
684 }
685
686 if (bins->IsDefault())
687 return kTRUE;
688
689 SetBinning(h, bins);
690 return kTRUE;
691}
692
693Bool_t MH::ApplyBinning(const MParList &plist, TString x, TString y, TH2 *h)
694{
695 const MBinning *binsx = (MBinning*)plist.FindObject("Binning"+x);
696 if (!binsx)
697 {
698 gLog << inf << "Object 'Binning" << x << "' [MBinning] not found... no binning applied." << endl;
699 return kFALSE;
700 }
701 const MBinning *binsy = (MBinning*)plist.FindObject("Binning"+y);
702 if (!binsy)
703 {
704 gLog << inf << "Object 'Binning" << y << "' [MBinning] not found... no binning applied." << endl;
705 return kFALSE;
706 }
707
708 if (binsx->IsDefault() && binsy->IsDefault())
709 return kTRUE;
710
711 // -------------------------
712 /*
713 MBinning binsx, binsy, binsz;
714 binsx.SetEdges(fHist, 'x');
715 binsy.SetEdges(fHist, 'y');
716 binsz.SetEdges(fHist, 'z');
717 */
718 // -------------------------
719
720 SetBinning(h, binsx, binsy);
721
722 return kTRUE;
723}
724
725Bool_t MH::ApplyBinning(const MParList &plist, TString x, TString y, TString z, TH3 *h)
726{
727 const MBinning *binsx = (MBinning*)plist.FindObject("Binning"+x);
728 if (!binsx)
729 {
730 gLog << inf << "Object 'Binning" << x << "' [MBinning] not found... no binning applied." << endl;
731 return kFALSE;
732 }
733 const MBinning *binsy = (MBinning*)plist.FindObject("Binning"+y);
734 if (!binsy)
735 {
736 gLog << inf << "Object 'Binning" << y << "' [MBinning] not found... no binning applied." << endl;
737 return kFALSE;
738 }
739 const MBinning *binsz = (MBinning*)plist.FindObject("Binning"+z);
740 if (!binsz)
741 {
742 gLog << inf << "Object 'Binning" << z << "' [MBinning] not found... no binning applied." << endl;
743 return kFALSE;
744 }
745
746 if (binsx->IsDefault() && binsy->IsDefault() && binsz->IsDefault())
747 return kTRUE;
748
749 SetBinning(h, binsx, binsy, binsz);
750 return kTRUE;
751}
752
753void MH::FindGoodLimits(Int_t nbins, Int_t &newbins, Double_t &xmin, Double_t &xmax, Bool_t isInteger)
754{
755#if ROOT_VERSION_CODE > ROOT_VERSION(3,04,01)
756 THLimitsFinder::OptimizeLimits(nbins, newbins, xmin, xmax, isInteger);
757#else
758//*-*-*-*-*-*-*-*-*Find reasonable bin values*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
759//*-* ==========================
760
761 Double_t dx = 0.1*(xmax-xmin);
762 Double_t umin = xmin - dx;
763 Double_t umax = xmax + dx;
764
765 if (umin < 0 && xmin >= 0)
766 umin = 0;
767
768 if (umax > 0 && xmax <= 0)
769 umax = 0;
770
771 Double_t binlow =0;
772 Double_t binhigh =0;
773 Double_t binwidth=0;
774
775 TGaxis::Optimize(umin, umax, nbins, binlow, binhigh, nbins, binwidth, "");
776
777 if (binwidth <= 0 || binwidth > 1.e+39)
778 {
779 xmin = -1;
780 xmax = 1;
781 }
782 else
783 {
784 xmin = binlow;
785 xmax = binhigh;
786 }
787
788 if (isInteger)
789 {
790 Int_t ixmin = (Int_t)xmin;
791 Int_t ixmax = (Int_t)xmax;
792 Double_t dxmin = (Double_t)ixmin;
793 Double_t dxmax = (Double_t)ixmax;
794
795 xmin = xmin<0 && xmin!=dxmin ? dxmin - 1 : dxmin;
796 xmax = xmax>0 && xmax!=dxmax ? dxmax + 1 : dxmax;
797
798 if (xmin>=xmax)
799 xmax = xmin+1;
800
801 Int_t bw = 1 + (Int_t)((xmax-xmin)/nbins);
802
803 nbins = (Int_t)((xmax-xmin)/bw);
804
805 if (xmin+nbins*bw < xmax)
806 {
807 nbins++;
808 xmax = xmin +nbins*bw;
809 }
810 }
811
812 newbins = nbins;
813#endif
814}
815
816// --------------------------------------------------------------------------
817//
818// Returns the lowest entry in a histogram which is greater than gt (eg >0)
819//
820Double_t MH::GetMinimumGT(const TH1 &h, Double_t gt)
821{
822 Double_t min = FLT_MAX;
823
824 const Int_t nx = h.GetXaxis()->GetNbins();
825 const Int_t ny = h.GetYaxis()->GetNbins();
826 const Int_t nz = h.GetZaxis()->GetNbins();
827
828 for (int iz=1; iz<=nz; iz++)
829 for (int iy=1; iy<=ny; iy++)
830 for (int ix=1; ix<=nx; ix++)
831 {
832 const Double_t v = h.GetBinContent(h.GetBin(ix, iy, iz));
833 if (gt<v && v<min)
834 min = v;
835 }
836 return min;
837}
838
839// --------------------------------------------------------------------------
840//
841// Returns the bin center in a logarithmic scale. If the given bin
842// number is <1 it is set to 1. If it is =GetNbins() it is set to
843// GetNbins()
844//
845Double_t MH::GetBinCenterLog(const TAxis &axe, Int_t nbin)
846{
847 if (nbin>axe.GetNbins())
848 nbin = axe.GetNbins();
849
850 if (nbin<1)
851 nbin = 1;
852
853 const Double_t lo = axe.GetBinLowEdge(nbin);
854 const Double_t hi = axe.GetBinUpEdge(nbin);
855
856 const Double_t val = log10(lo) + log10(hi);
857
858 return pow(10, val/2);
859}
860
861// --------------------------------------------------------------------------
862//
863// Draws a copy of the two given histograms. Uses title as the pad title.
864// Also layout the two statistic boxes and a legend.
865//
866void MH::DrawSameCopy(const TH1 &hist1, const TH1 &hist2, const TString title)
867{
868 //
869 // Draw first histogram
870 //
871 TH1 *h1 = hist1.DrawCopy();
872 gPad->SetBorderMode(0);
873 gPad->Update();
874
875 // FIXME: Also align max/min with set Maximum/Minimum
876 const Double_t maxbin1 = hist1.GetBinContent(hist1.GetMaximumBin());
877 const Double_t maxbin2 = hist2.GetBinContent(hist2.GetMaximumBin());
878 const Double_t minbin1 = hist1.GetBinContent(hist1.GetMinimumBin());
879 const Double_t minbin2 = hist2.GetBinContent(hist2.GetMinimumBin());
880
881 const Double_t max = TMath::Max(maxbin1, maxbin2);
882 const Double_t min = TMath::Min(minbin1, minbin2);
883
884 h1->SetMaximum(max>0?max*1.05:max*0.95);
885 h1->SetMinimum(max>0?min*0.95:min*1.05);
886
887 TPaveText *t = (TPaveText*)gPad->FindObject("title");
888 if (t)
889 {
890 t->SetName((TString)"MHTitle"); // rename object
891 t->Clear(); // clear old lines
892 t->AddText((TString)" "+title+" "); // add the new title
893 t->SetBit(kCanDelete); // make sure object is deleted
894
895 //
896 // FIXME: This is a stupid workaround to hide the redrawn
897 // (see THistPainter::PaintTitle) title
898 //
899 gPad->Modified(); // indicates a change
900 gPad->Update(); // recreates the original title
901 t->Pop(); // bring our title on top
902 }
903
904 //
905 // Rename first statistics box
906 //
907 TPaveStats *s1 = dynamic_cast<TPaveStats*>(gPad->FindObject("stats"));
908 if (!s1)
909 s1 = dynamic_cast<TPaveStats*>(hist1.GetListOfFunctions()->FindObject("stats"));
910 else
911 s1->SetName((TString)"Stat"+hist1.GetTitle());
912
913 if (s1 && s1->GetX2NDC()>0.95)
914 {
915 const Double_t x1 = s1->GetX1NDC()-0.01;
916 s1->SetX1NDC(x1-(s1->GetX2NDC()-s1->GetX1NDC()));
917 s1->SetX2NDC(x1);
918 }
919
920 //
921 // Draw second histogram
922 //
923 TH1 *h2 = hist2.DrawCopy("sames");
924 gPad->Update();
925
926 //
927 // Draw Legend
928 //
929 TPaveStats *s2 = dynamic_cast<TPaveStats*>(gPad->FindObject("stats"));
930 if (!s2)
931 s2 = dynamic_cast<TPaveStats*>(hist2.GetListOfFunctions()->FindObject("stats"));
932
933 if (s2)
934 {
935 TLegend &l = *new TLegend(s2->GetX1NDC(),
936 s2->GetY1NDC()-0.015-(s2->GetY2NDC()-s2->GetY1NDC())/2,
937 s2->GetX2NDC(),
938 s2->GetY1NDC()-0.01
939 );
940 l.AddEntry(h1, h1->GetTitle());
941 l.AddEntry(h2, h2->GetTitle());
942 l.SetTextSize(s2->GetTextSize());
943 l.SetTextFont(s2->GetTextFont());
944 l.SetBorderSize(s2->GetBorderSize());
945 l.SetBit(kCanDelete);
946 l.Draw();
947 }
948}
949
950// --------------------------------------------------------------------------
951//
952// Draws the two given histograms. Uses title as the pad title.
953// Also layout the two statistic boxes and a legend.
954//
955void MH::DrawSame(TH1 &hist1, TH1 &hist2, const TString title, Bool_t same)
956{
957 //
958 // Draw first histogram
959 //
960 hist1.Draw(same?"same":"");
961 gPad->SetBorderMode(0);
962 gPad->Update();
963
964 if (hist1.GetEntries()>0 && hist2.GetEntries()>0)
965 {
966 const Double_t maxbin1 = hist1.GetBinContent(hist1.GetMaximumBin());
967 const Double_t maxbin2 = hist2.GetBinContent(hist2.GetMaximumBin());
968 const Double_t minbin1 = hist1.GetBinContent(hist1.GetMinimumBin());
969 const Double_t minbin2 = hist2.GetBinContent(hist2.GetMinimumBin());
970
971 const Double_t max = TMath::Max(maxbin1, maxbin2);
972 const Double_t min = TMath::Min(minbin1, minbin2);
973
974 if (max!=min)
975 {
976 hist1.SetMaximum(max>0?max*1.05:max*0.95);
977 hist1.SetMinimum(max>0?min*0.95:min*1.05);
978 }
979 }
980
981 TPaveText *t = (TPaveText*)gPad->FindObject("title");
982 if (t)
983 {
984 t->SetName((TString)"MHTitle"); // rename object
985 t->Clear(); // clear old lines
986 t->AddText((TString)" "+title+" "); // add the new title
987 t->SetBit(kCanDelete); // make sure object is deleted
988
989 //
990 // FIXME: This is a stupid workaround to hide the redrawn
991 // (see THistPainter::PaintTitle) title
992 //
993 gPad->Modified(); // indicates a change
994 gPad->Update(); // recreates the original title
995 t->Pop(); // bring our title on top
996 }
997
998 //
999 // Rename first statistics box
1000 //
1001 // Where to get the TPaveStats depends on the root version
1002 TPaveStats *s1 = dynamic_cast<TPaveStats*>(gPad->FindObject("stats"));
1003 if (!s1)
1004 s1 = dynamic_cast<TPaveStats*>(hist1.GetListOfFunctions()->FindObject("stats"));
1005 else
1006 s1->SetName((TString)"Stat"+hist1.GetTitle());
1007
1008 if (s1 && s1->GetX2NDC()>0.95)
1009 {
1010 const Double_t x1 = s1->GetX1NDC()-0.01;
1011 s1->SetX1NDC(x1-(s1->GetX2NDC()-s1->GetX1NDC()));
1012 s1->SetX2NDC(x1);
1013 }
1014
1015 //
1016 // Draw second histogram
1017 //
1018 hist2.Draw("sames");
1019 gPad->Update();
1020
1021 //
1022 // Draw Legend
1023 //
1024 // Where to get the TPaveStats depends on the root version
1025 TPaveStats *s2 = dynamic_cast<TPaveStats*>(gPad->FindObject("stats"));
1026 if (!s2)
1027 s2 = dynamic_cast<TPaveStats*>(hist2.GetListOfFunctions()->FindObject("stats"));
1028
1029 if (s2)
1030 {
1031 TLegend &l = *new TLegend(s2->GetX1NDC(),
1032 s2->GetY1NDC()-0.015-(s2->GetY2NDC()-s2->GetY1NDC())/2,
1033 s2->GetX2NDC(),
1034 s2->GetY1NDC()-0.01
1035 );
1036 l.AddEntry(&hist1, hist1.GetTitle());
1037 l.AddEntry(&hist2, hist2.GetTitle());
1038 l.SetTextSize(s2->GetTextSize());
1039 l.SetTextFont(s2->GetTextFont());
1040 l.SetBorderSize(s2->GetBorderSize());
1041 l.SetBit(kCanDelete);
1042 l.Draw();
1043 }
1044}
1045
1046// --------------------------------------------------------------------------
1047//
1048// If the opt string contains 'nonew' or gPad is not given NULL is returned.
1049// Otherwise the present gPad is returned.
1050//
1051TVirtualPad *MH::GetNewPad(TString &opt)
1052{
1053 opt.ToLower();
1054
1055 if (!opt.Contains("nonew"))
1056 return NULL;
1057
1058 opt.ReplaceAll("nonew", "");
1059
1060 return gPad;
1061}
1062
1063// --------------------------------------------------------------------------
1064//
1065// Encapsulate the TObject::Clone such, that a cloned TH1 (or derived)
1066// object is not added to the current directory, when cloned.
1067//
1068TObject *MH::Clone(const char *name) const
1069{
1070 const Bool_t store = TH1::AddDirectoryStatus();
1071
1072 TH1::AddDirectory(kFALSE);
1073 TObject *o = MParContainer::Clone(name);
1074 TH1::AddDirectory(store);
1075
1076 return o;
1077}
1078
1079// --------------------------------------------------------------------------
1080//
1081// If the opt string contains 'nonew' or gPad is not given a new canvas
1082// with size w/h is created. Otherwise the object is cloned and drawn
1083// to the present pad. The kCanDelete bit is set for the clone.
1084//
1085TObject *MH::DrawClone(Option_t *opt, Int_t w, Int_t h) const
1086{
1087 TString option(opt);
1088
1089 TVirtualPad *p = GetNewPad(option);
1090 if (!p)
1091 p = MakeDefCanvas(this, w, h);
1092 else
1093 if (!option.Contains("same", TString::kIgnoreCase))
1094 p->Clear();
1095
1096 gROOT->SetSelectedPad(NULL);
1097
1098 TObject *o = MParContainer::DrawClone(option);
1099 o->SetBit(kCanDelete);
1100 return o;
1101}
1102
1103// --------------------------------------------------------------------------
1104//
1105// Check whether a class inheriting from MH overwrites the Draw function
1106//
1107Bool_t MH::OverwritesDraw(TClass *cls) const
1108{
1109 if (!cls)
1110 cls = IsA();
1111
1112 //
1113 // Check whether we reached the base class MTask
1114 //
1115 if (TString(cls->GetName())=="MH")
1116 return kFALSE;
1117
1118 //
1119 // Check whether the class cls overwrites Draw
1120 //
1121 if (cls->GetMethodAny("Draw"))
1122 return kTRUE;
1123
1124 //
1125 // If the class itself doesn't overload it check all it's base classes
1126 //
1127 TBaseClass *base=NULL;
1128 TIter NextBase(cls->GetListOfBases());
1129 while ((base=(TBaseClass*)NextBase()))
1130 {
1131 if (OverwritesDraw(base->GetClassPointer()))
1132 return kTRUE;
1133 }
1134
1135 return kFALSE;
1136}
1137
1138// --------------------------------------------------------------------------
1139//
1140// Cuts the bins containing only zeros at the edges.
1141//
1142// A new number of bins can be defined with nbins != 0
1143// In the case of nbins == 0, no rebinning will take place
1144//
1145// Returns the new (real) number of bins
1146//
1147Int_t MH::StripZeros(TH1 *h, Int_t nbins)
1148{
1149 TAxis &axe = *h->GetXaxis();
1150
1151 const Int_t min1 = axe.GetFirst();
1152 const Int_t max1 = axe.GetLast();
1153 const Int_t range1 = max1-min1;
1154
1155 //
1156 // Check for useless zeros
1157 //
1158 if (range1 == 0)
1159 return 0;
1160
1161 Int_t min2 = 0;
1162 for (int i=min1; i<=max1; i++)
1163 if (h->GetBinContent(i) != 0)
1164 {
1165 min2 = i;
1166 break;
1167 }
1168
1169 //
1170 // If the histogram consists of zeros only
1171 //
1172 if (min2 == max1)
1173 return 0;
1174
1175 Int_t max2 = 0;
1176 for (int i=max1; i>=min2; i--)
1177 if (h->GetBinContent(i) != 0)
1178 {
1179 max2 = i;
1180 break;
1181 }
1182
1183 //
1184 // Appying TAxis->SetRange before ReBin does not work ...
1185 // But this workaround helps quite fine
1186 //
1187 Axis_t min = h->GetBinLowEdge(min2);
1188 Axis_t max = h->GetBinLowEdge(max2)+h->GetBinWidth(max2);
1189
1190 Int_t nbins2 = max2-min2;
1191 //
1192 // Check for rebinning
1193 //
1194 if (nbins > 0)
1195 {
1196 const Int_t ngroup = (Int_t)(nbins2*h->GetNbinsX()/nbins/(max1-min1));
1197 if (ngroup > 1)
1198 {
1199 h->Rebin(ngroup);
1200 nbins2 /= ngroup;
1201 }
1202 }
1203
1204 Int_t newbins = 0;
1205 FindGoodLimits(nbins2, newbins, min, max, kFALSE);
1206 axe.SetRangeUser(min,max);
1207 return axe.GetLast()-axe.GetFirst();
1208}
1209
1210// --------------------------------------------------------------------------
1211//
1212// In contradiction to TPad::FindObject this function searches recursively
1213// in a pad for an object. gPad is the default.
1214//
1215TObject *MH::FindObjectInPad(const char *name, TVirtualPad *pad)
1216{
1217 if (!pad)
1218 pad = gPad;
1219
1220 if (!pad)
1221 return NULL;
1222
1223 TObject *o;
1224
1225 TIter Next(pad->GetListOfPrimitives());
1226 while ((o=Next()))
1227 {
1228 if (!strcmp(o->GetName(), name))
1229 return o;
1230
1231 if (o->InheritsFrom("TPad"))
1232 if ((o = FindObjectInPad(name, (TVirtualPad*)o)))
1233 return o;
1234 }
1235 return NULL;
1236}
1237
1238// --------------------------------------------------------------------------
1239//
1240//
1241//
1242TH1I* MH::ProjectArray(const TArrayF &array, Int_t nbins,
1243 const char* name, const char* title)
1244{
1245 const Int_t size = array.GetSize();
1246
1247 TH1I *h1=0;
1248
1249 //check if histogram with identical name exist
1250 TObject *h1obj = gROOT->FindObject(name);
1251 if (h1obj && h1obj->InheritsFrom("TH1I"))
1252 {
1253 h1 = (TH1I*)h1obj;
1254 h1->Reset();
1255 }
1256
1257 Double_t min = size>0 ? array[0] : 0;
1258 Double_t max = size>0 ? array[0] : 1;
1259
1260 // first loop over array to find the min and max
1261 for (Int_t i=1; i<size;i++)
1262 {
1263 max = TMath::Max((Double_t)array[i], max);
1264 min = TMath::Min((Double_t)array[i], min);
1265 }
1266
1267 Int_t newbins = 0;
1268 FindGoodLimits(nbins, newbins, min, max, kFALSE);
1269
1270 if (!h1)
1271 {
1272 h1 = new TH1I(name, title, nbins, min, max);
1273 h1->SetXTitle("");
1274 h1->SetYTitle("Counts");
1275 h1->SetDirectory(NULL);
1276 }
1277
1278 // Second loop to fill the histogram
1279 for (Int_t i=0;i<size;i++)
1280 h1->Fill(array[i]);
1281
1282 return h1;
1283}
1284
1285// --------------------------------------------------------------------------
1286//
1287//
1288//
1289TH1I* MH::ProjectArray(const TArrayD &array, Int_t nbins, const char* name, const char* title)
1290{
1291 const Int_t size = array.GetSize();
1292
1293 Double_t min = size>0 ? array[0] : 0;
1294 Double_t max = size>0 ? array[0] : 1;
1295
1296 TH1I *h1=0;
1297
1298 //check if histogram with identical name exist
1299 TObject *h1obj = gROOT->FindObject(name);
1300 if (h1obj && h1obj->InheritsFrom("TH1I"))
1301 {
1302 h1 = (TH1I*)h1obj;
1303 h1->Reset();
1304 }
1305
1306 // first loop over array to find the min and max
1307 for (Int_t i=1; i<size;i++)
1308 {
1309 max = TMath::Max(array[i], max);
1310 min = TMath::Min(array[i], min);
1311 }
1312
1313 Int_t newbins = 0;
1314 FindGoodLimits(nbins, newbins, min, max, kFALSE);
1315
1316 if (!h1)
1317 {
1318 h1 = new TH1I(name, title, newbins, min, max);
1319 h1->SetXTitle("");
1320 h1->SetYTitle("Counts");
1321 h1->SetDirectory(NULL);
1322 }
1323
1324 // Second loop to fill the histogram
1325 for (Int_t i=0;i<size;i++)
1326 h1->Fill(array[i]);
1327
1328 return h1;
1329}
1330
1331// --------------------------------------------------------------------------
1332//
1333//
1334//
1335TH1I* MH::ProjectArray(const MArrayF &array, Int_t nbins,
1336 const char* name, const char* title)
1337{
1338 return ProjectArray(TArrayF(array.GetSize(),array.GetArray()), nbins, name, title);
1339}
1340
1341// --------------------------------------------------------------------------
1342//
1343//
1344//
1345TH1I* MH::ProjectArray(const MArrayD &array, Int_t nbins, const char* name, const char* title)
1346{
1347 return ProjectArray(TArrayD(array.GetSize(),array.GetArray()), nbins, name, title);
1348}
1349
1350// --------------------------------------------------------------------------
1351//
1352// This is a workaround for rrot-version <5.13/04 to get correct
1353// binomial errors even if weights have been used, do:
1354// h->Divide(h1, h2, 5, 2, "b");
1355// MH::SetBinomialErrors(*h, *h1, *h2, 5, 2);
1356//
1357// see http://root.cern.ch/phpBB2/viewtopic.php?p=14818
1358// see http://savannah.cern.ch/bugs/?20722
1359//
1360void MH::SetBinomialErrors(TH1 &hres, const TH1 &h1, const TH1 &h2, Double_t c1, Double_t c2)
1361{
1362 for (Int_t binx=0; binx<=hres.GetNbinsX()+1; binx++)
1363 {
1364 const Double_t b1 = h1.GetBinContent(binx);
1365 const Double_t b2 = h2.GetBinContent(binx);
1366 const Double_t e1 = h1.GetBinError(binx);
1367 const Double_t e2 = h2.GetBinError(binx);
1368
1369 //const Double_t w = c2*b2 ? (c1*b1)/(c2*b2) : 0;
1370 //const Double_t rc = ((1-2*w)*e1*e1+w*w*e2*e2)/(b2*b2);
1371
1372 if (b2==0)
1373 {
1374 hres.SetBinError(binx, 0);
1375 continue;
1376 }
1377
1378 const Double_t c = c2==0 ? 1 : c1/c2;
1379 const Double_t u = b2==0 ? 0 : b1/b2;
1380
1381 const Double_t rc = c*((1-2*u)*e1*e1+u*u*e2*e2)/(b2*b2);
1382
1383 hres.SetBinError(binx, TMath::Sqrt(TMath::Abs(rc)));
1384 }
1385}
1386
1387// --------------------------------------------------------------------------
1388//
1389// Return the first and last bin of the histogram which is not 0
1390//
1391void MH::GetRange(const TH1 &h, Int_t &lo, Int_t &hi)
1392{
1393 lo = 0;
1394 hi = 1;
1395
1396 for (int i=1; i<=h.GetNbinsX(); i++)
1397 {
1398 if (lo==0 && h.GetBinContent(i)>0)
1399 lo = i;
1400
1401 if (h.GetBinContent(i)>0)
1402 hi = i;
1403 }
1404}
1405
1406// --------------------------------------------------------------------------
1407//
1408// Return the lower edge of the first and the upper edge of the last bin
1409// of the histogram which is not 0
1410//
1411void MH::GetRangeUser(const TH1 &h, Axis_t &lo, Axis_t &hi)
1412{
1413 Int_t f, l;
1414 GetRange(h, f, l);
1415
1416 lo = h.GetBinLowEdge(f);
1417 hi = h.GetBinLowEdge(l+1);
1418}
1419
1420// --------------------------------------------------------------------------
1421//
1422// Return the first and last column (x-bin) of the histogram which is not 0.
1423// Therefor a proper projection is produced if the argument is a TH2.
1424//
1425// TH3 are not yet supported
1426//
1427void MH::GetRangeX(const TH1 &hist, Int_t &lo, Int_t &hi)
1428{
1429 if (hist.InheritsFrom(TH3::Class()))
1430 return;
1431
1432 if (hist.InheritsFrom(TH2::Class()))
1433 {
1434 TH1 *pro = static_cast<const TH2&>(hist).ProjectionX();
1435 GetRange(*pro, lo, hi);
1436 delete pro;
1437 return;
1438 }
1439
1440 GetRange(hist, lo, hi);
1441}
1442
1443// --------------------------------------------------------------------------
1444//
1445// Return the first and last row (y-bin) of the histogram which is not 0.
1446// Therefor a proper projection is produced if the argument is a TH2.
1447//
1448// TH3 are not yet supported
1449//
1450void MH::GetRangeY(const TH1 &hist, Int_t &lo, Int_t &hi)
1451{
1452 if (hist.InheritsFrom(TH3::Class()))
1453 return;
1454
1455 if (hist.InheritsFrom(TH2::Class()))
1456 {
1457 TH1 *pro = static_cast<const TH2&>(hist).ProjectionY();
1458 GetRange(*pro, lo, hi);
1459 delete pro;
1460 }
1461}
1462
1463// --------------------------------------------------------------------------
1464//
1465// Return the lower edge of the first and the upper edge of the last bin
1466// of the histogram h returned by GetRangeX
1467//
1468void MH::GetRangeUserX(const TH1 &h, Axis_t &lo, Axis_t &hi)
1469{
1470 Int_t f, l;
1471 GetRangeX(h, f, l);
1472
1473 lo = h.GetXaxis()->GetBinLowEdge(f);
1474 hi = h.GetXaxis()->GetBinLowEdge(l+1);
1475}
1476
1477// --------------------------------------------------------------------------
1478//
1479// Return the lower edge of the first and the upper edge of the last bin
1480// of the histogram h returned by GetRangeY
1481//
1482void MH::GetRangeUserY(const TH1 &h, Axis_t &lo, Axis_t &hi)
1483{
1484 Int_t f, l;
1485 GetRangeY(h, f, l);
1486
1487 lo = h.GetYaxis()->GetBinLowEdge(f);
1488 hi = h.GetYaxis()->GetBinLowEdge(l+1);
1489}
1490
1491// --------------------------------------------------------------------------
1492//
1493// See MTask::PrintSkipped
1494//
1495void MH::PrintSkipped(UInt_t n, const char *str)
1496{
1497 *fLog << " " << setw(7) << n << " (";
1498 *fLog << Form("%5.1f", 100.*n/GetNumExecutions());
1499 *fLog << "%) Evts skipped: " << str << endl;
1500}
1501
1502#ifdef CreateGradientColorTable
1503#error CreateGradientColorTable already defined
1504#endif
1505
1506#if ROOT_VERSION_CODE < ROOT_VERSION(5,18,00)
1507#define CreateGradientColorTable gStyle->CreateGradientColorTable
1508#else
1509#define CreateGradientColorTable TColor::CreateGradientColorTable
1510#endif
1511
1512// --------------------------------------------------------------------------
1513//
1514// Calls gStyle->SetPalette. Allowed palettes are:
1515// pretty
1516// deepblue: darkblue -> lightblue
1517// lightblue: black -> blue -> white
1518// greyscale: black -> white
1519// glow1: black -> darkred -> orange -> yellow -> white
1520// glow2:
1521// glowsym: lightblue -> blue -> black -> darkred -> orange -> yellow -> white
1522// redish: darkred -> lightred
1523// bluish: darkblue -> lightblue
1524// small1:
1525//
1526// If the palette name contains 'inv' the order of the colors is inverted.
1527//
1528// The second argument determines the number of colors for the palette.
1529// The default is 50. 'pretty' always has 50 colors.
1530//
1531// (Remark: Drawing 3D object like TH2D with surf3 allows a maximum
1532// of 99 colors)
1533//
1534void MH::SetPalette(TString paletteName, Int_t ncol)
1535{
1536 Bool_t found=kFALSE;
1537
1538 paletteName.ToLower();
1539
1540 const Bool_t inverse = paletteName.Contains("inv");
1541
1542 if (paletteName.Contains("pretty"))
1543 {
1544 gStyle->SetPalette(1, 0);
1545 ncol=50;
1546 found=kTRUE;
1547 }
1548
1549 if (paletteName.Contains("deepblue"))
1550 {
1551 Double_t s[5] = { 0.00, 0.34, 0.61, 0.84, 1.00 };
1552 Double_t r[5] = { 0.00, 0.09, 0.18, 0.09, 0.00 };
1553 Double_t g[5] = { 0.01, 0.02, 0.39, 0.68, 0.97 };
1554 Double_t b[5] = { 0.17, 0.39, 0.62, 0.79, 0.97 };
1555 CreateGradientColorTable(5, s, r, g, b, ncol);
1556 found=kTRUE;
1557 }
1558
1559 if (paletteName.Contains("lightblue"))
1560 {
1561 Double_t s[5] = { 0.00, 0.34, 0.61, 0.84, 1.00 };
1562 Double_t r[5] = { 0.00, 0.09, 0.18, 0.09, 0.00 };
1563 Double_t g[5] = { 0.00, 0.02, 0.40, 0.70, 1.00 };
1564 Double_t b[5] = { 0.00, 0.27, 0.51, 0.81, 1.00 };
1565 CreateGradientColorTable(5, s, r, g, b, ncol);
1566 found=kTRUE;
1567 }
1568
1569 if (paletteName.Contains("greyscale"))
1570 {
1571 double s[2] = {0.00, 1.00};
1572 double r[2] = {0.00, 1.00};
1573 double g[2] = {0.00, 1.00};
1574 double b[2] = {0.00, 1.00};
1575 CreateGradientColorTable(2, s, r, g, b, ncol);
1576 found=kTRUE;
1577 }
1578
1579 if (paletteName.Contains("glow1"))
1580 {
1581 double s[5] = {0., 0.10, 0.45, 0.75, 1.00};
1582 double r[5] = {0., 0.35, 0.85, 1.00, 1.00};
1583 double g[5] = {0., 0.10, 0.20, 0.73, 1.00};
1584 double b[5] = {0., 0.03, 0.06, 0.00, 1.00};
1585 CreateGradientColorTable(5, s, r, g, b, ncol);
1586 found=kTRUE;
1587 }
1588
1589 if (paletteName.Contains("glow2"))
1590 {
1591 double s[4] = {0.00, 0.50, 0.75, 1.00};
1592 double r[4] = {0.24, 0.67, 1.00, 1.00};
1593 double g[4] = {0.03, 0.04, 0.80, 1.00};
1594 double b[4] = {0.03, 0.04, 0.00, 1.00};
1595 CreateGradientColorTable(4, s, r, g, b, ncol);
1596 found=kTRUE;
1597 }
1598
1599 if (paletteName.Contains("glowsym"))
1600 {
1601 double s[8] = {0.00, 0.17, 0.39, 0.50, 0.55, 0.72, 0.88, 1.00};
1602 double r[8] = {0.09, 0.18, 0.09, 0.00, 0.35, 0.85, 1.00, 1.00};
1603 double g[8] = {0.70, 0.40, 0.02, 0.00, 0.10, 0.20, 0.73, 1.00};
1604 double b[8] = {0.81, 0.51, 0.27, 0.00, 0.03, 0.06, 0.00, 1.00};
1605 CreateGradientColorTable(8, s, r, g, b, ncol);
1606 found=kTRUE;
1607 }
1608
1609 if (paletteName.Contains("redish"))
1610 {
1611 double s[3] = {0., 0.5, 1.};
1612 double r[3] = {0., 1.0, 1.};
1613 double g[3] = {0., 0.0, 1.};
1614 double b[3] = {0., 0.0, 1.};
1615 CreateGradientColorTable(3, s, r, g, b, ncol);
1616 found=kTRUE;
1617 }
1618
1619 if (paletteName.Contains("bluish"))
1620 {
1621 double s[3] = {0., 0.5, 1.};
1622 double r[3] = {0., 0.0, 1.};
1623 double g[3] = {0., 0.0, 1.};
1624 double b[3] = {0., 1.0, 1.};
1625 CreateGradientColorTable(3, s, r, g, b, ncol);
1626 found=kTRUE;
1627 }
1628
1629 if (paletteName.Contains("small1"))
1630 {
1631 double s[4] = {0.00, 0.50, 0.95, 1.};
1632 double r[4] = {0.04, 0.28, 0.98, 1.};
1633 double g[4] = {0.28, 0.93, 0.03, 1.};
1634 double b[4] = {0.79, 0.11, 0.03, 1.};
1635 CreateGradientColorTable(4, s, r, g, b, ncol);
1636 found=kTRUE;
1637 }
1638 if (paletteName.Contains("pepe"))
1639 {
1640 double s[5] = {0.0, 0.6, 0.7, 0.9, 1.0 };
1641 double r[5] = {0.1, 0.1, 1.0, 1.0, 1.0 };
1642 double g[5] = {0.1, 0.1, 0.0, 1.0, 1.0 };
1643 double b[5] = {0.2, 0.7, 0.0, 0.3, 0.9 };
1644 CreateGradientColorTable(5, s, r, g, b, ncol);
1645 found=kTRUE;
1646 }
1647
1648 if (inverse)
1649 {
1650 TArrayI c(ncol);
1651 for (int i=0; i<ncol; i++)
1652 c[ncol-i-1] = gStyle->GetColorPalette(i);
1653 gStyle->SetPalette(ncol, c.GetArray());
1654 }
1655
1656 if (!found)
1657 gLog << warn << "MH::SetPalette: Palette " << paletteName << " unknown... ignored." << endl;
1658}
Note: See TracBrowser for help on using the repository browser.