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

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