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

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