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

Last change on this file since 2173 was 2173, 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
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::DrawCopy(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 const Double_t x1 = s1.GetX1NDC()-0.01;
656 s1.SetName((TString)"Stat"+hist1.GetTitle());
657 s1.SetX1NDC(x1-(s1.GetX2NDC()-s1.GetX1NDC()));
658 s1.SetX2NDC(x1);
659
660 //
661 // Draw second histogram
662 //
663 TH1 *h2 = ((TH1&)hist2).DrawCopy("sames");
664 gPad->Update();
665
666 //
667 // Draw Legend
668 //
669 TPaveStats &s2 = *(TPaveStats*)gPad->FindObject("stats");
670 TLegend &l = *new TLegend(s2.GetX1NDC(),
671 s2.GetY1NDC()-0.015-(s2.GetY2NDC()-s2.GetY1NDC())/2,
672 s2.GetX2NDC(),
673 s2.GetY1NDC()-0.01
674 );
675 l.AddEntry(h1, h1->GetTitle());
676 l.AddEntry(h2, h2->GetTitle());
677 l.SetTextSize(s2.GetTextSize());
678 l.SetTextFont(s2.GetTextFont());
679 l.SetBorderSize(s2.GetBorderSize());
680 l.SetBit(kCanDelete);
681 l.Draw();
682}
683
684// --------------------------------------------------------------------------
685//
686// Draws the two given histograms. Uses title as the pad title.
687// Also layout the two statistic boxes and a legend.
688//
689void MH::Draw(TH1 &hist1, TH1 &hist2, const TString title)
690{
691 //
692 // Draw first histogram
693 //
694 hist1.Draw();
695 gPad->SetBorderMode(0);
696 gPad->Update();
697
698 if (hist1.GetEntries()>0 && hist2.GetEntries()>0)
699 {
700 const Double_t maxbin1 = hist1.GetBinContent(hist1.GetMaximumBin());
701 const Double_t maxbin2 = hist2.GetBinContent(hist2.GetMaximumBin());
702 const Double_t minbin1 = hist1.GetBinContent(hist1.GetMinimumBin());
703 const Double_t minbin2 = hist2.GetBinContent(hist2.GetMinimumBin());
704
705 const Double_t max = TMath::Max(maxbin1, maxbin2);
706 const Double_t min = TMath::Min(minbin1, minbin2);
707
708 if (max!=min)
709 {
710 hist1.SetMaximum(max>0?max*1.05:max*0.95);
711 hist1.SetMinimum(max>0?min*0.95:min*1.05);
712 }
713 }
714
715 TPaveText *t = (TPaveText*)gPad->FindObject("title");
716 if (t)
717 {
718 t->SetName((TString)"MHTitle"); // rename object
719 t->Clear(); // clear old lines
720 t->AddText((TString)" "+title+" "); // add the new title
721 t->SetBit(kCanDelete); // make sure object is deleted
722
723 //
724 // FIXME: This is a stupid workaround to hide the redrawn
725 // (see THistPainter::PaintTitle) title
726 //
727 gPad->Modified(); // indicates a change
728 gPad->Update(); // recreates the original title
729 t->Pop(); // bring our title on top
730 }
731
732 //
733 // Rename first statistics box
734 //
735 TPaveStats &s1 = *(TPaveStats*)gPad->FindObject("stats");
736 const Double_t x1 = s1.GetX1NDC()-0.01;
737 s1.SetName((TString)"Stat"+hist1.GetTitle());
738 s1.SetX1NDC(x1-(s1.GetX2NDC()-s1.GetX1NDC()));
739 s1.SetX2NDC(x1);
740
741 //
742 // Draw second histogram
743 //
744 hist2.Draw("sames");
745 gPad->Update();
746
747 //
748 // Draw Legend
749 //
750 TPaveStats &s2 = *(TPaveStats*)gPad->FindObject("stats");
751 TLegend &l = *new TLegend(s2.GetX1NDC(),
752 s2.GetY1NDC()-0.015-(s2.GetY2NDC()-s2.GetY1NDC())/2,
753 s2.GetX2NDC(),
754 s2.GetY1NDC()-0.01
755 );
756 l.AddEntry(&hist1, hist1.GetTitle());
757 l.AddEntry(&hist2, hist2.GetTitle());
758 l.SetTextSize(s2.GetTextSize());
759 l.SetTextFont(s2.GetTextFont());
760 l.SetBorderSize(s2.GetBorderSize());
761 l.SetBit(kCanDelete);
762 l.Draw();
763}
764
765// --------------------------------------------------------------------------
766//
767// If the opt string contains 'nonew' or gPad is not given NULL is returned.
768// Otherwise the present gPad is returned.
769//
770TVirtualPad *MH::GetNewPad(Option_t *opt)
771{
772 TString str(opt);
773
774 if (!str.Contains("nonew", TString::kIgnoreCase))
775 return NULL;
776
777 return gPad;
778}
779
780// --------------------------------------------------------------------------
781//
782// Encapsulate the TObject::Clone such, that a cloned TH1 (or derived)
783// object is not added to the current directory, when cloned.
784//
785TObject *MH::Clone(const char *name) const
786{
787 Bool_t store = TH1::AddDirectoryStatus();
788 TH1::AddDirectory(kFALSE);
789
790 TObject *o = MParContainer::Clone(name);
791
792 TH1::AddDirectory(store);
793
794 return o;
795}
796
797// --------------------------------------------------------------------------
798//
799// If the opt string contains 'nonew' or gPad is not given a new canvas
800// with size w/h is created. Otherwise the object is cloned and drawn
801// to the present pad. The kCanDelete bit is set for the clone.
802//
803TObject *MH::DrawClone(Option_t *opt, Int_t w, Int_t h) const
804{
805 TVirtualPad *p = GetNewPad(opt);
806 if (!p)
807 p = MakeDefCanvas(this, w, h);
808 else
809 p->Clear();
810
811 gROOT->SetSelectedPad(NULL);
812
813 TObject *o = MParContainer::DrawClone(opt);
814 o->SetBit(kCanDelete);
815 return o;
816}
817
818// --------------------------------------------------------------------------
819//
820// Check whether a class inheriting from MH overwrites the Draw function
821//
822Bool_t MH::OverwritesDraw(TClass *cls) const
823{
824 if (!cls)
825 cls = IsA();
826
827 //
828 // Check whether we reached the base class MTask
829 //
830 if (TString(cls->GetName())=="MH")
831 return kFALSE;
832
833 //
834 // Check whether the class cls overwrites Draw
835 //
836 if (cls->GetMethodAny("Draw"))
837 return kTRUE;
838
839 //
840 // If the class itself doesn't overload it check all it's base classes
841 //
842 TBaseClass *base=NULL;
843 TIter NextBase(cls->GetListOfBases());
844 while ((base=(TBaseClass*)NextBase()))
845 {
846 if (OverwritesDraw(base->GetClassPointer()))
847 return kTRUE;
848 }
849
850 return kFALSE;
851}
852
853void MH::ProjectionX(TH1D &dest, const TH2 &src, Int_t firstybin, Int_t lastybin)
854{
855 //*-*-*-*-*Project a 2-D histogram into a 1-D histogram along X*-*-*-*-*-*-*
856 //*-* ====================================================
857 //
858 // The projection dest is always of the type TH1D.
859 // The projection is made from the channels along the Y axis
860 // ranging from firstybin to lastybin included.
861 // By default, bins 1 to ny are included
862 // When all bins are included, the number of entries in the projection
863 // is set to the number of entries of the 2-D histogram, otherwise
864 // the number of entries is incremented by 1 for all non empty cells.
865 //
866 // if Sumw2() was called for dest, the errors are computed.
867 //
868 TAxis &axex = *((TH2&)src).GetXaxis();
869 TAxis &axey = *((TH2&)src).GetYaxis();
870
871 const Int_t nx = axex.GetNbins();
872 const Int_t ny = axey.GetNbins();
873 if (firstybin < 0)
874 firstybin = 1;
875 if (lastybin > ny)
876 lastybin = ny;
877
878 dest.Reset();
879 SetBinning(&dest, &axex);
880
881 // Create the projection histogram
882 const Bool_t computeErrors = dest.GetSumw2N() ? 1 : 0;
883
884 // Fill the projected histogram
885 for (Int_t binx=0; binx<=nx+1; binx++)
886 {
887 Double_t err2 = 0;
888 for (Int_t biny=firstybin; biny<=lastybin; biny++)
889 {
890 const Double_t cont = src.GetCellContent(binx,biny);
891 const Double_t err1 = src.GetCellError(binx,biny);
892 err2 += err1*err1;
893 if (cont)
894 dest.Fill(axex.GetBinCenter(binx), cont);
895 }
896 if (computeErrors)
897 dest.SetBinError(binx, TMath::Sqrt(err2));
898 }
899 if (firstybin <=1 && lastybin >= ny)
900 dest.SetEntries(src.GetEntries());
901}
902
903void MH::ProjectionY(TH1D &dest, const TH2 &src, Int_t firstxbin, Int_t lastxbin)
904{
905 //*-*-*-*-*Project a 2-D histogram into a 1-D histogram along X*-*-*-*-*-*-*
906 //*-* ====================================================
907 //
908 // The projection dest is always of the type TH1D.
909 // The projection is made from the channels along the Y axis
910 // ranging from firstybin to lastybin included.
911 // By default, bins 1 to ny are included
912 // When all bins are included, the number of entries in the projection
913 // is set to the number of entries of the 2-D histogram, otherwise
914 // the number of entries is incremented by 1 for all non empty cells.
915 //
916 // if Sumw2() was called for dest, the errors are computed.
917 //
918 TAxis &axex = *((TH2&)src).GetXaxis();
919 TAxis &axey = *((TH2&)src).GetYaxis();
920
921 const Int_t nx = axex.GetNbins();
922 const Int_t ny = axey.GetNbins();
923 if (firstxbin < 0)
924 firstxbin = 1;
925 if (lastxbin > nx)
926 lastxbin = nx;
927
928 dest.Reset();
929 SetBinning(&dest, &axey);
930
931 // Create the projection histogram
932 const Bool_t computeErrors = dest.GetSumw2N() ? 1 : 0;
933
934 // Fill the projected histogram
935 for (Int_t biny=0; biny<=ny+1; biny++)
936 {
937 Double_t err2 = 0;
938 for (Int_t binx=firstxbin; binx<=lastxbin; binx++)
939 {
940 const Double_t cont = src.GetCellContent(binx,biny);
941 const Double_t err1 = src.GetCellError(binx,biny);
942 err2 += err1*err1;
943 if (cont)
944 dest.Fill(axey.GetBinCenter(biny), cont);
945 }
946 if (computeErrors)
947 dest.SetBinError(biny, TMath::Sqrt(err2));
948 }
949 if (firstxbin <=1 && lastxbin >= nx)
950 dest.SetEntries(src.GetEntries());
951}
952
953// --------------------------------------------------------------------------
954//
955// In contradiction to TPad::FindObject this function searches recursively
956// in a pad for an object. gPad is the default.
957//
958TObject *MH::FindObjectInPad(const char *name, TVirtualPad *pad)
959{
960 if (!pad)
961 pad = gPad;
962
963 if (!pad)
964 return NULL;
965
966 TObject *o;
967
968 TIter Next(pad->GetListOfPrimitives());
969 while ((o=Next()))
970 {
971 if (!strcmp(o->GetName(), name))
972 return o;
973
974 if (o->InheritsFrom("TPad"))
975 if ((o = FindObjectInPad(name, (TVirtualPad*)o)))
976 return o;
977 }
978 return NULL;
979}
Note: See TracBrowser for help on using the repository browser.