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

Last change on this file since 9347 was 9315, checked in by tbretz, 16 years ago
*** empty log message ***
File size: 54.9 KB
Line 
1/* ======================================================================== *\
2! $Name: not supported by cvs2svn $:$Id: MH.cc,v 1.45 2009-02-11 12:08:23 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 return kTRUE;
701
702 SetBinning(h, bins);
703 return kTRUE;
704}
705
706Bool_t MH::ApplyBinning(const MParList &plist, TString x, TString y, TH2 *h)
707{
708 const MBinning *binsx = (MBinning*)plist.FindObject("Binning"+x);
709 if (!binsx)
710 {
711 gLog << inf << "Object 'Binning" << x << "' [MBinning] not found... no binning applied." << endl;
712 return kFALSE;
713 }
714 const MBinning *binsy = (MBinning*)plist.FindObject("Binning"+y);
715 if (!binsy)
716 {
717 gLog << inf << "Object 'Binning" << y << "' [MBinning] not found... no binning applied." << endl;
718 return kFALSE;
719 }
720
721 if (binsx->IsDefault() && binsy->IsDefault())
722 return kTRUE;
723
724 // -------------------------
725 /*
726 MBinning binsx, binsy, binsz;
727 binsx.SetEdges(fHist, 'x');
728 binsy.SetEdges(fHist, 'y');
729 binsz.SetEdges(fHist, 'z');
730 */
731 // -------------------------
732
733 SetBinning(h, binsx, binsy);
734
735 return kTRUE;
736}
737
738Bool_t MH::ApplyBinning(const MParList &plist, TString x, TString y, TString z, TH3 *h)
739{
740 const MBinning *binsx = (MBinning*)plist.FindObject("Binning"+x);
741 if (!binsx)
742 {
743 gLog << inf << "Object 'Binning" << x << "' [MBinning] not found... no binning applied." << endl;
744 return kFALSE;
745 }
746 const MBinning *binsy = (MBinning*)plist.FindObject("Binning"+y);
747 if (!binsy)
748 {
749 gLog << inf << "Object 'Binning" << y << "' [MBinning] not found... no binning applied." << endl;
750 return kFALSE;
751 }
752 const MBinning *binsz = (MBinning*)plist.FindObject("Binning"+z);
753 if (!binsz)
754 {
755 gLog << inf << "Object 'Binning" << z << "' [MBinning] not found... no binning applied." << endl;
756 return kFALSE;
757 }
758
759 if (binsx->IsDefault() && binsy->IsDefault() && binsz->IsDefault())
760 return kTRUE;
761
762 SetBinning(h, binsx, binsy, binsz);
763 return kTRUE;
764}
765
766void MH::FindGoodLimits(Int_t nbins, Int_t &newbins, Double_t &xmin, Double_t &xmax, Bool_t isInteger)
767{
768#if ROOT_VERSION_CODE > ROOT_VERSION(3,04,01)
769 THLimitsFinder::OptimizeLimits(nbins, newbins, xmin, xmax, isInteger);
770#else
771//*-*-*-*-*-*-*-*-*Find reasonable bin values*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
772//*-* ==========================
773
774 Double_t dx = 0.1*(xmax-xmin);
775 Double_t umin = xmin - dx;
776 Double_t umax = xmax + dx;
777
778 if (umin < 0 && xmin >= 0)
779 umin = 0;
780
781 if (umax > 0 && xmax <= 0)
782 umax = 0;
783
784 Double_t binlow =0;
785 Double_t binhigh =0;
786 Double_t binwidth=0;
787
788 TGaxis::Optimize(umin, umax, nbins, binlow, binhigh, nbins, binwidth, "");
789
790 if (binwidth <= 0 || binwidth > 1.e+39)
791 {
792 xmin = -1;
793 xmax = 1;
794 }
795 else
796 {
797 xmin = binlow;
798 xmax = binhigh;
799 }
800
801 if (isInteger)
802 {
803 Int_t ixmin = (Int_t)xmin;
804 Int_t ixmax = (Int_t)xmax;
805 Double_t dxmin = (Double_t)ixmin;
806 Double_t dxmax = (Double_t)ixmax;
807
808 xmin = xmin<0 && xmin!=dxmin ? dxmin - 1 : dxmin;
809 xmax = xmax>0 && xmax!=dxmax ? dxmax + 1 : dxmax;
810
811 if (xmin>=xmax)
812 xmax = xmin+1;
813
814 Int_t bw = 1 + (Int_t)((xmax-xmin)/nbins);
815
816 nbins = (Int_t)((xmax-xmin)/bw);
817
818 if (xmin+nbins*bw < xmax)
819 {
820 nbins++;
821 xmax = xmin +nbins*bw;
822 }
823 }
824
825 newbins = nbins;
826#endif
827}
828
829// --------------------------------------------------------------------------
830//
831// Returns the lowest entry in a histogram which is greater than gt (eg >0)
832//
833Double_t MH::GetMinimumGT(const TH1 &h, Double_t gt)
834{
835 Double_t min = FLT_MAX;
836
837 const Int_t nx = h.GetXaxis()->GetNbins();
838 const Int_t ny = h.GetYaxis()->GetNbins();
839 const Int_t nz = h.GetZaxis()->GetNbins();
840
841 for (int iz=1; iz<=nz; iz++)
842 for (int iy=1; iy<=ny; iy++)
843 for (int ix=1; ix<=nx; ix++)
844 {
845 const Double_t v = h.GetBinContent(h.GetBin(ix, iy, iz));
846 if (gt<v && v<min)
847 min = v;
848 }
849 return min;
850}
851
852// --------------------------------------------------------------------------
853//
854// Returns the bin center in a logarithmic scale. If the given bin
855// number is <1 it is set to 1. If it is =GetNbins() it is set to
856// GetNbins()
857//
858Double_t MH::GetBinCenterLog(const TAxis &axe, Int_t nbin)
859{
860 if (nbin>axe.GetNbins())
861 nbin = axe.GetNbins();
862
863 if (nbin<1)
864 nbin = 1;
865
866 const Double_t lo = axe.GetBinLowEdge(nbin);
867 const Double_t hi = axe.GetBinUpEdge(nbin);
868
869 const Double_t val = log10(lo) + log10(hi);
870
871 return pow(10, val/2);
872}
873
874// --------------------------------------------------------------------------
875//
876// Draws a copy of the two given histograms. Uses title as the pad title.
877// Also layout the two statistic boxes and a legend.
878//
879void MH::DrawSameCopy(const TH1 &hist1, const TH1 &hist2, const TString title)
880{
881 //
882 // Draw first histogram
883 //
884 TH1 *h1 = hist1.DrawCopy();
885 gPad->SetBorderMode(0);
886 gPad->Update();
887
888 // FIXME: Also align max/min with set Maximum/Minimum
889 const Double_t maxbin1 = hist1.GetBinContent(hist1.GetMaximumBin());
890 const Double_t maxbin2 = hist2.GetBinContent(hist2.GetMaximumBin());
891 const Double_t minbin1 = hist1.GetBinContent(hist1.GetMinimumBin());
892 const Double_t minbin2 = hist2.GetBinContent(hist2.GetMinimumBin());
893
894 const Double_t max = TMath::Max(maxbin1, maxbin2);
895 const Double_t min = TMath::Min(minbin1, minbin2);
896
897 h1->SetMaximum(max>0?max*1.05:max*0.95);
898 h1->SetMinimum(max>0?min*0.95:min*1.05);
899
900 TPaveText *t = (TPaveText*)gPad->FindObject("title");
901 if (t)
902 {
903 t->SetName((TString)"MHTitle"); // rename object
904 t->Clear(); // clear old lines
905 t->AddText((TString)" "+title+" "); // add the new title
906 t->SetBit(kCanDelete); // make sure object is deleted
907
908 //
909 // FIXME: This is a stupid workaround to hide the redrawn
910 // (see THistPainter::PaintTitle) title
911 //
912 gPad->Modified(); // indicates a change
913 gPad->Update(); // recreates the original title
914 t->Pop(); // bring our title on top
915 }
916
917 //
918 // Rename first statistics box
919 //
920 TPaveStats *s1 = dynamic_cast<TPaveStats*>(gPad->FindObject("stats"));
921 if (!s1)
922 s1 = dynamic_cast<TPaveStats*>(hist1.GetListOfFunctions()->FindObject("stats"));
923 else
924 s1->SetName((TString)"Stat"+hist1.GetTitle());
925
926 if (s1 && s1->GetX2NDC()>0.95)
927 {
928 const Double_t x1 = s1->GetX1NDC()-0.01;
929 s1->SetX1NDC(x1-(s1->GetX2NDC()-s1->GetX1NDC()));
930 s1->SetX2NDC(x1);
931 }
932
933 //
934 // Draw second histogram
935 //
936 TH1 *h2 = hist2.DrawCopy("sames");
937 gPad->Update();
938
939 //
940 // Draw Legend
941 //
942 TPaveStats *s2 = dynamic_cast<TPaveStats*>(gPad->FindObject("stats"));
943 if (!s2)
944 s2 = dynamic_cast<TPaveStats*>(hist2.GetListOfFunctions()->FindObject("stats"));
945
946 if (s2)
947 {
948 TLegend &l = *new TLegend(s2->GetX1NDC(),
949 s2->GetY1NDC()-0.015-(s2->GetY2NDC()-s2->GetY1NDC())/2,
950 s2->GetX2NDC(),
951 s2->GetY1NDC()-0.01
952 );
953 l.AddEntry(h1, h1->GetTitle());
954 l.AddEntry(h2, h2->GetTitle());
955 l.SetTextSize(s2->GetTextSize());
956 l.SetTextFont(s2->GetTextFont());
957 l.SetBorderSize(s2->GetBorderSize());
958 l.SetBit(kCanDelete);
959 l.Draw();
960 }
961}
962
963// --------------------------------------------------------------------------
964//
965// Draws the two given histograms. Uses title as the pad title.
966// Also layout the two statistic boxes and a legend.
967//
968void MH::DrawSame(TH1 &hist1, TH1 &hist2, const TString title, Bool_t same)
969{
970 //
971 // Draw first histogram
972 //
973 hist1.Draw(same?"same":"");
974 gPad->SetBorderMode(0);
975 gPad->Update();
976
977 if (hist1.GetEntries()>0 && hist2.GetEntries()>0)
978 {
979 const Double_t maxbin1 = hist1.GetBinContent(hist1.GetMaximumBin());
980 const Double_t maxbin2 = hist2.GetBinContent(hist2.GetMaximumBin());
981 const Double_t minbin1 = hist1.GetBinContent(hist1.GetMinimumBin());
982 const Double_t minbin2 = hist2.GetBinContent(hist2.GetMinimumBin());
983
984 const Double_t max = TMath::Max(maxbin1, maxbin2);
985 const Double_t min = TMath::Min(minbin1, minbin2);
986
987 if (max!=min)
988 {
989 hist1.SetMaximum(max>0?max*1.05:max*0.95);
990 hist1.SetMinimum(max>0?min*0.95:min*1.05);
991 }
992 }
993
994 TPaveText *t = (TPaveText*)gPad->FindObject("title");
995 if (t)
996 {
997 t->SetName((TString)"MHTitle"); // rename object
998 t->Clear(); // clear old lines
999 t->AddText((TString)" "+title+" "); // add the new title
1000 t->SetBit(kCanDelete); // make sure object is deleted
1001
1002 //
1003 // FIXME: This is a stupid workaround to hide the redrawn
1004 // (see THistPainter::PaintTitle) title
1005 //
1006 gPad->Modified(); // indicates a change
1007 gPad->Update(); // recreates the original title
1008 t->Pop(); // bring our title on top
1009 }
1010
1011 //
1012 // Rename first statistics box
1013 //
1014 // Where to get the TPaveStats depends on the root version
1015 TPaveStats *s1 = dynamic_cast<TPaveStats*>(gPad->FindObject("stats"));
1016 if (!s1)
1017 s1 = dynamic_cast<TPaveStats*>(hist1.GetListOfFunctions()->FindObject("stats"));
1018 else
1019 s1->SetName((TString)"Stat"+hist1.GetTitle());
1020
1021 if (s1 && s1->GetX2NDC()>0.95)
1022 {
1023 const Double_t x1 = s1->GetX1NDC()-0.01;
1024 s1->SetX1NDC(x1-(s1->GetX2NDC()-s1->GetX1NDC()));
1025 s1->SetX2NDC(x1);
1026 }
1027
1028 //
1029 // Draw second histogram
1030 //
1031 hist2.Draw("sames");
1032 gPad->Update();
1033
1034 //
1035 // Draw Legend
1036 //
1037 // Where to get the TPaveStats depends on the root version
1038 TPaveStats *s2 = dynamic_cast<TPaveStats*>(gPad->FindObject("stats"));
1039 if (!s2)
1040 s2 = dynamic_cast<TPaveStats*>(hist2.GetListOfFunctions()->FindObject("stats"));
1041
1042 if (s2)
1043 {
1044 TLegend &l = *new TLegend(s2->GetX1NDC(),
1045 s2->GetY1NDC()-0.015-(s2->GetY2NDC()-s2->GetY1NDC())/2,
1046 s2->GetX2NDC(),
1047 s2->GetY1NDC()-0.01
1048 );
1049 l.AddEntry(&hist1, hist1.GetTitle());
1050 l.AddEntry(&hist2, hist2.GetTitle());
1051 l.SetTextSize(s2->GetTextSize());
1052 l.SetTextFont(s2->GetTextFont());
1053 l.SetBorderSize(s2->GetBorderSize());
1054 l.SetBit(kCanDelete);
1055 l.Draw();
1056 }
1057}
1058
1059// --------------------------------------------------------------------------
1060//
1061// If the opt string contains 'nonew' or gPad is not given NULL is returned.
1062// Otherwise the present gPad is returned.
1063//
1064TVirtualPad *MH::GetNewPad(TString &opt)
1065{
1066 opt.ToLower();
1067
1068 if (!opt.Contains("nonew"))
1069 return NULL;
1070
1071 opt.ReplaceAll("nonew", "");
1072
1073 return gPad;
1074}
1075
1076// --------------------------------------------------------------------------
1077//
1078// Encapsulate the TObject::Clone such, that a cloned TH1 (or derived)
1079// object is not added to the current directory, when cloned.
1080//
1081TObject *MH::Clone(const char *name) const
1082{
1083 const Bool_t store = TH1::AddDirectoryStatus();
1084
1085 TH1::AddDirectory(kFALSE);
1086 TObject *o = MParContainer::Clone(name);
1087 TH1::AddDirectory(store);
1088
1089 return o;
1090}
1091
1092// --------------------------------------------------------------------------
1093//
1094// If the opt string contains 'nonew' or gPad is not given a new canvas
1095// with size w/h is created. Otherwise the object is cloned and drawn
1096// to the present pad. The kCanDelete bit is set for the clone.
1097//
1098TObject *MH::DrawClone(Option_t *opt, Int_t w, Int_t h) const
1099{
1100 TString option(opt);
1101
1102 TVirtualPad *p = GetNewPad(option);
1103 if (!p)
1104 p = MakeDefCanvas(this, w, h);
1105 else
1106 if (!option.Contains("same", TString::kIgnoreCase))
1107 p->Clear();
1108
1109 gROOT->SetSelectedPad(NULL);
1110
1111 TObject *o = MParContainer::DrawClone(option);
1112 o->SetBit(kCanDelete);
1113 return o;
1114}
1115
1116// --------------------------------------------------------------------------
1117//
1118// Check whether a class inheriting from MH overwrites the Draw function
1119//
1120Bool_t MH::OverwritesDraw(TClass *cls) const
1121{
1122 if (!cls)
1123 cls = IsA();
1124
1125 //
1126 // Check whether we reached the base class MTask
1127 //
1128 if (TString(cls->GetName())=="MH")
1129 return kFALSE;
1130
1131 //
1132 // Check whether the class cls overwrites Draw
1133 //
1134 if (cls->GetMethodAny("Draw"))
1135 return kTRUE;
1136
1137 //
1138 // If the class itself doesn't overload it check all it's base classes
1139 //
1140 TBaseClass *base=NULL;
1141 TIter NextBase(cls->GetListOfBases());
1142 while ((base=(TBaseClass*)NextBase()))
1143 {
1144 if (OverwritesDraw(base->GetClassPointer()))
1145 return kTRUE;
1146 }
1147
1148 return kFALSE;
1149}
1150
1151// --------------------------------------------------------------------------
1152//
1153// Cuts the bins containing only zeros at the edges.
1154//
1155// A new number of bins can be defined with nbins != 0
1156// In the case of nbins == 0, no rebinning will take place
1157//
1158// Returns the new (real) number of bins
1159//
1160Int_t MH::StripZeros(TH1 *h, Int_t nbins)
1161{
1162 TAxis &axe = *h->GetXaxis();
1163
1164 const Int_t min1 = axe.GetFirst();
1165 const Int_t max1 = axe.GetLast();
1166 const Int_t range1 = max1-min1;
1167
1168 //
1169 // Check for useless zeros
1170 //
1171 if (range1 == 0)
1172 return 0;
1173
1174 Int_t min2 = 0;
1175 for (int i=min1; i<=max1; i++)
1176 if (h->GetBinContent(i) != 0)
1177 {
1178 min2 = i;
1179 break;
1180 }
1181
1182 //
1183 // If the histogram consists of zeros only
1184 //
1185 if (min2 == max1)
1186 return 0;
1187
1188 Int_t max2 = 0;
1189 for (int i=max1; i>=min2; i--)
1190 if (h->GetBinContent(i) != 0)
1191 {
1192 max2 = i;
1193 break;
1194 }
1195
1196 //
1197 // Appying TAxis->SetRange before ReBin does not work ...
1198 // But this workaround helps quite fine
1199 //
1200 Axis_t min = h->GetBinLowEdge(min2);
1201 Axis_t max = h->GetBinLowEdge(max2)+h->GetBinWidth(max2);
1202
1203 Int_t nbins2 = max2-min2;
1204 //
1205 // Check for rebinning
1206 //
1207 if (nbins > 0)
1208 {
1209 const Int_t ngroup = (Int_t)(nbins2*h->GetNbinsX()/nbins/(max1-min1));
1210 if (ngroup > 1)
1211 {
1212 h->Rebin(ngroup);
1213 nbins2 /= ngroup;
1214 }
1215 }
1216
1217 Int_t newbins = 0;
1218 FindGoodLimits(nbins2, newbins, min, max, kFALSE);
1219 axe.SetRangeUser(min,max);
1220 return axe.GetLast()-axe.GetFirst();
1221}
1222
1223// --------------------------------------------------------------------------
1224//
1225// In contradiction to TPad::FindObject this function searches recursively
1226// in a pad for an object. gPad is the default.
1227//
1228TObject *MH::FindObjectInPad(const char *name, TVirtualPad *pad)
1229{
1230 if (!pad)
1231 pad = gPad;
1232
1233 if (!pad)
1234 return NULL;
1235
1236 TObject *o;
1237
1238 TIter Next(pad->GetListOfPrimitives());
1239 while ((o=Next()))
1240 {
1241 if (!strcmp(o->GetName(), name))
1242 return o;
1243
1244 if (o->InheritsFrom("TPad"))
1245 if ((o = FindObjectInPad(name, (TVirtualPad*)o)))
1246 return o;
1247 }
1248 return NULL;
1249}
1250
1251// --------------------------------------------------------------------------
1252//
1253//
1254//
1255TH1I* MH::ProjectArray(const TArrayF &array, Int_t nbins,
1256 const char* name, const char* title)
1257{
1258 const Int_t size = array.GetSize();
1259
1260 TH1I *h1=0;
1261
1262 //check if histogram with identical name exist
1263 TObject *h1obj = gROOT->FindObject(name);
1264 if (h1obj && h1obj->InheritsFrom("TH1I"))
1265 {
1266 h1 = (TH1I*)h1obj;
1267 h1->Reset();
1268 }
1269
1270 Double_t min = size>0 ? array[0] : 0;
1271 Double_t max = size>0 ? array[0] : 1;
1272
1273 // first loop over array to find the min and max
1274 for (Int_t i=1; i<size;i++)
1275 {
1276 max = TMath::Max((Double_t)array[i], max);
1277 min = TMath::Min((Double_t)array[i], min);
1278 }
1279
1280 Int_t newbins = 0;
1281 FindGoodLimits(nbins, newbins, min, max, kFALSE);
1282
1283 if (!h1)
1284 {
1285 h1 = new TH1I(name, title, nbins, min, max);
1286 h1->SetXTitle("");
1287 h1->SetYTitle("Counts");
1288 h1->SetDirectory(NULL);
1289 }
1290
1291 // Second loop to fill the histogram
1292 for (Int_t i=0;i<size;i++)
1293 h1->Fill(array[i]);
1294
1295 return h1;
1296}
1297
1298// --------------------------------------------------------------------------
1299//
1300//
1301//
1302TH1I* MH::ProjectArray(const TArrayD &array, Int_t nbins, const char* name, const char* title)
1303{
1304 const Int_t size = array.GetSize();
1305
1306 Double_t min = size>0 ? array[0] : 0;
1307 Double_t max = size>0 ? array[0] : 1;
1308
1309 TH1I *h1=0;
1310
1311 //check if histogram with identical name exist
1312 TObject *h1obj = gROOT->FindObject(name);
1313 if (h1obj && h1obj->InheritsFrom("TH1I"))
1314 {
1315 h1 = (TH1I*)h1obj;
1316 h1->Reset();
1317 }
1318
1319 // first loop over array to find the min and max
1320 for (Int_t i=1; i<size;i++)
1321 {
1322 max = TMath::Max(array[i], max);
1323 min = TMath::Min(array[i], min);
1324 }
1325
1326 Int_t newbins = 0;
1327 FindGoodLimits(nbins, newbins, min, max, kFALSE);
1328
1329 if (!h1)
1330 {
1331 h1 = new TH1I(name, title, newbins, min, max);
1332 h1->SetXTitle("");
1333 h1->SetYTitle("Counts");
1334 h1->SetDirectory(NULL);
1335 }
1336
1337 // Second loop to fill the histogram
1338 for (Int_t i=0;i<size;i++)
1339 h1->Fill(array[i]);
1340
1341 return h1;
1342}
1343
1344// --------------------------------------------------------------------------
1345//
1346//
1347//
1348TH1I* MH::ProjectArray(const MArrayF &array, Int_t nbins,
1349 const char* name, const char* title)
1350{
1351 return ProjectArray(TArrayF(array.GetSize(),array.GetArray()), nbins, name, title);
1352}
1353
1354// --------------------------------------------------------------------------
1355//
1356//
1357//
1358TH1I* MH::ProjectArray(const MArrayD &array, Int_t nbins, const char* name, const char* title)
1359{
1360 return ProjectArray(TArrayD(array.GetSize(),array.GetArray()), nbins, name, title);
1361}
1362
1363// --------------------------------------------------------------------------
1364//
1365// This is a workaround for rrot-version <5.13/04 to get correct
1366// binomial errors even if weights have been used, do:
1367// h->Divide(h1, h2, 5, 2, "b");
1368// MH::SetBinomialErrors(*h, *h1, *h2, 5, 2);
1369//
1370// see http://root.cern.ch/phpBB2/viewtopic.php?p=14818
1371// see http://savannah.cern.ch/bugs/?20722
1372//
1373void MH::SetBinomialErrors(TH1 &hres, const TH1 &h1, const TH1 &h2, Double_t c1, Double_t c2)
1374{
1375 for (Int_t binx=0; binx<=hres.GetNbinsX()+1; binx++)
1376 {
1377 const Double_t b1 = h1.GetBinContent(binx);
1378 const Double_t b2 = h2.GetBinContent(binx);
1379 const Double_t e1 = h1.GetBinError(binx);
1380 const Double_t e2 = h2.GetBinError(binx);
1381
1382 //const Double_t w = c2*b2 ? (c1*b1)/(c2*b2) : 0;
1383 //const Double_t rc = ((1-2*w)*e1*e1+w*w*e2*e2)/(b2*b2);
1384
1385 if (b2==0)
1386 {
1387 hres.SetBinError(binx, 0);
1388 continue;
1389 }
1390
1391 const Double_t c = c2==0 ? 1 : c1/c2;
1392 const Double_t u = b2==0 ? 0 : b1/b2;
1393
1394 const Double_t rc = c*((1-2*u)*e1*e1+u*u*e2*e2)/(b2*b2);
1395
1396 hres.SetBinError(binx, TMath::Sqrt(TMath::Abs(rc)));
1397 }
1398}
1399
1400// --------------------------------------------------------------------------
1401//
1402// Return the first and last bin of the histogram which is not 0
1403//
1404void MH::GetRange(const TH1 &h, Int_t &lo, Int_t &hi)
1405{
1406 lo = 0;
1407 hi = 1;
1408
1409 for (int i=1; i<=h.GetNbinsX(); i++)
1410 {
1411 if (lo==0 && h.GetBinContent(i)>0)
1412 lo = i;
1413
1414 if (h.GetBinContent(i)>0)
1415 hi = i;
1416 }
1417}
1418
1419// --------------------------------------------------------------------------
1420//
1421// Return the lower edge of the first and the upper edge of the last bin
1422// of the histogram which is not 0
1423//
1424void MH::GetRangeUser(const TH1 &h, Axis_t &lo, Axis_t &hi)
1425{
1426 Int_t f, l;
1427 GetRange(h, f, l);
1428
1429 lo = h.GetBinLowEdge(f);
1430 hi = h.GetBinLowEdge(l+1);
1431}
1432
1433// --------------------------------------------------------------------------
1434//
1435// Return the first and last column (x-bin) of the histogram which is not 0.
1436// Therefor a proper projection is produced if the argument is a TH2.
1437//
1438// TH3 are not yet supported
1439//
1440void MH::GetRangeX(const TH1 &hist, Int_t &lo, Int_t &hi)
1441{
1442 if (hist.InheritsFrom(TH3::Class()))
1443 return;
1444
1445 if (hist.InheritsFrom(TH2::Class()))
1446 {
1447 TH1 *pro = static_cast<const TH2&>(hist).ProjectionX();
1448 GetRange(*pro, lo, hi);
1449 delete pro;
1450 return;
1451 }
1452
1453 GetRange(hist, lo, hi);
1454}
1455
1456// --------------------------------------------------------------------------
1457//
1458// Return the first and last row (y-bin) of the histogram which is not 0.
1459// Therefor a proper projection is produced if the argument is a TH2.
1460//
1461// TH3 are not yet supported
1462//
1463void MH::GetRangeY(const TH1 &hist, Int_t &lo, Int_t &hi)
1464{
1465 if (hist.InheritsFrom(TH3::Class()))
1466 return;
1467
1468 if (hist.InheritsFrom(TH2::Class()))
1469 {
1470 TH1 *pro = static_cast<const TH2&>(hist).ProjectionY();
1471 GetRange(*pro, lo, hi);
1472 delete pro;
1473 }
1474}
1475
1476// --------------------------------------------------------------------------
1477//
1478// Return the lower edge of the first and the upper edge of the last bin
1479// of the histogram h returned by GetRangeX
1480//
1481void MH::GetRangeUserX(const TH1 &h, Axis_t &lo, Axis_t &hi)
1482{
1483 Int_t f, l;
1484 GetRangeX(h, f, l);
1485
1486 lo = h.GetXaxis()->GetBinLowEdge(f);
1487 hi = h.GetXaxis()->GetBinLowEdge(l+1);
1488}
1489
1490// --------------------------------------------------------------------------
1491//
1492// Return the lower edge of the first and the upper edge of the last bin
1493// of the histogram h returned by GetRangeY
1494//
1495void MH::GetRangeUserY(const TH1 &h, Axis_t &lo, Axis_t &hi)
1496{
1497 Int_t f, l;
1498 GetRangeY(h, f, l);
1499
1500 lo = h.GetYaxis()->GetBinLowEdge(f);
1501 hi = h.GetYaxis()->GetBinLowEdge(l+1);
1502}
1503
1504// --------------------------------------------------------------------------
1505//
1506// See MTask::PrintSkipped
1507//
1508void MH::PrintSkipped(UInt_t n, const char *str)
1509{
1510 *fLog << " " << setw(7) << n;
1511 if (GetNumExecutions()>0)
1512 {
1513 *fLog << " (" << MString::Format("%5.1f", 100.*n/GetNumExecutions());
1514 *fLog << "%)" << str << endl;
1515 }
1516 *fLog << " Evts skipped: " << str << endl;
1517}
1518
1519#ifdef CreateGradientColorTable
1520#error CreateGradientColorTable already defined
1521#endif
1522
1523#if ROOT_VERSION_CODE < ROOT_VERSION(5,18,00)
1524#define CreateGradientColorTable gStyle->CreateGradientColorTable
1525#else
1526#define CreateGradientColorTable TColor::CreateGradientColorTable
1527#endif
1528
1529// --------------------------------------------------------------------------
1530//
1531// Calls gStyle->SetPalette. Allowed palettes are:
1532// pretty
1533// deepblue: darkblue -> lightblue
1534// lightblue: black -> blue -> white
1535// greyscale: black -> white
1536// glow1: black -> darkred -> orange -> yellow -> white
1537// glow2:
1538// glowsym: lightblue -> blue -> black -> darkred -> orange -> yellow -> white
1539// redish: darkred -> lightred
1540// bluish: darkblue -> lightblue
1541// small1:
1542//
1543// If the palette name contains 'inv' the order of the colors is inverted.
1544//
1545// The second argument determines the number of colors for the palette.
1546// The default is 50. 'pretty' always has 50 colors.
1547//
1548// (Remark: Drawing 3D object like TH2D with surf3 allows a maximum
1549// of 99 colors)
1550//
1551void MH::SetPalette(TString paletteName, Int_t ncol)
1552{
1553 Bool_t found=kFALSE;
1554
1555 paletteName.ToLower();
1556
1557 const Bool_t inverse = paletteName.Contains("inv");
1558
1559 if (paletteName.Contains("pretty"))
1560 {
1561 gStyle->SetPalette(1, 0);
1562 ncol=50;
1563 found=kTRUE;
1564 }
1565
1566 if (paletteName.Contains("deepblue"))
1567 {
1568 Double_t s[5] = { 0.00, 0.34, 0.61, 0.84, 1.00 };
1569 Double_t r[5] = { 0.00, 0.09, 0.18, 0.09, 0.00 };
1570 Double_t g[5] = { 0.01, 0.02, 0.39, 0.68, 0.97 };
1571 Double_t b[5] = { 0.17, 0.39, 0.62, 0.79, 0.97 };
1572 CreateGradientColorTable(5, s, r, g, b, ncol);
1573 found=kTRUE;
1574 }
1575
1576 if (paletteName.Contains("lightblue"))
1577 {
1578 Double_t s[5] = { 0.00, 0.34, 0.61, 0.84, 1.00 };
1579 Double_t r[5] = { 0.00, 0.09, 0.18, 0.09, 0.00 };
1580 Double_t g[5] = { 0.00, 0.02, 0.40, 0.70, 1.00 };
1581 Double_t b[5] = { 0.00, 0.27, 0.51, 0.81, 1.00 };
1582 CreateGradientColorTable(5, s, r, g, b, ncol);
1583 found=kTRUE;
1584 }
1585
1586 if (paletteName.Contains("greyscale"))
1587 {
1588 double s[2] = {0.00, 1.00};
1589 double r[2] = {0.00, 1.00};
1590 double g[2] = {0.00, 1.00};
1591 double b[2] = {0.00, 1.00};
1592 CreateGradientColorTable(2, s, r, g, b, ncol);
1593 found=kTRUE;
1594 }
1595
1596 if (paletteName.Contains("glow1"))
1597 {
1598 double s[5] = {0., 0.10, 0.45, 0.75, 1.00};
1599 double r[5] = {0., 0.35, 0.85, 1.00, 1.00};
1600 double g[5] = {0., 0.10, 0.20, 0.73, 1.00};
1601 double b[5] = {0., 0.03, 0.06, 0.00, 1.00};
1602 CreateGradientColorTable(5, s, r, g, b, ncol);
1603 found=kTRUE;
1604 }
1605
1606 if (paletteName.Contains("glow2"))
1607 {
1608 double s[4] = {0.00, 0.50, 0.75, 1.00};
1609 double r[4] = {0.24, 0.67, 1.00, 1.00};
1610 double g[4] = {0.03, 0.04, 0.80, 1.00};
1611 double b[4] = {0.03, 0.04, 0.00, 1.00};
1612 CreateGradientColorTable(4, s, r, g, b, ncol);
1613 found=kTRUE;
1614 }
1615
1616 if (paletteName.Contains("glowsym"))
1617 {
1618 double s[8] = {0.00, 0.17, 0.39, 0.50, 0.55, 0.72, 0.88, 1.00};
1619 double r[8] = {0.09, 0.18, 0.09, 0.00, 0.35, 0.85, 1.00, 1.00};
1620 double g[8] = {0.70, 0.40, 0.02, 0.00, 0.10, 0.20, 0.73, 1.00};
1621 double b[8] = {0.81, 0.51, 0.27, 0.00, 0.03, 0.06, 0.00, 1.00};
1622 CreateGradientColorTable(8, s, r, g, b, ncol);
1623 found=kTRUE;
1624 }/*
1625 if (paletteName.Contains("glows2"))
1626 {
1627 double s[10] = {0.00, 0.17, 0.35, 0.50, 0.65, 0.73, 0.77, 0.85, 0.92, 1.00};
1628 double r[10] = {0.09, 0.18, 0.09, 0.00, 0.00, 0.20, 0.55, 0.85, 1.00, 1.00};
1629 double g[10] = {0.81, 0.51, 0.27, 0.00, 0.00, 0.05, 0.10, 0.20, 0.73, 1.00};
1630 double b[10] = {0.70, 0.40, 0.02, 0.00, 0.27, 0.40, 0.35, 0.16, 0.03, 1.00};
1631 gStyle->CreateGradientColorTable(10, s, r, g, b, ncol);
1632 found=kTRUE;
1633 }*/
1634
1635 if (paletteName.Contains("redish"))
1636 {
1637 double s[3] = {0., 0.5, 1.};
1638 double r[3] = {0., 1.0, 1.};
1639 double g[3] = {0., 0.0, 1.};
1640 double b[3] = {0., 0.0, 1.};
1641 CreateGradientColorTable(3, s, r, g, b, ncol);
1642 found=kTRUE;
1643 }
1644
1645 if (paletteName.Contains("bluish"))
1646 {
1647 double s[3] = {0., 0.5, 1.};
1648 double r[3] = {0., 0.0, 1.};
1649 double g[3] = {0., 0.0, 1.};
1650 double b[3] = {0., 1.0, 1.};
1651 CreateGradientColorTable(3, s, r, g, b, ncol);
1652 found=kTRUE;
1653 }
1654
1655 if (paletteName.Contains("small1"))
1656 {
1657 double s[4] = {0.00, 0.50, 0.95, 1.};
1658 double r[4] = {0.04, 0.28, 0.98, 1.};
1659 double g[4] = {0.28, 0.93, 0.03, 1.};
1660 double b[4] = {0.79, 0.11, 0.03, 1.};
1661 CreateGradientColorTable(4, s, r, g, b, ncol);
1662 found=kTRUE;
1663 }
1664 if (paletteName.Contains("pepe"))
1665 {
1666 double s[5] = {0.0, 0.6, 0.7, 0.9, 1.0 };
1667 double r[5] = {0.1, 0.1, 1.0, 1.0, 1.0 };
1668 double g[5] = {0.1, 0.1, 0.0, 1.0, 1.0 };
1669 double b[5] = {0.2, 0.7, 0.0, 0.3, 0.9 };
1670 CreateGradientColorTable(5, s, r, g, b, ncol);
1671 found=kTRUE;
1672 }
1673
1674 if (inverse)
1675 {
1676 TArrayI c(ncol);
1677 for (int i=0; i<ncol; i++)
1678 c[ncol-i-1] = gStyle->GetColorPalette(i);
1679 gStyle->SetPalette(ncol, c.GetArray());
1680 }
1681
1682 if (!found)
1683 gLog << warn << "MH::SetPalette: Palette " << paletteName << " unknown... ignored." << endl;
1684}
1685
1686// --------------------------------------------------------------------------
1687//
1688// Unfortunately in TH1::GetObjectInfo the buffer is just 64 characters
1689// which is sometimes to small. This is just a copy of the code but the
1690// buffer has been increased to 128 which should fairly be enough.
1691//
1692// Necessary for root <= 5.22/00
1693//
1694char *MH::GetObjectInfoH(Int_t px, Int_t py, const TH1 &h)
1695{
1696 const TH1 *fH = &h;
1697 const TAxis *fXaxis = h.GetXaxis();
1698 const TAxis *fYaxis = h.GetYaxis();
1699
1700 // Redefines TObject::GetObjectInfo.
1701 // Displays the histogram info (bin number, contents, integral up to bin
1702 // corresponding to cursor position px,py
1703
1704 if (!gPad) return (char*)"";
1705
1706 static char info[128];
1707 Double_t x = gPad->PadtoX(gPad->AbsPixeltoX(px));
1708 Double_t y = gPad->PadtoY(gPad->AbsPixeltoY(py));
1709 Double_t x1 = gPad->PadtoX(gPad->AbsPixeltoX(px+1));
1710 const char *drawOption = fH->GetDrawOption();
1711 Double_t xmin, xmax, uxmin,uxmax;
1712 Double_t ymin, ymax, uymin,uymax;
1713 if (fH->GetDimension() == 2) {
1714 if (gPad->GetView() || strncmp(drawOption,"cont",4) == 0
1715 || strncmp(drawOption,"CONT",4) == 0) {
1716 uxmin=gPad->GetUxmin();
1717 uxmax=gPad->GetUxmax();
1718 xmin = fXaxis->GetBinLowEdge(fXaxis->GetFirst());
1719 xmax = fXaxis->GetBinUpEdge(fXaxis->GetLast());
1720 x = xmin +(xmax-xmin)*(x-uxmin)/(uxmax-uxmin);
1721 uymin=gPad->GetUymin();
1722 uymax=gPad->GetUymax();
1723 ymin = fYaxis->GetBinLowEdge(fYaxis->GetFirst());
1724 ymax = fYaxis->GetBinUpEdge(fYaxis->GetLast());
1725 y = ymin +(ymax-ymin)*(y-uymin)/(uymax-uymin);
1726 }
1727 }
1728 Int_t binx,biny,binmin,binx1;
1729 if (gPad->IsVertical()) {
1730 binx = fXaxis->FindFixBin(x);
1731 binmin = fXaxis->GetFirst();
1732 binx1 = fXaxis->FindFixBin(x1);
1733 // special case if more than 1 bin in x per pixel
1734 if (binx1-binx>1 && fH->GetDimension() == 1) {
1735 Double_t binval=fH->GetBinContent(binx);
1736 Int_t binnear=binx;
1737 for (Int_t ibin=binx+1; ibin<binx1; ibin++) {
1738 Double_t binvaltmp = fH->GetBinContent(ibin);
1739 if (TMath::Abs(y-binvaltmp) < TMath::Abs(y-binval)) {
1740 binval=binvaltmp;
1741 binnear=ibin;
1742 }
1743 }
1744 binx = binnear;
1745 }
1746 } else {
1747 x1 = gPad->PadtoY(gPad->AbsPixeltoY(py+1));
1748 binx = fXaxis->FindFixBin(y);
1749 binmin = fXaxis->GetFirst();
1750 binx1 = fXaxis->FindFixBin(x1);
1751 // special case if more than 1 bin in x per pixel
1752 if (binx1-binx>1 && fH->GetDimension() == 1) {
1753 Double_t binval=fH->GetBinContent(binx);
1754 Int_t binnear=binx;
1755 for (Int_t ibin=binx+1; ibin<binx1; ibin++) {
1756 Double_t binvaltmp = fH->GetBinContent(ibin);
1757 if (TMath::Abs(x-binvaltmp) < TMath::Abs(x-binval)) {
1758 binval=binvaltmp;
1759 binnear=ibin;
1760 }
1761 }
1762 binx = binnear;
1763 }
1764 }
1765 if (fH->GetDimension() == 1) {
1766 Double_t integ = 0;
1767 for (Int_t bin=binmin;bin<=binx;bin++) {integ += fH->GetBinContent(bin);}
1768 sprintf(info,"(x=%g, y=%g, binx=%d, binc=%g, Sum=%g)",x,y,binx,fH->GetBinContent(binx),integ);
1769 } else {
1770 biny = fYaxis->FindFixBin(y);
1771 sprintf(info,"(x=%g, y=%g, binx=%d, biny=%d, binc=%g)",x,y,binx,biny,fH->GetCellContent(binx,biny));
1772 }
1773 return info;
1774}
1775
1776// --------------------------------------------------------------------------
1777//
1778// Unfortunately in TProfile::GetObjectInfo the buffer is just 64 characters
1779// which is sometimes to small. This is just a copy of the code but the
1780// buffer has been increased to 128 which should fairly be enough.
1781//
1782// Necessary for root <= 5.22/00
1783//
1784char *MH::GetObjectInfoP(Int_t px, Int_t py, const TProfile &p)
1785{
1786 if (!gPad) return (char*)"";
1787 static char info[128];
1788 Double_t x = gPad->PadtoX(gPad->AbsPixeltoX(px));
1789 Double_t y = gPad->PadtoY(gPad->AbsPixeltoY(py));
1790 Int_t binx = p.GetXaxis()->FindFixBin(x);
1791 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));
1792 return info;
1793}
1794
1795// --------------------------------------------------------------------------
1796//
1797// Unfortunately TH1::GetObjectInfo and TProfile::GetObjectInfo can
1798// result in buffer ovwerflows therefor we have to re-implement these
1799// function by our own.
1800//
1801// Necessary for root <= 5.22/00
1802//
1803char *MH::GetObjectInfo(Int_t px, Int_t py, const TObject &o)
1804{
1805 if (!o.InheritsFrom(TH1::Class()))
1806 return o.GetObjectInfo(px, py);
1807
1808 if (o.InheritsFrom(TProfile::Class()))
1809 return GetObjectInfoP(px, py, static_cast<const TProfile&>(o));
1810
1811 if (o.InheritsFrom("MHCamera"))
1812 return o.GetObjectInfo(px, py);
1813
1814 if (o.InheritsFrom(TH1::Class()))
1815 return GetObjectInfoH(px, py, static_cast<const TH1&>(o));
1816
1817 return "MH::GetObjectInfo: unknown class.";
1818}
1819
1820// --------------------------------------------------------------------------
1821//
1822// Set the pad-range such that at the smallest width it is still
1823// two times max and that the displayed "pixels" (i.e. its coordinate
1824// system) have the width to height ratio of aspect.
1825//
1826void MH::SetPadRange(Float_t max, Float_t aspect)
1827{
1828 if (!gPad)
1829 return;
1830
1831 const Float_t w = gPad->GetWw();
1832 const Float_t h = gPad->GetWh();
1833
1834 if (w>aspect*h)
1835 {
1836 const Double_t dx = ((w/h-aspect)/2+1)*max;
1837 gPad->Range(-dx, -max, dx, max);
1838 }
1839 else
1840 {
1841 const Double_t dy = ((h/w-1./aspect)/2+1)*max;
1842 gPad->Range(-max, -dy, max, dy);
1843 }
1844}
1845
1846// --------------------------------------------------------------------------
1847//
1848// Set the range of a pad in a way that the coordinates fit into the pad
1849// without abberation.
1850//
1851void MH::SetPadRange(Float_t x0, Float_t y0, Float_t x1, Float_t y1)
1852{
1853 if (!gPad)
1854 return;
1855
1856 const Float_t w = x1-x0; // Width in user coordinates
1857 const Float_t h = y1-y0; // Hieght in user coordinates
1858
1859 const Float_t ww = gPad->GetWw()*gPad->GetAbsWNDC(); // Width of pad in pixels
1860 const Float_t hh = gPad->GetWh()*gPad->GetAbsHNDC(); // Height of pad in pixels
1861
1862 if (ww/hh > w/h)
1863 {
1864 const Double_t dx = (ww/hh-w/h)/2*h;
1865
1866 gPad->Range(x0-dx, y0, x1+dx, y1);
1867 }
1868 else
1869 {
1870 const Double_t dy = (hh/ww-h/w)/2*w;
1871
1872 gPad->Range(x0, y0-dy, x1, y1+dy);
1873 }
1874}
Note: See TracBrowser for help on using the repository browser.