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

Last change on this file since 3945 was 3583, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 34.9 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz 07/2001 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2002
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26// //
27// MH //
28// //
29// This is a base tasks for mars histograms. It defines a common interface //
30// for filling the histograms with events (MH::Fill) which is used by a //
31// common 'filler' And a SetupFill member function which may be used //
32// by MFillH. The idea is: //
33// 1) If your Histogram can become filled by one single container //
34// (like MHHillas) you overload MH::Fill and it gets called with //
35// a pointer to the container with which it should be filled. //
36// //
37// 2) You histogram needs several containers to get filled. Than you //
38// have to overload MH::SetupFill and get the necessary objects from //
39// the parameter list. Use this objects in Fill to fill your //
40// histogram. //
41// //
42// If you want to create your own histogram class the new class must be //
43// derived from MH (instead of the base MParContainer) and you must //
44// the fill function of MH. This is the function which is called to fill //
45// the histogram(s) by the data of a corresponding parameter container. //
46// //
47// Remark: the static member function (eg MakeDefCanvas) can be called //
48// from everywhere using: MH::MakeDefCanvas(...) //
49// //
50//////////////////////////////////////////////////////////////////////////////
51
52#include "MH.h"
53
54#include <TH1.h>
55#include <TH2.h>
56#include <TH3.h>
57#include <TStyle.h> // TStyle::GetScreenFactor
58#include <TGaxis.h>
59#include <TCanvas.h>
60#include <TLegend.h>
61#include <TPaveStats.h>
62#include <TBaseClass.h>
63#if ROOT_VERSION_CODE > ROOT_VERSION(3,04,01)
64#include <THLimitsFinder.h>
65#endif
66
67#include "MLog.h"
68#include "MLogManip.h"
69
70#include "MParList.h"
71#include "MParContainer.h"
72
73#include "MBinning.h"
74
75ClassImp(MH);
76
77using namespace std;
78
79// --------------------------------------------------------------------------
80//
81// Default Constructor. It sets name and title only. Typically you won't
82// need to change this.
83//
84MH::MH(const char *name, const char *title)
85{
86 //
87 // set the name and title of this object
88 //
89 fName = name ? name : "MH";
90 fTitle = title ? title : "Base class for Mars histograms";
91}
92
93// --------------------------------------------------------------------------
94//
95// If you want to use the automatic filling of your derived class you
96// must overload this function. If it is not overloaded you cannot use
97// FillH with this class. The argument is a pointer to a container
98// in your paremeter list which is specified in the MFillH constructor.
99// If you are not going to use it you should at least add
100// Bool_t MH::Fill(const MParContainer *) { return kTRUE; }
101// to your class definition.
102//
103Bool_t MH::Fill(const MParContainer *par, const Stat_t w)
104{
105 *fLog << warn << GetDescriptor() << ": Fill not overloaded! Can't be used!" << endl;
106 return kFALSE;
107}
108
109// --------------------------------------------------------------------------
110//
111// This virtual function is ment as a generalized interface to retrieve
112// a pointer to a root histogram from the MH-derived class.
113//
114TH1 *MH::GetHistByName(const TString name)
115{
116 *fLog << warn << GetDescriptor() << ": GetHistByName not overloaded! Can't be used!" << endl;
117 return NULL;
118}
119
120// --------------------------------------------------------------------------
121//
122// This is a function which should replace the creation of default
123// canvases like root does. Because this is inconvinient in some aspects.
124// need to change this.
125// You can specify a name for the default canvas and a title. Also
126// width and height can be given.
127// MakeDefCanvas looks for a canvas with the given name. If now name is
128// given the DefCanvasName of root is used. If no such canvas is existing
129// it is created and returned. If such a canvas already exists a new canvas
130// with a name plus anumber is created (the number is calculated by the
131// number of all existing canvases plus one)
132//
133// Normally the canvas size is scaled with gStyle->GetScreenFactor() so
134// that on all screens it looks like the same part of the screen.
135// To suppress this scaling use usescreenfactor=kFALSE. In this case
136// you specify directly the size of the embedded pad.
137//
138TCanvas *MH::MakeDefCanvas(TString name, const char *title,
139 UInt_t w, UInt_t h, Bool_t usescreenfactor)
140{
141 const TList *list = (TList*)gROOT->GetListOfCanvases();
142
143 if (name.IsNull())
144 name = gROOT->GetDefCanvasName();
145
146 if (list->FindObject(name))
147 name += Form(" <%d>", list->GetSize()+1);
148
149 if (!usescreenfactor)
150 {
151 const Float_t cx = gStyle->GetScreenFactor();
152 w += 4;
153 h += 28;
154 w = (int)(w/cx+1);
155 h = (int)(h/cx+1);
156 }
157
158 return new TCanvas(name, title, w, h);
159}
160
161// --------------------------------------------------------------------------
162//
163// This function works like MakeDefCanvas(name, title, w, h) but name
164// and title are retrieved from the given TObject.
165//
166// Normally the canvas size is scaled with gStyle->GetScreenFactor() so
167// that on all screens it looks like the same part of the screen.
168// To suppress this scaling use usescreenfactor=kFALSE. In this case
169// you specify directly the size of the embedded pad.
170//
171TCanvas *MH::MakeDefCanvas(const TObject *obj,
172 UInt_t w, UInt_t h, Bool_t usescreenfactor)
173{
174 if (!usescreenfactor)
175 {
176 const Float_t cx = gStyle->GetScreenFactor();
177 w += 4;
178 h += 28;
179 h = (int)(h/cx+1);
180 w = (int)(w/cx+1);
181 }
182
183 return MakeDefCanvas(obj->GetName(), obj->GetTitle(), w, h);
184}
185
186// --------------------------------------------------------------------------
187//
188// Applies a given binning to a 1D-histogram
189//
190void MH::SetBinning(TH1 *h, const MBinning *binsx)
191{
192 //
193 // Another strange behaviour: TAxis::Set deletes the axis title!
194 //
195 TAxis &x = *h->GetXaxis();
196
197#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
198 TString xtitle = x.GetTitle();
199#endif
200
201 //
202 // This is a necessary workaround if one wants to set
203 // non-equidistant bins after the initialization
204 // TH1D::fNcells must be set correctly.
205 //
206 h->SetBins(binsx->GetNumBins(), 0, 1);
207
208 //
209 // Set the binning of the current histogram to the binning
210 // in one of the two given histograms
211 //
212 x.Set(binsx->GetNumBins(), binsx->GetEdges());
213#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
214 x.SetTitle(xtitle);
215#endif
216}
217
218// --------------------------------------------------------------------------
219//
220// Applies given binnings to the two axis of a 2D-histogram
221//
222void MH::SetBinning(TH2 *h, const MBinning *binsx, const MBinning *binsy)
223{
224 TAxis &x = *h->GetXaxis();
225 TAxis &y = *h->GetYaxis();
226
227 //
228 // Another strange behaviour: TAxis::Set deletes the axis title!
229 //
230#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
231 TString xtitle = x.GetTitle();
232 TString ytitle = y.GetTitle();
233#endif
234
235 //
236 // This is a necessary workaround if one wants to set
237 // non-equidistant bins after the initialization
238 // TH1D::fNcells must be set correctly.
239 //
240 h->SetBins(binsx->GetNumBins(), 0, 1,
241 binsy->GetNumBins(), 0, 1);
242
243 //
244 // Set the binning of the current histogram to the binning
245 // in one of the two given histograms
246 //
247 x.Set(binsx->GetNumBins(), binsx->GetEdges());
248 y.Set(binsy->GetNumBins(), binsy->GetEdges());
249#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
250 x.SetTitle(xtitle);
251 y.SetTitle(ytitle);
252#endif
253}
254
255// --------------------------------------------------------------------------
256//
257// Applies given binnings to the three axis of a 3D-histogram
258//
259void MH::SetBinning(TH3 *h, const MBinning *binsx, const MBinning *binsy, const MBinning *binsz)
260{
261 //
262 // Another strange behaviour: TAxis::Set deletes the axis title!
263 //
264 TAxis &x = *h->GetXaxis();
265 TAxis &y = *h->GetYaxis();
266 TAxis &z = *h->GetZaxis();
267
268#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
269 TString xtitle = x.GetTitle();
270 TString ytitle = y.GetTitle();
271 TString ztitle = z.GetTitle();
272#endif
273
274 //
275 // This is a necessary workaround if one wants to set
276 // non-equidistant bins after the initialization
277 // TH1D::fNcells must be set correctly.
278 //
279 h->SetBins(binsx->GetNumBins(), 0, 1,
280 binsy->GetNumBins(), 0, 1,
281 binsz->GetNumBins(), 0, 1);
282
283 //
284 // Set the binning of the current histogram to the binning
285 // in one of the two given histograms
286 //
287 x.Set(binsx->GetNumBins(), binsx->GetEdges());
288 y.Set(binsy->GetNumBins(), binsy->GetEdges());
289 z.Set(binsz->GetNumBins(), binsz->GetEdges());
290#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
291 x.SetTitle(xtitle);
292 y.SetTitle(ytitle);
293 z.SetTitle(ztitle);
294#endif
295}
296
297// --------------------------------------------------------------------------
298//
299// Applies given binning (the n+1 edges) to the axis of a 1D-histogram
300//
301void MH::SetBinning(TH1 *h, const TArrayD &binsx)
302{
303 MBinning bx;
304 bx.SetEdges(binsx);
305 SetBinning(h, &bx);
306}
307
308// --------------------------------------------------------------------------
309//
310// Applies given binning (the n+1 edges) to the two axis of a
311// 2D-histogram
312//
313void MH::SetBinning(TH2 *h, const TArrayD &binsx, const TArrayD &binsy)
314{
315 MBinning bx;
316 MBinning by;
317 bx.SetEdges(binsx);
318 by.SetEdges(binsy);
319 SetBinning(h, &bx, &by);
320}
321
322// --------------------------------------------------------------------------
323//
324// Applies given binning (the n+1 edges) to the three axis of a
325// 3D-histogram
326//
327void MH::SetBinning(TH3 *h, const TArrayD &binsx, const TArrayD &binsy, const TArrayD &binsz)
328{
329 MBinning bx;
330 MBinning by;
331 MBinning bz;
332 bx.SetEdges(binsx);
333 by.SetEdges(binsy);
334 bz.SetEdges(binsz);
335 SetBinning(h, &bx, &by, &bz);
336}
337
338// --------------------------------------------------------------------------
339//
340// Applies the binning of a TAxis (eg from a root histogram) to the axis
341// of a 1D-histogram
342//
343void MH::SetBinning(TH1 *h, const TAxis *binsx)
344{
345 const Int_t nx = binsx->GetNbins();
346
347 TArrayD bx(nx+1);
348 for (int i=0; i<nx; i++) bx[i] = binsx->GetBinLowEdge(i+1);
349 bx[nx] = binsx->GetXmax();
350
351 SetBinning(h, bx);
352}
353
354// --------------------------------------------------------------------------
355//
356// Applies the binnings of the TAxis' (eg from a root histogram) to the
357// two axis' of a 2D-histogram
358//
359void MH::SetBinning(TH2 *h, const TAxis *binsx, const TAxis *binsy)
360{
361 const Int_t nx = binsx->GetNbins();
362 const Int_t ny = binsy->GetNbins();
363
364 TArrayD bx(nx+1);
365 TArrayD by(ny+1);
366 for (int i=0; i<nx; i++) bx[i] = binsx->GetBinLowEdge(i+1);
367 for (int i=0; i<ny; i++) by[i] = binsy->GetBinLowEdge(i+1);
368 bx[nx] = binsx->GetXmax();
369 by[ny] = binsy->GetXmax();
370
371 SetBinning(h, bx, by);
372}
373
374// --------------------------------------------------------------------------
375//
376// Applies the binnings of the TAxis' (eg from a root histogram) to the
377// three axis' of a 3D-histogram
378//
379void MH::SetBinning(TH3 *h, const TAxis *binsx, const TAxis *binsy, const TAxis *binsz)
380{
381 const Int_t nx = binsx->GetNbins();
382 const Int_t ny = binsy->GetNbins();
383 const Int_t nz = binsz->GetNbins();
384
385 TArrayD bx(nx+1);
386 TArrayD by(ny+1);
387 TArrayD bz(nz+1);
388 for (int i=0; i<nx; i++) bx[i] = binsx->GetBinLowEdge(i+1);
389 for (int i=0; i<ny; i++) by[i] = binsy->GetBinLowEdge(i+1);
390 for (int i=0; i<nz; i++) bz[i] = binsz->GetBinLowEdge(i+1);
391 bx[nx] = binsx->GetXmax();
392 by[ny] = binsy->GetXmax();
393 bz[nz] = binsz->GetXmax();
394
395 SetBinning(h, bx, by, bz);
396}
397
398// --------------------------------------------------------------------------
399//
400// Applies the binnings of one root-histogram x to another one h
401// Both histograms must be of the same type: TH1, TH2 or TH3
402//
403void MH::SetBinning(TH1 *h, const TH1 *x)
404{
405 if (h->InheritsFrom(TH3::Class()) && x->InheritsFrom(TH3::Class()))
406 {
407 SetBinning((TH3*)h, ((TH1*)x)->GetXaxis(), ((TH1*)x)->GetYaxis(), ((TH1*)x)->GetZaxis());
408 return;
409 }
410 if (h->InheritsFrom(TH3::Class()) || x->InheritsFrom(TH3::Class()))
411 return;
412 if (h->InheritsFrom(TH2::Class()) && x->InheritsFrom(TH2::Class()))
413 {
414 SetBinning((TH2*)h, ((TH1*)x)->GetXaxis(), ((TH1*)x)->GetYaxis());
415 return;
416 }
417 if (h->InheritsFrom(TH2::Class()) || x->InheritsFrom(TH2::Class()))
418 return;
419 if (h->InheritsFrom(TH1::Class()) && x->InheritsFrom(TH1::Class()))
420 {
421 SetBinning(h, ((TH1*)x)->GetXaxis());
422 return;
423 }
424}
425
426// --------------------------------------------------------------------------
427//
428// Multiplies all entries in a TArrayD by a float f
429//
430void MH::ScaleArray(TArrayD &bins, Double_t f)
431{
432 for (int i=0; i<bins.GetSize(); i++)
433 bins[i] *= f;
434}
435
436// --------------------------------------------------------------------------
437//
438// Scales the binning of a TAxis by a float f
439//
440TArrayD MH::ScaleAxis(TAxis &axe, Double_t f)
441{
442 TArrayD arr(axe.GetNbins()+1);
443
444 for (int i=1; i<=axe.GetNbins()+1; i++)
445 arr[i-1] = axe.GetBinLowEdge(i);
446
447 ScaleArray(arr, f);
448
449 return arr;
450}
451
452// --------------------------------------------------------------------------
453//
454// Scales the binning of one, two or three axis of a histogram by a float f
455//
456void MH::ScaleAxis(TH1 *h, Double_t fx, Double_t fy, Double_t fz)
457{
458 if (h->InheritsFrom(TH3::Class()))
459 {
460 SetBinning((TH3*)h,
461 ScaleAxis(*h->GetXaxis(), fx),
462 ScaleAxis(*h->GetYaxis(), fy),
463 ScaleAxis(*h->GetZaxis(), fz));
464 return;
465 }
466
467 if (h->InheritsFrom(TH2::Class()))
468 {
469 SetBinning((TH2*)h,
470 ScaleAxis(*h->GetXaxis(), fx),
471 ScaleAxis(*h->GetYaxis(), fy));
472 return;
473 }
474
475 if (h->InheritsFrom(TH1::Class()))
476 SetBinning(h, ScaleAxis(*h->GetXaxis(), fx));
477}
478
479// --------------------------------------------------------------------------
480//
481// Tries to find a MBinning container with the name "Binning"+name
482// in the given parameter list. If it was found it is applied to the
483// given histogram. This is only valid for 1D-histograms
484//
485Bool_t MH::ApplyBinning(const MParList &plist, TString name, TH1 *h)
486{
487 if (h->InheritsFrom(TH2::Class()) || h->InheritsFrom(TH3::Class()))
488 {
489 gLog << warn << "MH::ApplyBinning: '" << h->GetName() << "' is not a basic TH1 object... no binning applied." << endl;
490 return kFALSE;
491 }
492
493 const MBinning *bins = (MBinning*)plist.FindObject("Binning"+name);
494 if (!bins)
495 {
496 gLog << inf << "Object 'Binning" << name << "' [MBinning] not found... no binning applied." << endl;
497 return kFALSE;
498 }
499
500 SetBinning(h, bins);
501 return kTRUE;
502}
503
504void MH::FindGoodLimits(Int_t nbins, Int_t &newbins, Double_t &xmin, Double_t &xmax, Bool_t isInteger)
505{
506#if ROOT_VERSION_CODE > ROOT_VERSION(3,04,01)
507 THLimitsFinder::OptimizeLimits(nbins, newbins, xmin, xmax, isInteger);
508#else
509//*-*-*-*-*-*-*-*-*Find reasonable bin values*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
510//*-* ==========================
511
512 Double_t dx = 0.1*(xmax-xmin);
513 Double_t umin = xmin - dx;
514 Double_t umax = xmax + dx;
515
516 if (umin < 0 && xmin >= 0)
517 umin = 0;
518
519 if (umax > 0 && xmax <= 0)
520 umax = 0;
521
522 Double_t binlow =0;
523 Double_t binhigh =0;
524 Double_t binwidth=0;
525
526 TGaxis::Optimize(umin, umax, nbins, binlow, binhigh, nbins, binwidth, "");
527
528 if (binwidth <= 0 || binwidth > 1.e+39)
529 {
530 xmin = -1;
531 xmax = 1;
532 }
533 else
534 {
535 xmin = binlow;
536 xmax = binhigh;
537 }
538
539 if (isInteger)
540 {
541 Int_t ixmin = (Int_t)xmin;
542 Int_t ixmax = (Int_t)xmax;
543 Double_t dxmin = (Double_t)ixmin;
544 Double_t dxmax = (Double_t)ixmax;
545
546 xmin = xmin<0 && xmin!=dxmin ? dxmin - 1 : dxmin;
547 xmax = xmax>0 && xmax!=dxmax ? dxmax + 1 : dxmax;
548
549 if (xmin>=xmax)
550 xmax = xmin+1;
551
552 Int_t bw = 1 + (Int_t)((xmax-xmin)/nbins);
553
554 nbins = (Int_t)((xmax-xmin)/bw);
555
556 if (xmin+nbins*bw < xmax)
557 {
558 nbins++;
559 xmax = xmin +nbins*bw;
560 }
561 }
562
563 newbins = nbins;
564#endif
565}
566
567// --------------------------------------------------------------------------
568//
569// Returns the lowest entry in a histogram which is greater than gt (eg >0)
570//
571Double_t MH::GetMinimumGT(const TH1 &h, Double_t gt)
572{
573 Double_t min = FLT_MAX;
574
575 const TAxis &axex = *((TH1&)h).GetXaxis();
576 const TAxis &axey = *((TH1&)h).GetYaxis();
577 const TAxis &axez = *((TH1&)h).GetZaxis();
578
579 for (int iz=1; iz<=axez.GetNbins(); iz++)
580 for (int iy=1; iy<=axey.GetNbins(); iy++)
581 for (int ix=1; ix<=axex.GetNbins(); ix++)
582 {
583 const Double_t v = h.GetBinContent(h.GetBin(ix, iy, iz));
584 if (gt<v && v<min)
585 min = v;
586 }
587 return min;
588}
589
590// --------------------------------------------------------------------------
591//
592// Returns the bin center in a logarithmic scale. If the given bin
593// number is <1 it is set to 1. If it is =GetNbins() it is set to
594// GetNbins()
595//
596Double_t MH::GetBinCenterLog(const TAxis &axe, Int_t nbin)
597{
598 if (nbin>axe.GetNbins())
599 nbin = axe.GetNbins();
600
601 if (nbin<1)
602 nbin = 1;
603
604 const Double_t lo = axe.GetBinLowEdge(nbin);
605 const Double_t hi = axe.GetBinUpEdge(nbin);
606
607 const Double_t val = log10(lo) + log10(hi);
608
609 return pow(10, val/2);
610}
611
612// --------------------------------------------------------------------------
613//
614// Draws a copy of the two given histograms. Uses title as the pad title.
615// Also layout the two statistic boxes and a legend.
616//
617void MH::DrawSameCopy(const TH1 &hist1, const TH1 &hist2, const TString title)
618{
619 //
620 // Draw first histogram
621 //
622 TH1 *h1 = ((TH1&)hist1).DrawCopy();
623 gPad->SetBorderMode(0);
624 gPad->Update();
625
626 // FIXME: Also align max/min with set Maximum/Minimum
627 const Double_t maxbin1 = hist1.GetBinContent(hist1.GetMaximumBin());
628 const Double_t maxbin2 = hist2.GetBinContent(hist2.GetMaximumBin());
629 const Double_t minbin1 = hist1.GetBinContent(hist1.GetMinimumBin());
630 const Double_t minbin2 = hist2.GetBinContent(hist2.GetMinimumBin());
631
632 const Double_t max = TMath::Max(maxbin1, maxbin2);
633 const Double_t min = TMath::Min(minbin1, minbin2);
634
635 h1->SetMaximum(max>0?max*1.05:max*0.95);
636 h1->SetMinimum(max>0?min*0.95:min*1.05);
637
638 TPaveText *t = (TPaveText*)gPad->FindObject("title");
639 if (t)
640 {
641 t->SetName((TString)"MHTitle"); // rename object
642 t->Clear(); // clear old lines
643 t->AddText((TString)" "+title+" "); // add the new title
644 t->SetBit(kCanDelete); // make sure object is deleted
645
646 //
647 // FIXME: This is a stupid workaround to hide the redrawn
648 // (see THistPainter::PaintTitle) title
649 //
650 gPad->Modified(); // indicates a change
651 gPad->Update(); // recreates the original title
652 t->Pop(); // bring our title on top
653 }
654
655 //
656 // Rename first statistics box
657 //
658 TPaveStats *s1 = (TPaveStats*)gPad->FindObject("stats");
659 if (!s1)
660 s1 = (TPaveStats*)hist1.GetListOfFunctions()->FindObject("stats");
661 else
662 s1->SetName((TString)"Stat"+hist1.GetTitle());
663
664 if (s1 && s1->GetX2NDC()>0.95)
665 {
666 const Double_t x1 = s1->GetX1NDC()-0.01;
667 s1->SetX1NDC(x1-(s1->GetX2NDC()-s1->GetX1NDC()));
668 s1->SetX2NDC(x1);
669 }
670
671 //
672 // Draw second histogram
673 //
674 TH1 *h2 = ((TH1&)hist2).DrawCopy("sames");
675 gPad->Update();
676
677 //
678 // Draw Legend
679 //
680 TPaveStats *s2 = (TPaveStats*)gPad->FindObject("stats");
681 if (!s2)
682 s2 = (TPaveStats*)hist2.GetListOfFunctions()->FindObject("stats");
683
684 if (s2)
685 {
686 TLegend &l = *new TLegend(s2->GetX1NDC(),
687 s2->GetY1NDC()-0.015-(s2->GetY2NDC()-s2->GetY1NDC())/2,
688 s2->GetX2NDC(),
689 s2->GetY1NDC()-0.01
690 );
691 l.AddEntry(h1, h1->GetTitle());
692 l.AddEntry(h2, h2->GetTitle());
693 l.SetTextSize(s2->GetTextSize());
694 l.SetTextFont(s2->GetTextFont());
695 l.SetBorderSize(s2->GetBorderSize());
696 l.SetBit(kCanDelete);
697 l.Draw();
698 }
699}
700
701// --------------------------------------------------------------------------
702//
703// Draws the two given histograms. Uses title as the pad title.
704// Also layout the two statistic boxes and a legend.
705//
706void MH::DrawSame(TH1 &hist1, TH1 &hist2, const TString title)
707{
708 //
709 // Draw first histogram
710 //
711 hist1.Draw();
712 gPad->SetBorderMode(0);
713 gPad->Update();
714
715 if (hist1.GetEntries()>0 && hist2.GetEntries()>0)
716 {
717 const Double_t maxbin1 = hist1.GetBinContent(hist1.GetMaximumBin());
718 const Double_t maxbin2 = hist2.GetBinContent(hist2.GetMaximumBin());
719 const Double_t minbin1 = hist1.GetBinContent(hist1.GetMinimumBin());
720 const Double_t minbin2 = hist2.GetBinContent(hist2.GetMinimumBin());
721
722 const Double_t max = TMath::Max(maxbin1, maxbin2);
723 const Double_t min = TMath::Min(minbin1, minbin2);
724
725 if (max!=min)
726 {
727 hist1.SetMaximum(max>0?max*1.05:max*0.95);
728 hist1.SetMinimum(max>0?min*0.95:min*1.05);
729 }
730 }
731
732 TPaveText *t = (TPaveText*)gPad->FindObject("title");
733 if (t)
734 {
735 t->SetName((TString)"MHTitle"); // rename object
736 t->Clear(); // clear old lines
737 t->AddText((TString)" "+title+" "); // add the new title
738 t->SetBit(kCanDelete); // make sure object is deleted
739
740 //
741 // FIXME: This is a stupid workaround to hide the redrawn
742 // (see THistPainter::PaintTitle) title
743 //
744 gPad->Modified(); // indicates a change
745 gPad->Update(); // recreates the original title
746 t->Pop(); // bring our title on top
747 }
748
749 //
750 // Rename first statistics box
751 //
752 // Where to get the TPaveStats depends on the root version
753 TPaveStats *s1 = (TPaveStats*)gPad->FindObject("stats");
754 if (!s1)
755 s1 = (TPaveStats*)hist1.GetListOfFunctions()->FindObject("stats");
756 else
757 s1->SetName((TString)"Stat"+hist1.GetTitle());
758
759 if (s1 && s1->GetX2NDC()>0.95)
760 {
761 const Double_t x1 = s1->GetX1NDC()-0.01;
762 s1->SetX1NDC(x1-(s1->GetX2NDC()-s1->GetX1NDC()));
763 s1->SetX2NDC(x1);
764 }
765
766 //
767 // Draw second histogram
768 //
769 hist2.Draw("sames");
770 gPad->Update();
771
772 //
773 // Draw Legend
774 //
775 // Where to get the TPaveStats depends on the root version
776 TPaveStats *s2 = (TPaveStats*)gPad->FindObject("stats");
777 if (!s2)
778 s2 = (TPaveStats*)hist2.GetListOfFunctions()->FindObject("stats");
779
780 if (s2)
781 {
782 TLegend &l = *new TLegend(s2->GetX1NDC(),
783 s2->GetY1NDC()-0.015-(s2->GetY2NDC()-s2->GetY1NDC())/2,
784 s2->GetX2NDC(),
785 s2->GetY1NDC()-0.01
786 );
787 l.AddEntry(&hist1, hist1.GetTitle());
788 l.AddEntry(&hist2, hist2.GetTitle());
789 l.SetTextSize(s2->GetTextSize());
790 l.SetTextFont(s2->GetTextFont());
791 l.SetBorderSize(s2->GetBorderSize());
792 l.SetBit(kCanDelete);
793 l.Draw();
794 }
795}
796
797// --------------------------------------------------------------------------
798//
799// If the opt string contains 'nonew' or gPad is not given NULL is returned.
800// Otherwise the present gPad is returned.
801//
802TVirtualPad *MH::GetNewPad(TString &opt)
803{
804 opt.ToLower();
805
806 if (!opt.Contains("nonew"))
807 return NULL;
808
809 opt.ReplaceAll("nonew", "");
810
811 return gPad;
812}
813
814// --------------------------------------------------------------------------
815//
816// Encapsulate the TObject::Clone such, that a cloned TH1 (or derived)
817// object is not added to the current directory, when cloned.
818//
819TObject *MH::Clone(const char *name) const
820{
821 const Bool_t store = TH1::AddDirectoryStatus();
822
823 TH1::AddDirectory(kFALSE);
824 TObject *o = MParContainer::Clone(name);
825 TH1::AddDirectory(store);
826
827 return o;
828}
829
830// --------------------------------------------------------------------------
831//
832// If the opt string contains 'nonew' or gPad is not given a new canvas
833// with size w/h is created. Otherwise the object is cloned and drawn
834// to the present pad. The kCanDelete bit is set for the clone.
835//
836TObject *MH::DrawClone(Option_t *opt, Int_t w, Int_t h) const
837{
838 TString option(opt);
839
840 TVirtualPad *p = GetNewPad(option);
841 if (!p)
842 p = MakeDefCanvas(this, w, h);
843 else
844 if (!option.Contains("same", TString::kIgnoreCase))
845 p->Clear();
846
847 gROOT->SetSelectedPad(NULL);
848
849 TObject *o = MParContainer::DrawClone(option);
850 o->SetBit(kCanDelete);
851 return o;
852}
853
854// --------------------------------------------------------------------------
855//
856// Check whether a class inheriting from MH overwrites the Draw function
857//
858Bool_t MH::OverwritesDraw(TClass *cls) const
859{
860 if (!cls)
861 cls = IsA();
862
863 //
864 // Check whether we reached the base class MTask
865 //
866 if (TString(cls->GetName())=="MH")
867 return kFALSE;
868
869 //
870 // Check whether the class cls overwrites Draw
871 //
872 if (cls->GetMethodAny("Draw"))
873 return kTRUE;
874
875 //
876 // If the class itself doesn't overload it check all it's base classes
877 //
878 TBaseClass *base=NULL;
879 TIter NextBase(cls->GetListOfBases());
880 while ((base=(TBaseClass*)NextBase()))
881 {
882 if (OverwritesDraw(base->GetClassPointer()))
883 return kTRUE;
884 }
885
886 return kFALSE;
887}
888
889// --------------------------------------------------------------------------
890//
891// Cuts the bins containing only zeros at the edges.
892//
893// A new number of bins can be defined with nbins != 0
894// In the case of nbins == 0, no rebinning will take place
895//
896// Returns the new (real) number of bins
897//
898Int_t MH::StripZeros(TH1 *h, Int_t nbins)
899{
900 TAxis &axe = *h->GetXaxis();
901
902 const Int_t min1 = axe.GetFirst();
903 const Int_t max1 = axe.GetLast();
904 const Int_t range1 = max1-min1;
905
906 //
907 // Check for useless zeros
908 //
909 if (range1 == 0)
910 return 0;
911
912 Int_t min2 = 0;
913 for (int i=min1; i<=max1; i++)
914 if (h->GetBinContent(i) != 0)
915 {
916 min2 = i;
917 break;
918 }
919
920 //
921 // If the histogram consists of zeros only
922 //
923 if (min2 == max1)
924 return 0;
925
926 Int_t max2 = 0;
927 for (int i=max1; i>=min2; i--)
928 if (h->GetBinContent(i) != 0)
929 {
930 max2 = i;
931 break;
932 }
933
934 //
935 // Appying TAxis->SetRange before ReBin does not work ...
936 // But this workaround helps quite fine
937 //
938 Axis_t min = h->GetBinLowEdge(min2);
939 Axis_t max = h->GetBinLowEdge(max2)+h->GetBinWidth(max2);
940
941 Int_t nbins2 = max2-min2;
942 //
943 // Check for rebinning
944 //
945 if (nbins > 0)
946 {
947 const Int_t ngroup = (Int_t)(nbins2*h->GetNbinsX()/nbins/(max1-min1));
948 if (ngroup > 1)
949 {
950 h->Rebin(ngroup);
951 nbins2 /= ngroup;
952 }
953 }
954
955 Int_t newbins = 0;
956 FindGoodLimits(nbins2, newbins, min, max, kFALSE);
957 axe.SetRangeUser(min,max);
958 return axe.GetLast()-axe.GetFirst();
959}
960
961void MH::ProjectionX(TH1D &dest, const TH2 &src, Int_t firstybin, Int_t lastybin)
962{
963 //*-*-*-*-*Project a 2-D histogram into a 1-D histogram along X*-*-*-*-*-*-*
964 //*-* ====================================================
965 //
966 // The projection dest is always of the type TH1D.
967 // The projection is made from the channels along the Y axis
968 // ranging from firstybin to lastybin included.
969 // By default, bins 1 to ny are included
970 // When all bins are included, the number of entries in the projection
971 // is set to the number of entries of the 2-D histogram, otherwise
972 // the number of entries is incremented by 1 for all non empty cells.
973 //
974 // if Sumw2() was called for dest, the errors are computed.
975 //
976 TAxis &axex = *((TH2&)src).GetXaxis();
977 TAxis &axey = *((TH2&)src).GetYaxis();
978
979 const Int_t nx = axex.GetNbins();
980 const Int_t ny = axey.GetNbins();
981 if (firstybin < 0)
982 firstybin = 1;
983 if (lastybin > ny)
984 lastybin = ny;
985
986 dest.Reset();
987 SetBinning(&dest, &axex);
988
989 // Create the projection histogram
990 const Bool_t computeErrors = dest.GetSumw2N() ? 1 : 0;
991
992 // Fill the projected histogram
993 for (Int_t binx=0; binx<=nx+1; binx++)
994 {
995 Double_t err2 = 0;
996 for (Int_t biny=firstybin; biny<=lastybin; biny++)
997 {
998 const Double_t cont = src.GetCellContent(binx,biny);
999 const Double_t err1 = src.GetCellError(binx,biny);
1000 err2 += err1*err1;
1001 if (cont)
1002 dest.Fill(axex.GetBinCenter(binx), cont);
1003 }
1004 if (computeErrors)
1005 dest.SetBinError(binx, TMath::Sqrt(err2));
1006 }
1007 if (firstybin <=1 && lastybin >= ny)
1008 dest.SetEntries(src.GetEntries());
1009}
1010
1011void MH::ProjectionY(TH1D &dest, const TH2 &src, Int_t firstxbin, Int_t lastxbin)
1012{
1013 //*-*-*-*-*Project a 2-D histogram into a 1-D histogram along X*-*-*-*-*-*-*
1014 //*-* ====================================================
1015 //
1016 // The projection dest is always of the type TH1D.
1017 // The projection is made from the channels along the Y axis
1018 // ranging from firstybin to lastybin included.
1019 // By default, bins 1 to ny are included
1020 // When all bins are included, the number of entries in the projection
1021 // is set to the number of entries of the 2-D histogram, otherwise
1022 // the number of entries is incremented by 1 for all non empty cells.
1023 //
1024 // if Sumw2() was called for dest, the errors are computed.
1025 //
1026 TAxis &axex = *((TH2&)src).GetXaxis();
1027 TAxis &axey = *((TH2&)src).GetYaxis();
1028
1029 const Int_t nx = axex.GetNbins();
1030 const Int_t ny = axey.GetNbins();
1031 if (firstxbin < 0)
1032 firstxbin = 1;
1033 if (lastxbin > nx)
1034 lastxbin = nx;
1035
1036 dest.Reset();
1037 SetBinning(&dest, &axey);
1038
1039 // Create the projection histogram
1040 const Bool_t computeErrors = dest.GetSumw2N() ? 1 : 0;
1041
1042 // Fill the projected histogram
1043 for (Int_t biny=0; biny<=ny+1; biny++)
1044 {
1045 Double_t err2 = 0;
1046 for (Int_t binx=firstxbin; binx<=lastxbin; binx++)
1047 {
1048 const Double_t cont = src.GetCellContent(binx,biny);
1049 const Double_t err1 = src.GetCellError(binx,biny);
1050 err2 += err1*err1;
1051 if (cont)
1052 dest.Fill(axey.GetBinCenter(biny), cont);
1053 }
1054 if (computeErrors)
1055 dest.SetBinError(biny, TMath::Sqrt(err2));
1056 }
1057 if (firstxbin <=1 && lastxbin >= nx)
1058 dest.SetEntries(src.GetEntries());
1059}
1060
1061// --------------------------------------------------------------------------
1062//
1063// In contradiction to TPad::FindObject this function searches recursively
1064// in a pad for an object. gPad is the default.
1065//
1066TObject *MH::FindObjectInPad(const char *name, TVirtualPad *pad)
1067{
1068 if (!pad)
1069 pad = gPad;
1070
1071 if (!pad)
1072 return NULL;
1073
1074 TObject *o;
1075
1076 TIter Next(pad->GetListOfPrimitives());
1077 while ((o=Next()))
1078 {
1079 if (!strcmp(o->GetName(), name))
1080 return o;
1081
1082 if (o->InheritsFrom("TPad"))
1083 if ((o = FindObjectInPad(name, (TVirtualPad*)o)))
1084 return o;
1085 }
1086 return NULL;
1087}
1088
1089// --------------------------------------------------------------------------
1090//
1091// M.Gaug added this withouz Documentation
1092//
1093TH1I* MH::ProjectArray(const TArrayF &array, Int_t nbins, const char* name, const char* title)
1094{
1095 const Int_t size = array.GetSize();
1096
1097 TH1I *h1=0;
1098
1099 //check if histogram with identical name exist
1100 TObject *h1obj = gROOT->FindObject(name);
1101 if (h1obj && h1obj->InheritsFrom("TH1I"))
1102 {
1103 h1 = (TH1I*)h1obj;
1104 h1->Reset();
1105 }
1106
1107 Double_t min = size>0 ? array[0] : 0;
1108 Double_t max = size>0 ? array[0] : 1;
1109
1110 // first loop over array to find the min and max
1111 for (Int_t i=1; i<size;i++)
1112 {
1113 max = TMath::Max((Double_t)array[i], max);
1114 min = TMath::Min((Double_t)array[i], min);
1115 }
1116
1117 Int_t newbins = 0;
1118 FindGoodLimits(nbins, newbins, min, max, kFALSE);
1119
1120 if (!h1)
1121 {
1122 h1 = new TH1I(name, title, nbins, min, max);
1123 h1->SetXTitle("");
1124 h1->SetYTitle("Counts");
1125 h1->SetDirectory(gROOT);
1126 }
1127
1128 // Second loop to fill the histogram
1129 for (Int_t i=0;i<size;i++)
1130 h1->Fill(array[i]);
1131
1132 return h1;
1133}
1134
1135// --------------------------------------------------------------------------
1136//
1137// M.Gaug added this withouz Documentation
1138//
1139TH1I* MH::ProjectArray(const TArrayD &array, Int_t nbins, const char* name, const char* title)
1140{
1141 const Int_t size = array.GetSize();
1142 TH1I *h1=0;
1143
1144 //check if histogram with identical name exist
1145 TObject *h1obj = gROOT->FindObject(name);
1146 if (h1obj && h1obj->InheritsFrom("TH1I"))
1147 {
1148 h1 = (TH1I*)h1obj;
1149 h1->Reset();
1150 }
1151
1152 Double_t min = size>0 ? array[0] : 0;
1153 Double_t max = size>0 ? array[0] : 1;
1154
1155 // first loop over array to find the min and max
1156 for (Int_t i=1; i<size;i++)
1157 {
1158 max = TMath::Max(array[i], max);
1159 min = TMath::Min(array[i], min);
1160 }
1161
1162 Int_t newbins = 0;
1163 FindGoodLimits(nbins, newbins, min, max, kFALSE);
1164
1165 if (!h1)
1166 {
1167 h1 = new TH1I(name, title, newbins, min, max);
1168 h1->SetXTitle("");
1169 h1->SetYTitle("Counts");
1170 h1->SetDirectory(gROOT);
1171 }
1172
1173 // Second loop to fill the histogram
1174 for (Int_t i=0;i<size;i++)
1175 h1->Fill(array[i]);
1176
1177 return h1;
1178}
1179
Note: See TracBrowser for help on using the repository browser.