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

Last change on this file since 2166 was 2150, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 29.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
77// --------------------------------------------------------------------------
78//
79// Default Constructor. It sets name and title only. Typically you won't
80// need to change this.
81//
82MH::MH(const char *name, const char *title)
83{
84 //
85 // set the name and title of this object
86 //
87 fName = name ? name : "MH";
88 fTitle = title ? title : "Base class for Mars histograms";
89}
90
91// --------------------------------------------------------------------------
92//
93// If you want to use the automatic filling of your derived class you
94// must overload this function. If it is not overloaded you cannot use
95// FillH with this class. The argument is a pointer to a container
96// in your paremeter list which is specified in the MFillH constructor.
97// If you are not going to use it you should at least add
98// Bool_t MH::Fill(const MParContainer *) { return kTRUE; }
99// to your class definition.
100//
101Bool_t MH::Fill(const MParContainer *par, const Stat_t w)
102{
103 *fLog << warn << GetDescriptor() << ": Fill not overloaded! Can't be used!" << endl;
104 return kFALSE;
105}
106
107// --------------------------------------------------------------------------
108//
109// This virtual function is ment as a generalized interface to retrieve
110// a pointer to a root histogram from the MH-derived class.
111//
112TH1 *MH::GetHistByName(const TString name)
113{
114 *fLog << warn << GetDescriptor() << ": GetHistByName not overloaded! Can't be used!" << endl;
115 return NULL;
116}
117
118// --------------------------------------------------------------------------
119//
120// This is a function which should replace the creation of default
121// canvases like root does. Because this is inconvinient in some aspects.
122// need to change this.
123// You can specify a name for the default canvas and a title. Also
124// width and height can be given.
125// MakeDefCanvas looks for a canvas with the given name. If now name is
126// given the DefCanvasName of root is used. If no such canvas is existing
127// it is created and returned. If such a canvas already exists a new canvas
128// with a name plus anumber is created (the number is calculated by the
129// number of all existing canvases plus one)
130//
131// Normally the canvas size is scaled with gStyle->GetScreenFactor() so
132// that on all screens it looks like the same part of the screen.
133// To suppress this scaling use usescreenfactor=kFALSE. In this case
134// you specify directly the size of the embedded pad.
135//
136TCanvas *MH::MakeDefCanvas(TString name, const char *title,
137 UInt_t w, UInt_t h, Bool_t usescreenfactor)
138{
139 const TList *list = (TList*)gROOT->GetListOfCanvases();
140
141 if (name.IsNull())
142 name = gROOT->GetDefCanvasName();
143
144 if (list->FindObject(name))
145 name += Form(" <%d>", list->GetSize()+1);
146
147 if (!usescreenfactor)
148 {
149 const Float_t cx = gStyle->GetScreenFactor();
150 w += 4;
151 h += 28;
152 w = (int)(w/cx+1);
153 h = (int)(h/cx+1);
154 }
155
156 return new TCanvas(name, title, w, h);
157}
158
159// --------------------------------------------------------------------------
160//
161// This function works like MakeDefCanvas(name, title, w, h) but name
162// and title are retrieved from the given TObject.
163//
164// Normally the canvas size is scaled with gStyle->GetScreenFactor() so
165// that on all screens it looks like the same part of the screen.
166// To suppress this scaling use usescreenfactor=kFALSE. In this case
167// you specify directly the size of the embedded pad.
168//
169TCanvas *MH::MakeDefCanvas(const TObject *obj,
170 UInt_t w, UInt_t h, Bool_t usescreenfactor)
171{
172 if (!usescreenfactor)
173 {
174 const Float_t cx = gStyle->GetScreenFactor();
175 w += 4;
176 h += 28;
177 h = (int)(h/cx+1);
178 w = (int)(w/cx+1);
179 }
180
181 return MakeDefCanvas(obj->GetName(), obj->GetTitle(), w, h);
182}
183
184// --------------------------------------------------------------------------
185//
186// Applies a given binning to a 1D-histogram
187//
188void MH::SetBinning(TH1 *h, const MBinning *binsx)
189{
190 //
191 // Another strange behaviour: TAxis::Set deletes the axis title!
192 //
193 TAxis &x = *h->GetXaxis();
194
195#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
196 TString xtitle = x.GetTitle();
197#endif
198
199 //
200 // This is a necessary workaround if one wants to set
201 // non-equidistant bins after the initialization
202 // TH1D::fNcells must be set correctly.
203 //
204 h->SetBins(binsx->GetNumBins(), 0, 1);
205
206 //
207 // Set the binning of the current histogram to the binning
208 // in one of the two given histograms
209 //
210 x.Set(binsx->GetNumBins(), binsx->GetEdges());
211#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
212 x.SetTitle(xtitle);
213#endif
214}
215
216// --------------------------------------------------------------------------
217//
218// Applies given binnings to the two axis of a 2D-histogram
219//
220void MH::SetBinning(TH2 *h, const MBinning *binsx, const MBinning *binsy)
221{
222 TAxis &x = *h->GetXaxis();
223 TAxis &y = *h->GetYaxis();
224
225 //
226 // Another strange behaviour: TAxis::Set deletes the axis title!
227 //
228#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
229 TString xtitle = x.GetTitle();
230 TString ytitle = y.GetTitle();
231#endif
232
233 //
234 // This is a necessary workaround if one wants to set
235 // non-equidistant bins after the initialization
236 // TH1D::fNcells must be set correctly.
237 //
238 h->SetBins(binsx->GetNumBins(), 0, 1,
239 binsy->GetNumBins(), 0, 1);
240
241 //
242 // Set the binning of the current histogram to the binning
243 // in one of the two given histograms
244 //
245 x.Set(binsx->GetNumBins(), binsx->GetEdges());
246 y.Set(binsy->GetNumBins(), binsy->GetEdges());
247#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
248 x.SetTitle(xtitle);
249 y.SetTitle(ytitle);
250#endif
251}
252
253// --------------------------------------------------------------------------
254//
255// Applies given binnings to the three axis of a 3D-histogram
256//
257void MH::SetBinning(TH3 *h, const MBinning *binsx, const MBinning *binsy, const MBinning *binsz)
258{
259 //
260 // Another strange behaviour: TAxis::Set deletes the axis title!
261 //
262 TAxis &x = *h->GetXaxis();
263 TAxis &y = *h->GetYaxis();
264 TAxis &z = *h->GetZaxis();
265
266#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
267 TString xtitle = x.GetTitle();
268 TString ytitle = y.GetTitle();
269 TString ztitle = z.GetTitle();
270#endif
271
272 //
273 // This is a necessary workaround if one wants to set
274 // non-equidistant bins after the initialization
275 // TH1D::fNcells must be set correctly.
276 //
277 h->SetBins(binsx->GetNumBins(), 0, 1,
278 binsy->GetNumBins(), 0, 1,
279 binsz->GetNumBins(), 0, 1);
280
281 //
282 // Set the binning of the current histogram to the binning
283 // in one of the two given histograms
284 //
285 x.Set(binsx->GetNumBins(), binsx->GetEdges());
286 y.Set(binsy->GetNumBins(), binsy->GetEdges());
287 z.Set(binsz->GetNumBins(), binsz->GetEdges());
288#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,03)
289 x.SetTitle(xtitle);
290 y.SetTitle(ytitle);
291 z.SetTitle(ztitle);
292#endif
293}
294
295// --------------------------------------------------------------------------
296//
297// Applies given binning (the n+1 edges) to the axis of a 1D-histogram
298//
299void MH::SetBinning(TH1 *h, const TArrayD &binsx)
300{
301 MBinning bx;
302 bx.SetEdges(binsx);
303 SetBinning(h, &bx);
304}
305
306// --------------------------------------------------------------------------
307//
308// Applies given binning (the n+1 edges) to the two axis of a
309// 2D-histogram
310//
311void MH::SetBinning(TH2 *h, const TArrayD &binsx, const TArrayD &binsy)
312{
313 MBinning bx;
314 MBinning by;
315 bx.SetEdges(binsx);
316 by.SetEdges(binsy);
317 SetBinning(h, &bx, &by);
318}
319
320// --------------------------------------------------------------------------
321//
322// Applies given binning (the n+1 edges) to the three axis of a
323// 3D-histogram
324//
325void MH::SetBinning(TH3 *h, const TArrayD &binsx, const TArrayD &binsy, const TArrayD &binsz)
326{
327 MBinning bx;
328 MBinning by;
329 MBinning bz;
330 bx.SetEdges(binsx);
331 by.SetEdges(binsy);
332 bz.SetEdges(binsz);
333 SetBinning(h, &bx, &by, &bz);
334}
335
336// --------------------------------------------------------------------------
337//
338// Applies the binning of a TAxis (eg from a root histogram) to the axis
339// of a 1D-histogram
340//
341void MH::SetBinning(TH1 *h, const TAxis *binsx)
342{
343 const Int_t nx = binsx->GetNbins();
344
345 TArrayD bx(nx+1);
346 for (int i=0; i<nx; i++) bx[i] = binsx->GetBinLowEdge(i+1);
347 bx[nx] = binsx->GetXmax();
348
349 SetBinning(h, bx);
350}
351
352// --------------------------------------------------------------------------
353//
354// Applies the binnings of the TAxis' (eg from a root histogram) to the
355// two axis' of a 2D-histogram
356//
357void MH::SetBinning(TH2 *h, const TAxis *binsx, const TAxis *binsy)
358{
359 const Int_t nx = binsx->GetNbins();
360 const Int_t ny = binsy->GetNbins();
361
362 TArrayD bx(nx+1);
363 TArrayD by(ny+1);
364 for (int i=0; i<nx; i++) bx[i] = binsx->GetBinLowEdge(i+1);
365 for (int i=0; i<ny; i++) by[i] = binsy->GetBinLowEdge(i+1);
366 bx[nx] = binsx->GetXmax();
367 by[ny] = binsy->GetXmax();
368
369 SetBinning(h, bx, by);
370}
371
372// --------------------------------------------------------------------------
373//
374// Applies the binnings of the TAxis' (eg from a root histogram) to the
375// three axis' of a 3D-histogram
376//
377void MH::SetBinning(TH3 *h, const TAxis *binsx, const TAxis *binsy, const TAxis *binsz)
378{
379 const Int_t nx = binsx->GetNbins();
380 const Int_t ny = binsy->GetNbins();
381 const Int_t nz = binsz->GetNbins();
382
383 TArrayD bx(nx+1);
384 TArrayD by(ny+1);
385 TArrayD bz(nz+1);
386 for (int i=0; i<nx; i++) bx[i] = binsx->GetBinLowEdge(i+1);
387 for (int i=0; i<ny; i++) by[i] = binsy->GetBinLowEdge(i+1);
388 for (int i=0; i<nz; i++) bz[i] = binsz->GetBinLowEdge(i+1);
389 bx[nx] = binsx->GetXmax();
390 by[ny] = binsy->GetXmax();
391 bz[nz] = binsz->GetXmax();
392
393 SetBinning(h, bx, by, bz);
394}
395
396// --------------------------------------------------------------------------
397//
398// Applies the binnings of one root-histogram x to another one h
399// Both histograms must be of the same type: TH1, TH2 or TH3
400//
401void MH::SetBinning(TH1 *h, const TH1 *x)
402{
403 if (h->InheritsFrom(TH3::Class()) && x->InheritsFrom(TH3::Class()))
404 {
405 SetBinning((TH3*)h, ((TH1*)x)->GetXaxis(), ((TH1*)x)->GetYaxis(), ((TH1*)x)->GetZaxis());
406 return;
407 }
408 if (h->InheritsFrom(TH3::Class()) || x->InheritsFrom(TH3::Class()))
409 return;
410 if (h->InheritsFrom(TH2::Class()) && x->InheritsFrom(TH2::Class()))
411 {
412 SetBinning((TH2*)h, ((TH1*)x)->GetXaxis(), ((TH1*)x)->GetYaxis());
413 return;
414 }
415 if (h->InheritsFrom(TH2::Class()) || x->InheritsFrom(TH2::Class()))
416 return;
417 if (h->InheritsFrom(TH1::Class()) && x->InheritsFrom(TH1::Class()))
418 {
419 SetBinning(h, ((TH1*)x)->GetXaxis());
420 return;
421 }
422}
423
424// --------------------------------------------------------------------------
425//
426// Multiplies all entries in a TArrayD by a float f
427//
428void MH::ScaleArray(TArrayD &bins, Double_t f)
429{
430 for (int i=0; i<bins.GetSize(); i++)
431 bins[i] *= f;
432}
433
434// --------------------------------------------------------------------------
435//
436// Scales the binning of a TAxis by a float f
437//
438TArrayD MH::ScaleAxis(TAxis &axe, Double_t f)
439{
440 TArrayD arr(axe.GetNbins()+1);
441
442 for (int i=1; i<=axe.GetNbins()+1; i++)
443 arr[i-1] = axe.GetBinLowEdge(i);
444
445 ScaleArray(arr, f);
446
447 return arr;
448}
449
450// --------------------------------------------------------------------------
451//
452// Scales the binning of one, two or three axis of a histogram by a float f
453//
454void MH::ScaleAxis(TH1 *h, Double_t fx, Double_t fy, Double_t fz)
455{
456 if (h->InheritsFrom(TH3::Class()))
457 {
458 SetBinning((TH3*)h,
459 ScaleAxis(*h->GetXaxis(), fx),
460 ScaleAxis(*h->GetYaxis(), fy),
461 ScaleAxis(*h->GetZaxis(), fz));
462 return;
463 }
464
465 if (h->InheritsFrom(TH2::Class()))
466 {
467 SetBinning((TH2*)h,
468 ScaleAxis(*h->GetXaxis(), fx),
469 ScaleAxis(*h->GetYaxis(), fy));
470 return;
471 }
472
473 if (h->InheritsFrom(TH1::Class()))
474 SetBinning(h, ScaleAxis(*h->GetXaxis(), fx));
475}
476
477// --------------------------------------------------------------------------
478//
479// Tries to find a MBinning container with the name "Binning"+name
480// in the given parameter list. If it was found it is applied to the
481// given histogram. This is only valid for 1D-histograms
482//
483Bool_t MH::ApplyBinning(const MParList &plist, TString name, TH1 *h)
484{
485 if (h->InheritsFrom(TH2::Class()) || h->InheritsFrom(TH3::Class()))
486 {
487 gLog << warn << "MH::ApplyBinning: '" << h->GetName() << "' is not a basic TH1 object... no binning applied." << endl;
488 return kFALSE;
489 }
490
491 const MBinning *bins = (MBinning*)plist.FindObject("Binning"+name);
492 if (!bins)
493 {
494 gLog << warn << "Object 'Binning" << name << "' [MBinning] not found... no binning applied." << endl;
495 return kFALSE;
496 }
497
498 SetBinning(h, bins);
499 return kTRUE;
500}
501
502void MH::FindGoodLimits(Int_t nbins, Int_t &newbins, Double_t &xmin, Double_t &xmax, Bool_t isInteger)
503{
504#if ROOT_VERSION_CODE > ROOT_VERSION(3,04,01)
505 THLimitsFinder::OptimizeLimits(nbins, newbins, xmin, xmax, isInteger);
506#else
507//*-*-*-*-*-*-*-*-*Find reasonable bin values*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
508//*-* ==========================
509
510 Double_t dx = 0.1*(xmax-xmin);
511 Double_t umin = xmin - dx;
512 Double_t umax = xmax + dx;
513
514 if (umin < 0 && xmin >= 0)
515 umin = 0;
516
517 if (umax > 0 && xmax <= 0)
518 umax = 0;
519
520 Double_t binlow =0;
521 Double_t binhigh =0;
522 Double_t binwidth=0;
523
524 TGaxis::Optimize(umin, umax, nbins, binlow, binhigh, nbins, binwidth, "");
525
526 if (binwidth <= 0 || binwidth > 1.e+39)
527 {
528 xmin = -1;
529 xmax = 1;
530 }
531 else
532 {
533 xmin = binlow;
534 xmax = binhigh;
535 }
536
537 if (isInteger)
538 {
539 Int_t ixmin = (Int_t)xmin;
540 Int_t ixmax = (Int_t)xmax;
541 Double_t dxmin = (Double_t)ixmin;
542 Double_t dxmax = (Double_t)ixmax;
543
544 xmin = xmin<0 && xmin!=dxmin ? dxmin - 1 : dxmin;
545 xmax = xmax>0 && xmax!=dxmax ? dxmax + 1 : dxmax;
546
547 if (xmin>=xmax)
548 xmax = xmin+1;
549
550 Int_t bw = 1 + (Int_t)((xmax-xmin)/nbins);
551
552 nbins = (Int_t)((xmax-xmin)/bw);
553
554 if (xmin+nbins*bw < xmax)
555 {
556 nbins++;
557 xmax = xmin +nbins*bw;
558 }
559 }
560
561 newbins = nbins;
562#endif
563}
564
565// --------------------------------------------------------------------------
566//
567// Returns the lowest entry in a histogram which is greater than gt (eg >0)
568//
569Double_t MH::GetMinimumGT(const TH1 &h, Double_t gt)
570{
571 Double_t min = FLT_MAX;
572
573 const TAxis &axe = *((TH1&)h).GetXaxis();
574
575 for (int i=1; i<=axe.GetNbins(); i++)
576 {
577 Double_t x = h.GetBinContent(i);
578 if (gt<x && x<min)
579 min = x;
580 }
581 return min;
582}
583
584// --------------------------------------------------------------------------
585//
586// Returns the bin center in a logarithmic scale. If the given bin
587// number is <1 it is set to 1. If it is =GetNbins() it is set to
588// GetNbins()
589//
590Double_t MH::GetBinCenterLog(const TAxis &axe, Int_t nbin)
591{
592 if (nbin>axe.GetNbins())
593 nbin = axe.GetNbins();
594
595 if (nbin<1)
596 nbin = 1;
597
598 const Double_t lo = axe.GetBinLowEdge(nbin);
599 const Double_t hi = axe.GetBinUpEdge(nbin);
600
601 const Double_t val = log10(lo) + log10(hi);
602
603 return pow(10, val/2);
604}
605
606// --------------------------------------------------------------------------
607//
608// Draws a copy of the two given histograms. Uses title as the pad title.
609// Also layout the two statistic boxes and a legend.
610//
611void MH::DrawCopy(const TH1 &hist1, const TH1 &hist2, const TString title)
612{
613 //
614 // Draw first histogram
615 //
616 TH1 *h1 = ((TH1&)hist1).DrawCopy();
617 gPad->SetBorderMode(0);
618 gPad->Update();
619
620 // FIXME: Also align max/min with set Maximum/Minimum
621 const Double_t maxbin1 = hist1.GetBinContent(hist1.GetMaximumBin());
622 const Double_t maxbin2 = hist2.GetBinContent(hist2.GetMaximumBin());
623 const Double_t minbin1 = hist1.GetBinContent(hist1.GetMinimumBin());
624 const Double_t minbin2 = hist2.GetBinContent(hist2.GetMinimumBin());
625
626 const Double_t max = TMath::Max(maxbin1, maxbin2);
627 const Double_t min = TMath::Min(minbin1, minbin2);
628
629 h1->SetMaximum(max>0?max*1.05:max*0.95);
630 h1->SetMinimum(max>0?min*0.95:min*1.05);
631
632 TPaveText *t = (TPaveText*)gPad->FindObject("title");
633 if (t)
634 {
635 t->SetName((TString)"MHTitle"); // rename object
636 t->Clear(); // clear old lines
637 t->AddText((TString)" "+title+" "); // add the new title
638 t->SetBit(kCanDelete); // make sure object is deleted
639
640 //
641 // FIXME: This is a stupid workaround to hide the redrawn
642 // (see THistPainter::PaintTitle) title
643 //
644 gPad->Modified(); // indicates a change
645 gPad->Update(); // recreates the original title
646 t->Pop(); // bring our title on top
647 }
648
649 //
650 // Rename first statistics box
651 //
652 TPaveStats &s1 = *(TPaveStats*)gPad->FindObject("stats");
653 const Double_t x1 = s1.GetX1NDC()-0.01;
654 s1.SetName((TString)"Stat"+hist1.GetTitle());
655 s1.SetX1NDC(x1-(s1.GetX2NDC()-s1.GetX1NDC()));
656 s1.SetX2NDC(x1);
657
658 //
659 // Draw second histogram
660 //
661 TH1 *h2 = ((TH1&)hist2).DrawCopy("sames");
662 gPad->Update();
663
664 //
665 // Draw Legend
666 //
667 TPaveStats &s2 = *(TPaveStats*)gPad->FindObject("stats");
668 TLegend &l = *new TLegend(s2.GetX1NDC(),
669 s2.GetY1NDC()-0.015-(s2.GetY2NDC()-s2.GetY1NDC())/2,
670 s2.GetX2NDC(),
671 s2.GetY1NDC()-0.01
672 );
673 l.AddEntry(h1, h1->GetTitle());
674 l.AddEntry(h2, h2->GetTitle());
675 l.SetTextSize(s2.GetTextSize());
676 l.SetTextFont(s2.GetTextFont());
677 l.SetBorderSize(s2.GetBorderSize());
678 l.SetBit(kCanDelete);
679 l.Draw();
680}
681
682// --------------------------------------------------------------------------
683//
684// Draws the two given histograms. Uses title as the pad title.
685// Also layout the two statistic boxes and a legend.
686//
687void MH::Draw(TH1 &hist1, TH1 &hist2, const TString title)
688{
689 //
690 // Draw first histogram
691 //
692 hist1.Draw();
693 gPad->SetBorderMode(0);
694 gPad->Update();
695
696 if (hist1.GetEntries()>0 && hist2.GetEntries()>0)
697 {
698 const Double_t maxbin1 = hist1.GetBinContent(hist1.GetMaximumBin());
699 const Double_t maxbin2 = hist2.GetBinContent(hist2.GetMaximumBin());
700 const Double_t minbin1 = hist1.GetBinContent(hist1.GetMinimumBin());
701 const Double_t minbin2 = hist2.GetBinContent(hist2.GetMinimumBin());
702
703 const Double_t max = TMath::Max(maxbin1, maxbin2);
704 const Double_t min = TMath::Min(minbin1, minbin2);
705
706 if (max!=min)
707 {
708 hist1.SetMaximum(max>0?max*1.05:max*0.95);
709 hist1.SetMinimum(max>0?min*0.95:min*1.05);
710 }
711 }
712
713 TPaveText *t = (TPaveText*)gPad->FindObject("title");
714 if (t)
715 {
716 t->SetName((TString)"MHTitle"); // rename object
717 t->Clear(); // clear old lines
718 t->AddText((TString)" "+title+" "); // add the new title
719 t->SetBit(kCanDelete); // make sure object is deleted
720
721 //
722 // FIXME: This is a stupid workaround to hide the redrawn
723 // (see THistPainter::PaintTitle) title
724 //
725 gPad->Modified(); // indicates a change
726 gPad->Update(); // recreates the original title
727 t->Pop(); // bring our title on top
728 }
729
730 //
731 // Rename first statistics box
732 //
733 TPaveStats &s1 = *(TPaveStats*)gPad->FindObject("stats");
734 const Double_t x1 = s1.GetX1NDC()-0.01;
735 s1.SetName((TString)"Stat"+hist1.GetTitle());
736 s1.SetX1NDC(x1-(s1.GetX2NDC()-s1.GetX1NDC()));
737 s1.SetX2NDC(x1);
738
739 //
740 // Draw second histogram
741 //
742 hist2.Draw("sames");
743 gPad->Update();
744
745 //
746 // Draw Legend
747 //
748 TPaveStats &s2 = *(TPaveStats*)gPad->FindObject("stats");
749 TLegend &l = *new TLegend(s2.GetX1NDC(),
750 s2.GetY1NDC()-0.015-(s2.GetY2NDC()-s2.GetY1NDC())/2,
751 s2.GetX2NDC(),
752 s2.GetY1NDC()-0.01
753 );
754 l.AddEntry(&hist1, hist1.GetTitle());
755 l.AddEntry(&hist2, hist2.GetTitle());
756 l.SetTextSize(s2.GetTextSize());
757 l.SetTextFont(s2.GetTextFont());
758 l.SetBorderSize(s2.GetBorderSize());
759 l.SetBit(kCanDelete);
760 l.Draw();
761}
762
763// --------------------------------------------------------------------------
764//
765// If the opt string contains 'nonew' or gPad is not given NULL is returned.
766// Otherwise the present gPad is returned.
767//
768TVirtualPad *MH::GetNewPad(Option_t *opt)
769{
770 TString str(opt);
771
772 if (!str.Contains("nonew", TString::kIgnoreCase))
773 return NULL;
774
775 return gPad;
776}
777
778// --------------------------------------------------------------------------
779//
780// Encapsulate the TObject::Clone such, that a cloned TH1 (or derived)
781// object is not added to the current directory, when cloned.
782//
783TObject *MH::Clone(const char *name) const
784{
785 Bool_t store = TH1::AddDirectoryStatus();
786 TH1::AddDirectory(kFALSE);
787
788 TObject *o = MParContainer::Clone(name);
789
790 TH1::AddDirectory(store);
791
792 return o;
793}
794
795// --------------------------------------------------------------------------
796//
797// If the opt string contains 'nonew' or gPad is not given a new canvas
798// with size w/h is created. Otherwise the object is cloned and drawn
799// to the present pad. The kCanDelete bit is set for the clone.
800//
801TObject *MH::DrawClone(Option_t *opt, Int_t w, Int_t h) const
802{
803 TVirtualPad *p = GetNewPad(opt);
804 if (!p)
805 p = MakeDefCanvas(this, w, h);
806 else
807 p->Clear();
808
809 gROOT->SetSelectedPad(NULL);
810
811 TObject *o = MParContainer::DrawClone(opt);
812 o->SetBit(kCanDelete);
813 return o;
814}
815
816// --------------------------------------------------------------------------
817//
818// Check whether a class inheriting from MH overwrites the Draw function
819//
820Bool_t MH::OverwritesDraw(TClass *cls) const
821{
822 if (!cls)
823 cls = IsA();
824
825 //
826 // Check whether we reached the base class MTask
827 //
828 if (TString(cls->GetName())=="MH")
829 return kFALSE;
830
831 //
832 // Check whether the class cls overwrites Draw
833 //
834 if (cls->GetMethodAny("Draw"))
835 return kTRUE;
836
837 //
838 // If the class itself doesn't overload it check all it's base classes
839 //
840 TBaseClass *base=NULL;
841 TIter NextBase(cls->GetListOfBases());
842 while ((base=(TBaseClass*)NextBase()))
843 {
844 if (OverwritesDraw(base->GetClassPointer()))
845 return kTRUE;
846 }
847
848 return kFALSE;
849}
850
851void MH::ProjectionX(TH1D &dest, const TH2 &src, Int_t firstybin, Int_t lastybin)
852{
853 //*-*-*-*-*Project a 2-D histogram into a 1-D histogram along X*-*-*-*-*-*-*
854 //*-* ====================================================
855 //
856 // The projection dest is always of the type TH1D.
857 // The projection is made from the channels along the Y axis
858 // ranging from firstybin to lastybin included.
859 // By default, bins 1 to ny are included
860 // When all bins are included, the number of entries in the projection
861 // is set to the number of entries of the 2-D histogram, otherwise
862 // the number of entries is incremented by 1 for all non empty cells.
863 //
864 // if Sumw2() was called for dest, the errors are computed.
865 //
866 TAxis &axex = *((TH2&)src).GetXaxis();
867 TAxis &axey = *((TH2&)src).GetYaxis();
868
869 const Int_t nx = axex.GetNbins();
870 const Int_t ny = axey.GetNbins();
871 if (firstybin < 0)
872 firstybin = 1;
873 if (lastybin > ny)
874 lastybin = ny;
875
876 dest.Reset();
877 SetBinning(&dest, &axex);
878
879 // Create the projection histogram
880 const Bool_t computeErrors = dest.GetSumw2N() ? 1 : 0;
881
882 // Fill the projected histogram
883 for (Int_t binx=0; binx<=nx+1; binx++)
884 {
885 Double_t err2 = 0;
886 for (Int_t biny=firstybin; biny<=lastybin; biny++)
887 {
888 const Double_t cont = src.GetCellContent(binx,biny);
889 const Double_t err1 = src.GetCellError(binx,biny);
890 err2 += err1*err1;
891 if (cont)
892 dest.Fill(axex.GetBinCenter(binx), cont);
893 }
894 if (computeErrors)
895 dest.SetBinError(binx, TMath::Sqrt(err2));
896 }
897 if (firstybin <=1 && lastybin >= ny)
898 dest.SetEntries(src.GetEntries());
899}
900
901void MH::ProjectionY(TH1D &dest, const TH2 &src, Int_t firstxbin, Int_t lastxbin)
902{
903 //*-*-*-*-*Project a 2-D histogram into a 1-D histogram along X*-*-*-*-*-*-*
904 //*-* ====================================================
905 //
906 // The projection dest is always of the type TH1D.
907 // The projection is made from the channels along the Y axis
908 // ranging from firstybin to lastybin included.
909 // By default, bins 1 to ny are included
910 // When all bins are included, the number of entries in the projection
911 // is set to the number of entries of the 2-D histogram, otherwise
912 // the number of entries is incremented by 1 for all non empty cells.
913 //
914 // if Sumw2() was called for dest, the errors are computed.
915 //
916 TAxis &axex = *((TH2&)src).GetXaxis();
917 TAxis &axey = *((TH2&)src).GetYaxis();
918
919 const Int_t nx = axex.GetNbins();
920 const Int_t ny = axey.GetNbins();
921 if (firstxbin < 0)
922 firstxbin = 1;
923 if (lastxbin > nx)
924 lastxbin = nx;
925
926 dest.Reset();
927 SetBinning(&dest, &axey);
928
929 // Create the projection histogram
930 const Bool_t computeErrors = dest.GetSumw2N() ? 1 : 0;
931
932 // Fill the projected histogram
933 for (Int_t biny=0; biny<=ny+1; biny++)
934 {
935 Double_t err2 = 0;
936 for (Int_t binx=firstxbin; binx<=lastxbin; binx++)
937 {
938 const Double_t cont = src.GetCellContent(binx,biny);
939 const Double_t err1 = src.GetCellError(binx,biny);
940 err2 += err1*err1;
941 if (cont)
942 dest.Fill(axey.GetBinCenter(biny), cont);
943 }
944 if (computeErrors)
945 dest.SetBinError(biny, TMath::Sqrt(err2));
946 }
947 if (firstxbin <=1 && lastxbin >= nx)
948 dest.SetEntries(src.GetEntries());
949}
950
951// --------------------------------------------------------------------------
952//
953// In contradiction to TPad::FindObject this function searches recursively
954// in a pad for an object. gPad is the default.
955//
956TObject *MH::FindObjectInPad(const char *name, TVirtualPad *pad)
957{
958 if (!pad)
959 pad = gPad;
960
961 if (!pad)
962 return NULL;
963
964 TObject *o;
965
966 TIter Next(pad->GetListOfPrimitives());
967 while ((o=Next()))
968 {
969 if (!strcmp(o->GetName(), name))
970 return o;
971
972 if (o->InheritsFrom("TPad"))
973 if ((o = FindObjectInPad(name, (TVirtualPad*)o)))
974 return o;
975 }
976 return NULL;
977}
Note: See TracBrowser for help on using the repository browser.