source: trunk/Mars/mhbase/MH.cc@ 19344

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