source: trunk/MagicSoft/Mars/mhist/MH.cc@ 2572

Last change on this file since 2572 was 2530, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 32.3 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz 07/2001 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-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 << warn << "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 &axe = *((TH1&)h).GetXaxis();
576
577 for (int i=1; i<=axe.GetNbins(); i++)
578 {
579 Double_t x = h.GetBinContent(i);
580 if (gt<x && x<min)
581 min = x;
582 }
583 return min;
584}
585
586// --------------------------------------------------------------------------
587//
588// Returns the bin center in a logarithmic scale. If the given bin
589// number is <1 it is set to 1. If it is =GetNbins() it is set to
590// GetNbins()
591//
592Double_t MH::GetBinCenterLog(const TAxis &axe, Int_t nbin)
593{
594 if (nbin>axe.GetNbins())
595 nbin = axe.GetNbins();
596
597 if (nbin<1)
598 nbin = 1;
599
600 const Double_t lo = axe.GetBinLowEdge(nbin);
601 const Double_t hi = axe.GetBinUpEdge(nbin);
602
603 const Double_t val = log10(lo) + log10(hi);
604
605 return pow(10, val/2);
606}
607
608// --------------------------------------------------------------------------
609//
610// Draws a copy of the two given histograms. Uses title as the pad title.
611// Also layout the two statistic boxes and a legend.
612//
613void MH::DrawSameCopy(const TH1 &hist1, const TH1 &hist2, const TString title)
614{
615 //
616 // Draw first histogram
617 //
618 TH1 *h1 = ((TH1&)hist1).DrawCopy();
619 gPad->SetBorderMode(0);
620 gPad->Update();
621
622 // FIXME: Also align max/min with set Maximum/Minimum
623 const Double_t maxbin1 = hist1.GetBinContent(hist1.GetMaximumBin());
624 const Double_t maxbin2 = hist2.GetBinContent(hist2.GetMaximumBin());
625 const Double_t minbin1 = hist1.GetBinContent(hist1.GetMinimumBin());
626 const Double_t minbin2 = hist2.GetBinContent(hist2.GetMinimumBin());
627
628 const Double_t max = TMath::Max(maxbin1, maxbin2);
629 const Double_t min = TMath::Min(minbin1, minbin2);
630
631 h1->SetMaximum(max>0?max*1.05:max*0.95);
632 h1->SetMinimum(max>0?min*0.95:min*1.05);
633
634 TPaveText *t = (TPaveText*)gPad->FindObject("title");
635 if (t)
636 {
637 t->SetName((TString)"MHTitle"); // rename object
638 t->Clear(); // clear old lines
639 t->AddText((TString)" "+title+" "); // add the new title
640 t->SetBit(kCanDelete); // make sure object is deleted
641
642 //
643 // FIXME: This is a stupid workaround to hide the redrawn
644 // (see THistPainter::PaintTitle) title
645 //
646 gPad->Modified(); // indicates a change
647 gPad->Update(); // recreates the original title
648 t->Pop(); // bring our title on top
649 }
650
651 //
652 // Rename first statistics box
653 //
654 TPaveStats *s1 = (TPaveStats*)gPad->FindObject("stats");
655 if (!s1)
656 s1 = (TPaveStats*)hist1.GetListOfFunctions()->FindObject("stats");
657 else
658 s1->SetName((TString)"Stat"+hist1.GetTitle());
659
660 if (s1 && s1->GetX2NDC()>0.95)
661 {
662 const Double_t x1 = s1->GetX1NDC()-0.01;
663 s1->SetX1NDC(x1-(s1->GetX2NDC()-s1->GetX1NDC()));
664 s1->SetX2NDC(x1);
665 }
666
667 //
668 // Draw second histogram
669 //
670 TH1 *h2 = ((TH1&)hist2).DrawCopy("sames");
671 gPad->Update();
672
673 //
674 // Draw Legend
675 //
676 TPaveStats *s2 = (TPaveStats*)gPad->FindObject("stats");
677 if (!s2)
678 s2 = (TPaveStats*)hist2.GetListOfFunctions()->FindObject("stats");
679
680 if (s2)
681 {
682 TLegend &l = *new TLegend(s2->GetX1NDC(),
683 s2->GetY1NDC()-0.015-(s2->GetY2NDC()-s2->GetY1NDC())/2,
684 s2->GetX2NDC(),
685 s2->GetY1NDC()-0.01
686 );
687 l.AddEntry(h1, h1->GetTitle());
688 l.AddEntry(h2, h2->GetTitle());
689 l.SetTextSize(s2->GetTextSize());
690 l.SetTextFont(s2->GetTextFont());
691 l.SetBorderSize(s2->GetBorderSize());
692 l.SetBit(kCanDelete);
693 l.Draw();
694 }
695}
696
697// --------------------------------------------------------------------------
698//
699// Draws the two given histograms. Uses title as the pad title.
700// Also layout the two statistic boxes and a legend.
701//
702void MH::DrawSame(TH1 &hist1, TH1 &hist2, const TString title)
703{
704 //
705 // Draw first histogram
706 //
707 hist1.Draw();
708 gPad->SetBorderMode(0);
709 gPad->Update();
710
711 if (hist1.GetEntries()>0 && hist2.GetEntries()>0)
712 {
713 const Double_t maxbin1 = hist1.GetBinContent(hist1.GetMaximumBin());
714 const Double_t maxbin2 = hist2.GetBinContent(hist2.GetMaximumBin());
715 const Double_t minbin1 = hist1.GetBinContent(hist1.GetMinimumBin());
716 const Double_t minbin2 = hist2.GetBinContent(hist2.GetMinimumBin());
717
718 const Double_t max = TMath::Max(maxbin1, maxbin2);
719 const Double_t min = TMath::Min(minbin1, minbin2);
720
721 if (max!=min)
722 {
723 hist1.SetMaximum(max>0?max*1.05:max*0.95);
724 hist1.SetMinimum(max>0?min*0.95:min*1.05);
725 }
726 }
727
728 TPaveText *t = (TPaveText*)gPad->FindObject("title");
729 if (t)
730 {
731 t->SetName((TString)"MHTitle"); // rename object
732 t->Clear(); // clear old lines
733 t->AddText((TString)" "+title+" "); // add the new title
734 t->SetBit(kCanDelete); // make sure object is deleted
735
736 //
737 // FIXME: This is a stupid workaround to hide the redrawn
738 // (see THistPainter::PaintTitle) title
739 //
740 gPad->Modified(); // indicates a change
741 gPad->Update(); // recreates the original title
742 t->Pop(); // bring our title on top
743 }
744
745 //
746 // Rename first statistics box
747 //
748 // Where to get the TPaveStats depends on the root version
749 TPaveStats *s1 = (TPaveStats*)gPad->FindObject("stats");
750 if (!s1)
751 s1 = (TPaveStats*)hist1.GetListOfFunctions()->FindObject("stats");
752 else
753 s1->SetName((TString)"Stat"+hist1.GetTitle());
754
755 if (s1 && s1->GetX2NDC()>0.95)
756 {
757 const Double_t x1 = s1->GetX1NDC()-0.01;
758 s1->SetX1NDC(x1-(s1->GetX2NDC()-s1->GetX1NDC()));
759 s1->SetX2NDC(x1);
760 }
761
762 //
763 // Draw second histogram
764 //
765 hist2.Draw("sames");
766 gPad->Update();
767
768 //
769 // Draw Legend
770 //
771 // Where to get the TPaveStats depends on the root version
772 TPaveStats *s2 = (TPaveStats*)gPad->FindObject("stats");
773 if (!s2)
774 s2 = (TPaveStats*)hist2.GetListOfFunctions()->FindObject("stats");
775
776 if (s2)
777 {
778 TLegend &l = *new TLegend(s2->GetX1NDC(),
779 s2->GetY1NDC()-0.015-(s2->GetY2NDC()-s2->GetY1NDC())/2,
780 s2->GetX2NDC(),
781 s2->GetY1NDC()-0.01
782 );
783 l.AddEntry(&hist1, hist1.GetTitle());
784 l.AddEntry(&hist2, hist2.GetTitle());
785 l.SetTextSize(s2->GetTextSize());
786 l.SetTextFont(s2->GetTextFont());
787 l.SetBorderSize(s2->GetBorderSize());
788 l.SetBit(kCanDelete);
789 l.Draw();
790 }
791}
792
793// --------------------------------------------------------------------------
794//
795// If the opt string contains 'nonew' or gPad is not given NULL is returned.
796// Otherwise the present gPad is returned.
797//
798TVirtualPad *MH::GetNewPad(TString &opt)
799{
800 opt.ToLower();
801
802 if (!opt.Contains("nonew"))
803 return NULL;
804
805 opt.ReplaceAll("nonew", "");
806
807 return gPad;
808}
809
810// --------------------------------------------------------------------------
811//
812// Encapsulate the TObject::Clone such, that a cloned TH1 (or derived)
813// object is not added to the current directory, when cloned.
814//
815TObject *MH::Clone(const char *name) const
816{
817 const Bool_t store = TH1::AddDirectoryStatus();
818
819 TH1::AddDirectory(kFALSE);
820 TObject *o = MParContainer::Clone(name);
821 TH1::AddDirectory(store);
822
823 return o;
824}
825
826// --------------------------------------------------------------------------
827//
828// If the opt string contains 'nonew' or gPad is not given a new canvas
829// with size w/h is created. Otherwise the object is cloned and drawn
830// to the present pad. The kCanDelete bit is set for the clone.
831//
832TObject *MH::DrawClone(Option_t *opt, Int_t w, Int_t h) const
833{
834 TString option(opt);
835
836 TVirtualPad *p = GetNewPad(option);
837 if (!p)
838 p = MakeDefCanvas(this, w, h);
839 else
840 p->Clear();
841
842 gROOT->SetSelectedPad(NULL);
843
844 TObject *o = MParContainer::DrawClone(option);
845 o->SetBit(kCanDelete);
846 return o;
847}
848
849// --------------------------------------------------------------------------
850//
851// Check whether a class inheriting from MH overwrites the Draw function
852//
853Bool_t MH::OverwritesDraw(TClass *cls) const
854{
855 if (!cls)
856 cls = IsA();
857
858 //
859 // Check whether we reached the base class MTask
860 //
861 if (TString(cls->GetName())=="MH")
862 return kFALSE;
863
864 //
865 // Check whether the class cls overwrites Draw
866 //
867 if (cls->GetMethodAny("Draw"))
868 return kTRUE;
869
870 //
871 // If the class itself doesn't overload it check all it's base classes
872 //
873 TBaseClass *base=NULL;
874 TIter NextBase(cls->GetListOfBases());
875 while ((base=(TBaseClass*)NextBase()))
876 {
877 if (OverwritesDraw(base->GetClassPointer()))
878 return kTRUE;
879 }
880
881 return kFALSE;
882}
883
884// --------------------------------------------------------------------------
885//
886// Cuts the bins containing only zeros at the edges.
887//
888// A new number of bins can be defined with nbins != 0
889// In the case of nbins == 0, no rebinning will take place
890//
891// Returns the new (real) number of bins
892//
893Int_t MH::CutEdges(TH1 *h, Int_t nbins)
894{
895 TAxis* axe = h->GetXaxis();
896
897 const Int_t min1 = axe->GetFirst();
898 const Int_t max1 = axe->GetLast();
899 const Int_t range1 = max1-min1;
900
901 //
902 // Check for useless zeros
903 //
904 if (range1 == 0)
905 return 0;
906
907 Int_t min2 = 0;
908 for (int i=min1; i<=max1; i++)
909 if (h->GetBinContent(i) != 0)
910 {
911 min2 = i;
912 break;
913 }
914
915 //
916 // If the histogram consists of zeros only
917 //
918 if (min2 == max1)
919 return 0;
920
921 Int_t max2 = 0;
922 for (int i=max1; i>=min2; i--)
923 if (h->GetBinContent(i) != 0)
924 {
925 max2 = i;
926 break;
927 }
928
929 //
930 // Check for rebinning
931 //
932 if (nbins < 1)
933 {
934 axe->SetRange(min2,max2);
935 return axe->GetLast()-axe->GetFirst();
936 }
937
938 //
939 // Appying TAxis->SetRange before ReBin does not work ...
940 // But this workaround helps quite fine
941 //
942 const Axis_t min = h->GetBinLowEdge(min2);
943 const Axis_t max = h->GetBinLowEdge(max2)+h->GetBinWidth(max2);
944
945 const Int_t ngroup = (int)((max2-min2)*h->GetNbinsX()/nbins/(max1-min1));
946
947 if (ngroup > 1)
948 h->Rebin(ngroup);
949
950 axe->SetRangeUser(min,max);
951
952 return axe->GetLast()-axe->GetFirst();
953}
954
955void MH::ProjectionX(TH1D &dest, const TH2 &src, Int_t firstybin, Int_t lastybin)
956{
957 //*-*-*-*-*Project a 2-D histogram into a 1-D histogram along X*-*-*-*-*-*-*
958 //*-* ====================================================
959 //
960 // The projection dest is always of the type TH1D.
961 // The projection is made from the channels along the Y axis
962 // ranging from firstybin to lastybin included.
963 // By default, bins 1 to ny are included
964 // When all bins are included, the number of entries in the projection
965 // is set to the number of entries of the 2-D histogram, otherwise
966 // the number of entries is incremented by 1 for all non empty cells.
967 //
968 // if Sumw2() was called for dest, the errors are computed.
969 //
970 TAxis &axex = *((TH2&)src).GetXaxis();
971 TAxis &axey = *((TH2&)src).GetYaxis();
972
973 const Int_t nx = axex.GetNbins();
974 const Int_t ny = axey.GetNbins();
975 if (firstybin < 0)
976 firstybin = 1;
977 if (lastybin > ny)
978 lastybin = ny;
979
980 dest.Reset();
981 SetBinning(&dest, &axex);
982
983 // Create the projection histogram
984 const Bool_t computeErrors = dest.GetSumw2N() ? 1 : 0;
985
986 // Fill the projected histogram
987 for (Int_t binx=0; binx<=nx+1; binx++)
988 {
989 Double_t err2 = 0;
990 for (Int_t biny=firstybin; biny<=lastybin; biny++)
991 {
992 const Double_t cont = src.GetCellContent(binx,biny);
993 const Double_t err1 = src.GetCellError(binx,biny);
994 err2 += err1*err1;
995 if (cont)
996 dest.Fill(axex.GetBinCenter(binx), cont);
997 }
998 if (computeErrors)
999 dest.SetBinError(binx, TMath::Sqrt(err2));
1000 }
1001 if (firstybin <=1 && lastybin >= ny)
1002 dest.SetEntries(src.GetEntries());
1003}
1004
1005void MH::ProjectionY(TH1D &dest, const TH2 &src, Int_t firstxbin, Int_t lastxbin)
1006{
1007 //*-*-*-*-*Project a 2-D histogram into a 1-D histogram along X*-*-*-*-*-*-*
1008 //*-* ====================================================
1009 //
1010 // The projection dest is always of the type TH1D.
1011 // The projection is made from the channels along the Y axis
1012 // ranging from firstybin to lastybin included.
1013 // By default, bins 1 to ny are included
1014 // When all bins are included, the number of entries in the projection
1015 // is set to the number of entries of the 2-D histogram, otherwise
1016 // the number of entries is incremented by 1 for all non empty cells.
1017 //
1018 // if Sumw2() was called for dest, the errors are computed.
1019 //
1020 TAxis &axex = *((TH2&)src).GetXaxis();
1021 TAxis &axey = *((TH2&)src).GetYaxis();
1022
1023 const Int_t nx = axex.GetNbins();
1024 const Int_t ny = axey.GetNbins();
1025 if (firstxbin < 0)
1026 firstxbin = 1;
1027 if (lastxbin > nx)
1028 lastxbin = nx;
1029
1030 dest.Reset();
1031 SetBinning(&dest, &axey);
1032
1033 // Create the projection histogram
1034 const Bool_t computeErrors = dest.GetSumw2N() ? 1 : 0;
1035
1036 // Fill the projected histogram
1037 for (Int_t biny=0; biny<=ny+1; biny++)
1038 {
1039 Double_t err2 = 0;
1040 for (Int_t binx=firstxbin; binx<=lastxbin; binx++)
1041 {
1042 const Double_t cont = src.GetCellContent(binx,biny);
1043 const Double_t err1 = src.GetCellError(binx,biny);
1044 err2 += err1*err1;
1045 if (cont)
1046 dest.Fill(axey.GetBinCenter(biny), cont);
1047 }
1048 if (computeErrors)
1049 dest.SetBinError(biny, TMath::Sqrt(err2));
1050 }
1051 if (firstxbin <=1 && lastxbin >= nx)
1052 dest.SetEntries(src.GetEntries());
1053}
1054
1055// --------------------------------------------------------------------------
1056//
1057// In contradiction to TPad::FindObject this function searches recursively
1058// in a pad for an object. gPad is the default.
1059//
1060TObject *MH::FindObjectInPad(const char *name, TVirtualPad *pad)
1061{
1062 if (!pad)
1063 pad = gPad;
1064
1065 if (!pad)
1066 return NULL;
1067
1068 TObject *o;
1069
1070 TIter Next(pad->GetListOfPrimitives());
1071 while ((o=Next()))
1072 {
1073 if (!strcmp(o->GetName(), name))
1074 return o;
1075
1076 if (o->InheritsFrom("TPad"))
1077 if ((o = FindObjectInPad(name, (TVirtualPad*)o)))
1078 return o;
1079 }
1080 return NULL;
1081}
Note: See TracBrowser for help on using the repository browser.