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

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