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

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