source: trunk/Mars/mhbase/MH3.cc@ 15325

Last change on this file since 15325 was 15124, checked in by tbretz, 12 years ago
Remove the 3D option kLabelsX which is not supported by newer root versions anymore.
File size: 41.8 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 2002 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2010
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MH3
28//
29// With this histogram you can fill a histogram with up to three
30// variables from Mars parameter containers in an eventloop.
31//
32// In the constructor you can give up to three variables which should be
33// filled in the histogram. Dependend on the number of given variables
34// (data members) a TH1D, TH2D or TH3D is created.
35// Specify the data mamber like the following:
36// "MHillas.fLength"
37// Where MHillas is the name of the parameter container in the parameter
38// list and fLength is the name of the data member which should be filled
39// in the histogram. Assuming that your MHillas container has a different
40// name (MyHillas) the name to give would be:
41// "MyHillas.fLength"
42//
43// If you want to use a different unit for histogramming use SetScaleX,
44// SetScaleY and SetScaleZ.
45//
46//
47// Binning/Binning name
48// =====================
49//
50// The axis binning is retrieved from the parameter list, too. Create a
51// MBinning with the name "Binning" plus the name of your MH3 container
52// plus the axis name ("X", "Y" or "Z") and add it to the parameter list.
53//
54// If the binning should have a different name than the histogram name
55// the binning name can be added to the name, eg.:
56// SetName("MyHistName;MyXBins;MyYBins")
57// Instead of BinningMyHistName[XYZ] the parameter list will be searched
58// for BinningMyXBinning, BinningMyYBins and BinningMyHistNameZ
59//
60// If you don't want to use a MBinning object from the parameter list
61// you can also set one directly, for example
62// MBinning bins(10, 0, 1);
63// mh3.SetBinningX(&bins);
64// You must not delete the MBinning object before the class has been
65// PreProcessed.
66//
67//
68// Axis titles
69// ===========
70//
71// 1) If no other title is given the rule for this axis is used.
72// 2) If the MBinning used for this axis has a non-default Title
73// (MBinning::HasTitle) this title is used for the corresponding axis
74// 3) If the MH3 has a non-default title (MH3::SetTitle called)
75// this title is set as the histogram title. It can be used to overwrite
76// the axis titles. For more information see TH1::SetTitle, eg.
77// SetTitle("MyHist;x[mm];y[cm];Counts");
78//
79//
80// Labels
81// ======
82//
83// To use labels at an axis you have to initialize this for the axis
84// by either calling InitLabels(Labels_t) or setiting a DefaultLabel.
85// For the axis for which the labels have been initialized the
86// number returned by the given corresponding phrase is converted
87// to int with TMath::Nint and used as a label. If you want to replace
88// this id by a named label you can call DefineLabel to do that.
89// Several ids can be replaced by the same label. If you define
90// named labels for every label which was not defined the default
91// is used, if any, otherwise an unnamed label is created.
92//
93// In the case of an axis with labels the axis-title cannot be
94// set via a MBinning, because the MBinning is not evaluated.
95//
96// Please note that for some reason not all combinations of
97// labels, dimensions and weights are available in the root-
98// histogram classes. Please check the MH3::Fill function to see
99// whether your combination is supported.
100//
101//
102// Examples:
103// =========
104//
105// 1) MH3 myhist("MHillas.fLength");
106// myhist.SetName("MyHist");
107// myhist.SetScaleX(geomcam.GetConvMm2Deg()); //convert length to degree
108// MBinning bins("BinningMyHistX", "Title for my x-axis [Hz]");
109// bins.SetEdges(10, 0, 150);
110// plist.AddToList(&bins);
111//
112// 2) MH3 myhist("MHillas.fLength");
113// myhist.SetName("MyHist;MyX");
114// myhist.SetTitle("Histogram Title;X-Title [mm];Counts");
115// MBinning bins("BinningMyX");
116// bins.SetEdges(10, 0, 150);
117// plist.AddToList(&bins);
118//
119// 3) MH3 myhist("MTriggerPatter.GetUnprescaled");
120// myhist.SetWeight("1./MRawRunHeader.GetRunLength");
121// myhist.SetTitle("Rate of the trigger pattern [Hz];Run Number;Trigger Pattern;Rate [Hz]");
122// myhist.InitLabels(MH3::kLabelsXY);
123// myhist.DefaultLabelY("UNKNOWN"); // Lvl1
124// myhist.DefineLabelY( 1, "Trig"); // Lvl1
125// myhist.DefineLabelY( 2, "Cal"); // Cal
126// myhist.DefineLabelY( 4, "Trig"); // Lvl2
127// myhist.DefineLabelY( 8, "Ped"); // Ped
128//
129//
130// Class Version 1:
131// ----------------
132// - MData *fData[3];
133// + MData *fData[4];
134//
135// Class Version 2:
136// ----------------
137// - MDataChain *fData[3]; // Object from which the data is filled
138// + MData *fData[3]; // Object from which the data is filled
139//
140// Class Version 3:
141// ----------------
142// - Byte_t fStyleBits
143// + MBinning fBins[3]
144//
145// Class Version 5:
146// ----------------
147// + TFormula *fConversion
148//
149// Class Version 6:
150// ----------------
151// + MData *fWeight;
152//
153// Class Version 7:
154// ----------------
155// + MData *fData[4]
156// + Double_t fScale[4]
157// - MData *fData[3]
158// - Double_t fScale[3]
159//
160/////////////////////////////////////////////////////////////////////////////
161#include "MH3.h"
162
163#include <ctype.h> // tolower
164#include <stdlib.h> // atoi (Ubuntu 8.10)
165#include <fstream>
166
167#include <TMath.h>
168#include <TFormula.h>
169
170#include <THashList.h>
171#include <TObjString.h>
172
173//#include <TPad.h>
174#include <TStyle.h>
175#include <TCanvas.h>
176
177#include <TH2.h>
178#include <TH3.h>
179#include <TProfile.h>
180#include <TProfile2D.h>
181#include <TProfile3D.h>
182
183#include "MLog.h"
184#include "MLogManip.h"
185
186#include "MString.h"
187
188#include "MParList.h"
189#include "MBinning.h"
190#include "MDataPhrase.h"
191
192ClassImp(MH3);
193
194using namespace std;
195
196const TString MH3::gsDefName = "MH3";
197const TString MH3::gsDefTitle = "Container for a n-D Mars Histogram";
198
199// --------------------------------------------------------------------------
200//
201// Set fStyleBits to 0, Reset fBins to NULL, fScale to 1, set name and title
202// to gsDefName and gsDefTitle and if fHist!=NULL UseCurrentStyle and
203// SetDirectory(0)
204//
205void MH3::Init()
206{
207 fStyleBits = 0;
208
209 fWeight = NULL;
210
211 fData[0] = NULL;
212 fData[1] = NULL;
213 fData[2] = NULL;
214 fData[3] = NULL;
215
216 fBins[0] = NULL;
217 fBins[1] = NULL;
218 fBins[2] = NULL;
219
220 fScale[0] = 1;
221 fScale[1] = 1;
222 fScale[2] = 1;
223 fScale[3] = 1;
224
225 fConversion = NULL;
226
227 fName = gsDefName;
228 fTitle = gsDefTitle;
229
230 if (!fHist)
231 return;
232
233 fHist->UseCurrentStyle();
234 fHist->SetDirectory(NULL);
235}
236
237// --------------------------------------------------------------------------
238//
239// Default constructor.
240//
241MH3::MH3(const Int_t dim, Type_t type) : fDimension(dim), fHist(NULL)
242{
243 // FIXME?
244 switch (type)
245 {
246 case kHistogram:
247 if (fDimension>3)
248 fDimension=3;
249 break;
250 case kProfile:
251 case kProfileSpread:
252 fDimension = -TMath::Abs(fDimension);
253 if (fDimension<-2)
254 fDimension = -2;
255 break;
256 }
257
258 switch (fDimension)
259 {
260 case 1:
261 fHist = new TH1D;
262 fHist->SetYTitle("Counts");
263 break;
264 case -1:
265 fHist = new TProfile;
266 fHist->SetYTitle("Average");
267 if (type==kProfileSpread)
268 static_cast<TProfile*>(fHist)->SetErrorOption("s");
269 break;
270 case 2:
271 fHist = new TH2D;
272 fHist->SetZTitle("Counts");
273 break;
274 case -2:
275 fHist = new TProfile2D;
276 fHist->SetZTitle("Average");
277 static_cast<TProfile2D*>(fHist)->BuildOptions(0, 0, type==kProfileSpread?"s":"");
278 break;
279 case 3:
280 fHist = new TH3D;
281 break;
282 case -3:
283 fHist = new TProfile2D;
284 fHist->SetZTitle("Average");
285 static_cast<TProfile2D*>(fHist)->BuildOptions(0, 0, type==kProfileSpread?"s":"");
286 break;
287 }
288
289 Init();
290}
291
292// --------------------------------------------------------------------------
293//
294// Creates an TH1D. memberx is filled into the X-bins. For a more detailed
295// description see the class description above.
296//
297MH3::MH3(const char *memberx, Type_t type) : fDimension(1)
298{
299 fHist = new TH1D;
300 fHist->SetYTitle("Counts");
301
302 Init();
303
304 fData[0] = new MDataPhrase(memberx);
305}
306
307// --------------------------------------------------------------------------
308//
309// Adapt a given histogram
310//
311MH3::MH3(const TH1 &h1) : fDimension(1)
312{
313 if (h1.InheritsFrom(TH3::Class()))
314 fDimension = 3;
315 if (h1.InheritsFrom(TH2::Class()))
316 fDimension = 2;
317
318 if (h1.InheritsFrom(TProfile3D::Class()))
319 {
320 fDimension = -3;
321 *fLog << warn << "WARNING - MH3::MH3(TH1&) does not support TProfile3D." << endl;
322 }
323 if (h1.InheritsFrom(TProfile2D::Class()))
324 fDimension = -2;
325 if (h1.InheritsFrom(TProfile::Class()))
326 fDimension = -1;
327
328 fHist = (TH1*)h1.Clone();
329
330 Init(); // Before without SeUseCurrentStyle!
331
332 switch (fDimension)
333 {
334 case 3:
335 case -2:
336 fData[2] = new MDataPhrase(h1.GetZaxis()->GetTitle());
337 case 2:
338 case -1:
339 fData[1] = new MDataPhrase(h1.GetYaxis()->GetTitle());
340 case 1:
341 fData[0] = new MDataPhrase(h1.GetXaxis()->GetTitle());
342 }
343}
344
345// --------------------------------------------------------------------------
346//
347// Creates an TH2D. memberx is filled into the X-bins. membery is filled
348// into the Y-bins. For a more detailed description see the class
349// description above.
350//
351MH3::MH3(const char *memberx, const char *membery, Type_t type)
352 : fDimension(type==kHistogram?2:-1)
353{
354
355 switch (fDimension)
356 {
357 case 2:
358 fHist = static_cast<TH1*>(new TH2D);
359 break;
360 case -1:
361 fHist = static_cast<TH1*>(new TProfile);
362 if (type==kProfileSpread)
363 static_cast<TProfile*>(fHist)->SetErrorOption("s");
364
365 break;
366 }
367
368 fHist->SetZTitle(fDimension>0?"Counts":"Average");
369
370 Init();
371
372 fData[0] = new MDataPhrase(memberx);
373 fData[1] = new MDataPhrase(membery);
374}
375
376// --------------------------------------------------------------------------
377//
378// Creates an TH3D. memberx is filled into the X-bins. membery is filled
379// into the Y-bins. membery is filled into the Z-bins. For a more detailed
380// description see the class description above.
381//
382MH3::MH3(const char *memberx, const char *membery, const char *memberz, Type_t type)
383 : fDimension(type==kHistogram?3:-2)
384{
385 switch (fDimension)
386 {
387 case 3:
388 fHist = static_cast<TH1*>(new TH3D);
389 break;
390 case -2:
391 fHist = static_cast<TH1*>(new TProfile2D);
392 static_cast<TProfile2D*>(fHist)->BuildOptions(0, 0, type==kProfileSpread?"s":"");
393 }
394
395 Init();
396
397 fData[0] = new MDataPhrase(memberx);
398 fData[1] = new MDataPhrase(membery);
399 fData[2] = new MDataPhrase(memberz);
400}
401
402// --------------------------------------------------------------------------
403//
404// Creates an TH3D. memberx is filled into the X-bins. membery is filled
405// into the Y-bins. membery is filled into the Z-bins. Weight is used as a
406// weight for the profile histogram. For a more detailed description see the
407// class description above.
408//
409MH3::MH3(const char *memberx, const char *membery, const char *memberz, const char *weight, Type_t type)
410 : fDimension(-3)
411{
412 fHist = static_cast<TH1*>(new TProfile3D);
413 static_cast<TProfile3D*>(fHist)->BuildOptions(0, 0, type==kProfileSpread?"s":"");
414
415 Init();
416
417 fData[0] = new MDataPhrase(memberx);
418 fData[1] = new MDataPhrase(membery);
419 fData[2] = new MDataPhrase(memberz);
420 fData[3] = new MDataPhrase(weight);
421}
422
423// --------------------------------------------------------------------------
424//
425// Deletes the histogram
426//
427MH3::~MH3()
428{
429 if (fHist)
430 delete fHist;
431
432 if (fConversion)
433 delete fConversion;
434
435 if (fWeight)
436 delete fWeight;
437
438 for (int i=0; i<4; i++)
439 if (fData[i])
440 delete fData[i];
441
442 for (int i=0; i<3; i++)
443 if (fLabels[i].GetDefault())
444 delete fLabels[i].GetDefault();
445}
446
447// --------------------------------------------------------------------------
448//
449// You can set a weight as a phrase additionally to the one given
450// as an argument to Fill (most likely from MFillH). The two weights
451// are multiplied together.
452//
453void MH3::SetWeight(const char *phrase)
454{
455 if (fWeight)
456 delete fWeight;
457 fWeight = new MDataPhrase(phrase);
458}
459
460// --------------------------------------------------------------------------
461//
462// Set a function which is applied to the histogram before it is displayed.
463// Note, that it only effects the displayed histogram.
464//
465// e.g. SetConversion("sqrt(x)");
466//
467Bool_t MH3::SetConversion(const char *func)
468{
469 if (TString(func).IsNull())
470 {
471 delete fConversion;
472 fConversion = 0;
473 return kTRUE;
474 }
475
476 fConversion = new TFormula;
477
478 // Must have a name otherwise all axis labels disappear like a miracle
479 fConversion->SetName("ConversionFunction");
480 if (fConversion->Compile(func))
481 {
482 *fLog << err << dbginf << "Syntax Error: TFormula::Compile failed for " << func << endl;
483 delete fConversion;
484 fConversion = 0;
485 return kFALSE;
486 }
487
488 gROOT->GetListOfFunctions()->Remove(fConversion);
489
490 return kTRUE;
491}
492
493// --------------------------------------------------------------------------
494//
495// The axis label is centered and the labeling of the axis is initialized.
496//
497// This function must not be called after any label has been created!
498//
499void MH3::InitLabels(TAxis &x) const
500{
501 x.CenterTitle();
502 x.SetBinLabel(1, "");
503 x.LabelsOption("h"); // FIXME: Is "a" thread safe? (Paint and Fill?)
504 x.GetLabels()->Delete();
505}
506
507// --------------------------------------------------------------------------
508//
509// Depending on the bits set the InitLabels(TAxis&) function for
510// the corresponding axes are called. In any case the kCanRebin bit
511// is set.
512//
513// This function must not be called after any label has been created!
514//
515void MH3::InitLabels(Labels_t type) const
516{
517 if (!fHist)
518 return;
519
520 if (type&kLabelsX && fHist->GetXaxis())
521 InitLabels(*fHist->GetXaxis());
522
523 if (type&kLabelsY && fHist->GetYaxis())
524 InitLabels(*fHist->GetYaxis());
525
526 if (type&kLabelsZ && fHist->GetZaxis())
527 InitLabels(*fHist->GetZaxis());
528
529 if (type&kLabelsXYZ)
530 fHist->SetBit(TH1::kCanRebin);
531}
532
533// --------------------------------------------------------------------------
534//
535// Return the corresponding Labels_t describing for which axis
536// axis-labels are switched on.
537//
538MH3::Labels_t MH3::GetLabels() const
539{
540 UInt_t type = kNoLabels;
541 if (fHist->GetXaxis() && fHist->GetXaxis()->GetLabels())
542 type |= kLabelsX;
543 if (fHist->GetYaxis() && fHist->GetYaxis()->GetLabels())
544 type |= kLabelsY;
545 if (fHist->GetZaxis() && fHist->GetZaxis()->GetLabels())
546 type |= kLabelsZ;
547 return (Labels_t)type;
548}
549
550// --------------------------------------------------------------------------
551//
552// Calls the LabelsDeflate from the histogram for all axes.
553// LabelsDeflate will just do nothing if the axis has no labels
554// initialized.
555//
556void MH3::DeflateLabels() const
557{
558 fHist->LabelsDeflate("X");
559 fHist->LabelsDeflate("Y");
560 fHist->LabelsDeflate("Z");
561}
562
563// --------------------------------------------------------------------------
564//
565// Returns the named label corresponding to the given value
566// and the given axis. The names are defined with the
567// DefineLabel-functions. if no name is defined the value
568// is converted to a string with %d and TMath::Nint.
569// If names are defined, but not for the given value, the default
570// label is returned instead. If no default is defined the
571// %d-converted string is returned.
572//
573const char *MH3::GetLabel(Int_t axe, Double_t val) const
574{
575 const Int_t v = TMath::Nint(val);
576
577 if (fLabels[axe].GetSize())
578 {
579 const char *l = fLabels[axe].GetObjName(v);
580 if (l)
581 return l;
582 }
583
584 return Form("%d", v);
585}
586
587// --------------------------------------------------------------------------
588//
589// Return the data members used by the data chain to be used in
590// MTask::AddBranchToList
591//
592TString MH3::GetDataMember() const
593{
594 TString str=fData[0]->GetDataMember();
595
596 for (int i=1; i<4; i++)
597 if (fData[i])
598 {
599 str += ";";
600 str += fData[i]->GetDataMember();
601 }
602
603 return str;
604}
605
606// --------------------------------------------------------------------------
607//
608// Setup the Binning for the histograms automatically if the correct
609// instances of MBinning are found in the parameter list
610// For a more detailed description see class description above.
611//
612Bool_t MH3::SetupFill(const MParList *plist)
613{
614 // reset histogram (necessary if the same eventloop is run more than once)
615 if (!TestBit(kDoNotReset))
616 fHist->Reset();
617
618 // Tokenize name into name and binnings names
619 TObjArray *tok = fName.Tokenize(";");
620
621 const TString name = (*tok)[0] ? (*tok)[0]->GetName() : fName.Data();
622
623 TString bx = (*tok)[1] ? (*tok)[1]->GetName() : Form("%sX", name.Data());
624 TString by = (*tok)[2] ? (*tok)[2]->GetName() : Form("%sY", name.Data());
625 TString bz = (*tok)[3] ? (*tok)[3]->GetName() : Form("%sZ", name.Data());
626
627 bx.Prepend("Binning");
628 by.Prepend("Binning");
629 bz.Prepend("Binning");
630
631 delete tok;
632
633 MBinning *binsx = NULL;
634 MBinning *binsy = NULL;
635 MBinning *binsz = NULL;
636
637 const Labels_t labels = GetLabels();
638
639 switch (TMath::Abs(fDimension))
640 {
641 case 3:
642 if (fData[2])
643 fHist->SetZTitle(fData[2]->GetTitle());
644 if (!(labels&kLabelsZ))
645 {
646 binsz = fBins[2] ? fBins[2] : (MBinning*)plist->FindObject(bz, "MBinning");
647 if (!binsz)
648 {
649 *fLog << err << dbginf << "MBinning '" << bz << "' not found... aborting." << endl;
650 return kFALSE;
651 }
652 if (binsz->HasTitle())
653 fHist->SetZTitle(binsz->GetTitle());
654 if (binsz->IsLogarithmic())
655 fHist->SetBit(kIsLogz);
656 }
657 case 2:
658 if (fData[1])
659 fHist->SetYTitle(fData[1]->GetTitle());
660 if (!(labels&kLabelsY))
661 {
662 binsy = fBins[1] ? fBins[1] : (MBinning*)plist->FindObject(by, "MBinning");
663 if (!binsy)
664 {
665 *fLog << err << dbginf << "MBinning '" << by << "' not found... aborting." << endl;
666 return kFALSE;
667 }
668 if (binsy->HasTitle())
669 fHist->SetYTitle(binsy->GetTitle());
670 if (binsy->IsLogarithmic())
671 fHist->SetBit(kIsLogy);
672 }
673 case 1:
674 if (fData[0]!=NULL)
675 fHist->SetXTitle(fData[0]->GetTitle());
676 if (!(labels&kLabelsX))
677 {
678 binsx = fBins[0] ? fBins[0] : (MBinning*)plist->FindObject(bx, "MBinning");
679 if (!binsx)
680 {
681 if (fDimension==1)
682 binsx = (MBinning*)plist->FindObject("Binning"+fName, "MBinning");
683
684 if (!binsx)
685 {
686 *fLog << err << dbginf << "Neither '" << bx << "' nor 'Binning" << fName << "' found... aborting." << endl;
687 return kFALSE;
688 }
689 }
690 if (binsx->HasTitle())
691 fHist->SetXTitle(binsx->GetTitle());
692 if (binsx->IsLogarithmic())
693 fHist->SetBit(kIsLogx);
694 }
695 }
696
697 // PreProcess existing fData members
698 for (int i=0; i<4; i++)
699 if (fData[i] && !fData[i]->PreProcess(plist))
700 return kFALSE;
701
702 if (fWeight && !fWeight->PreProcess(plist))
703 return kFALSE;
704
705 TString title(fDimension>0?"Histogram":"Profile");
706 title += " for ";
707 title += name;
708 title += Form(" (%dD)", TMath::Abs(fDimension));
709
710 fHist->SetName(name);
711 fHist->SetTitle(fTitle==gsDefTitle ? title : fTitle);
712 fHist->SetDirectory(0);
713
714 // This is for the case we have set lables
715 const MBinning def(1, 0, 1);
716 if (!binsx)
717 binsx = const_cast<MBinning*>(&def);
718 if (!binsy)
719 binsy = const_cast<MBinning*>(&def);
720 if (!binsz)
721 binsz = const_cast<MBinning*>(&def);
722
723 // set binning
724 switch (TMath::Abs(fDimension))
725 {
726 case 1:
727 SetBinning(*fHist, *binsx);
728 return kTRUE;
729 case 2:
730 SetBinning(static_cast<TH2&>(*fHist), *binsx, *binsy);
731 return kTRUE;
732 case 3:
733 SetBinning(static_cast<TH3&>(*fHist), *binsx, *binsy, *binsz);
734 return kTRUE;
735 }
736
737 *fLog << err << "ERROR - MH3 has " << TMath::Abs(fDimension) << " dimensions!" << endl;
738 return kFALSE;
739}
740
741// --------------------------------------------------------------------------
742//
743// Set the name of the histogram ant the MH3 container
744//
745void MH3::SetName(const char *name)
746{
747 if (fHist)
748 {
749 if (gPad)
750 {
751 const TString pfx(MString::Format("%sProfX", fHist->GetName()));
752 const TString pfy(MString::Format("%sProfY", fHist->GetName()));
753
754 TProfile *p = 0;
755 if ((p=dynamic_cast<TProfile*>(gPad->FindObject(pfx))))
756 p->SetName(MString::Format("%sProfX", name));
757 if ((p=dynamic_cast<TProfile*>(gPad->FindObject(pfy))))
758 p->SetName(MString::Format("%sProfY", name));
759 }
760
761 fHist->SetName(name);
762 fHist->SetDirectory(0);
763
764 }
765 MParContainer::SetName(name);
766}
767
768// --------------------------------------------------------------------------
769//
770// Set the title of the histogram ant the MH3 container
771//
772void MH3::SetTitle(const char *title)
773{
774 if (fHist)
775 fHist->SetTitle(title);
776 MParContainer::SetTitle(title);
777}
778
779// --------------------------------------------------------------------------
780//
781// Fills the one, two or three data members into our histogram
782//
783Int_t MH3::Fill(const MParContainer *par, const Stat_t ww)
784{
785 // Get Information about labels (UInt_t, to supress warning about
786 // unhandeled cases in switch)
787 const UInt_t type = GetLabels();
788
789 // Get values for axis
790 Double_t x=0;
791 Double_t y=0;
792 Double_t z=0;
793 Double_t t=0;
794 Double_t w=ww;
795
796 switch (fDimension)
797 {
798 case -3:
799 t = fData[3]->GetValue()*fScale[3];
800 case -2:
801 case 3:
802 z = fData[2]->GetValue()*fScale[2];
803 case -1:
804 case 2:
805 y = fData[1]->GetValue()*fScale[1];
806 case 1:
807 x = fData[0]->GetValue()*fScale[0];
808 }
809
810 if (fWeight)
811 w *= fWeight->GetValue();
812
813 // If label option is set, convert value to label
814 TString labelx, labely, labelz;
815 if (type&kLabelsX)
816 labelx = GetLabel(0, x);
817 if (type&kLabelsY)
818 labely = GetLabel(1, y);
819 if (type&kLabelsZ)
820 labelz = GetLabel(2, z);
821
822 // Fill histogram
823 switch (fDimension)
824 {
825 case 3:
826 switch (type)
827 {
828 case kNoLabels:
829 static_cast<TH3*>(fHist)->Fill(x, y, z, w);
830 return kTRUE;
831 case kLabelsX:
832#if ROOT_VERSION_CODE > ROOT_VERSION(5,32,00)
833 static_cast<TH3*>(fHist)->Fill(labelx, y, z);
834#endif
835 return kTRUE;
836 case kLabelsY:
837 static_cast<TH3*>(fHist)->Fill(x, labely, z, w);
838 return kTRUE;
839 case kLabelsZ:
840 static_cast<TH3*>(fHist)->Fill(x, y, labelz, w);
841 return kTRUE;
842 case kLabelsXY:
843 static_cast<TH3*>(fHist)->Fill(labelx, labely, z, w);
844 return kTRUE;
845 case kLabelsXZ:
846 static_cast<TH3*>(fHist)->Fill(labelx, y, labelz, w);
847 return kTRUE;
848 case kLabelsYZ:
849 static_cast<TH3*>(fHist)->Fill(x, labely, labelz, w);
850 return kTRUE;
851 case kLabelsXYZ:
852 static_cast<TH3*>(fHist)->Fill(labelx, labely, labelz, w);
853 return kTRUE;
854 }
855 break;
856 case 2:
857 switch (type)
858 {
859 case kNoLabels:
860 static_cast<TH2*>(fHist)->Fill(x, y, w);
861 return kTRUE;
862 case kLabelsX:
863 static_cast<TH2*>(fHist)->Fill(x, labely, w);
864 return kTRUE;
865 case kLabelsY:
866 static_cast<TH2*>(fHist)->Fill(labelx, y, w);
867 return kTRUE;
868 case kLabelsXY:
869 static_cast<TH2*>(fHist)->Fill(labelx, labely, w);
870 return kTRUE;
871 }
872 break;
873 case 1:
874 switch (type)
875 {
876 case kNoLabels:
877 fHist->Fill(x, w);
878 return kTRUE;
879 case kLabelsX:
880 fHist->Fill(labelx, w);
881 return kTRUE;
882 }
883 break;
884 case -1:
885 switch (type)
886 {
887 case kNoLabels:
888 static_cast<TProfile*>(fHist)->Fill(x, y, w);
889 return kTRUE;
890 case kLabelsX:
891 static_cast<TProfile*>(fHist)->Fill(labelx, y, w);
892 return kTRUE;
893 }
894 break;
895 case -2:
896 switch (type)
897 {
898 case kNoLabels:
899 static_cast<TProfile2D*>(fHist)->Fill(x, y, z, w);
900 return kTRUE;
901 case kLabelsX:
902 static_cast<TProfile2D*>(fHist)->Fill(labelx, y, z);
903 return kTRUE;
904 case kLabelsY:
905 static_cast<TProfile2D*>(fHist)->Fill(x, labely, z);
906 return kTRUE;
907 case kLabelsXY:
908 static_cast<TProfile2D*>(fHist)->Fill(labelx, labely, z);
909 return kTRUE;
910 }
911 break;
912 case -3:
913 switch (type)
914 {
915 case kNoLabels:
916 static_cast<TProfile3D*>(fHist)->Fill(x, y, z, t, w);
917 return kTRUE;
918 default:
919 *fLog << err << "ERROR - Labels not supported in TProfile3D." << endl;
920 }
921 break;
922 }
923
924 *fLog << err << "MH3::Fill: ERROR - A fatal error occured." << endl;
925 return kERROR;
926}
927
928// --------------------------------------------------------------------------
929//
930// If an auto range bit is set the histogram range of the corresponding
931// axis is set to show only the non-empty bins (with a single empty bin
932// on both sides)
933//
934Bool_t MH3::Finalize()
935{
936 DeflateLabels();
937
938 Bool_t autorangex=TESTBIT(fStyleBits, 0);
939 Bool_t autorangey=TESTBIT(fStyleBits, 1);
940 //Bool_t autorangez=TESTBIT(fStyleBits, 2);
941
942 Int_t lo, hi;
943 if (autorangex)
944 {
945 GetRangeX(*fHist, lo, hi);
946 fHist->GetXaxis()->SetRange(lo-2, hi+1);
947 }
948 if (autorangey)
949 {
950 GetRangeY(*fHist, lo, hi);
951 fHist->GetYaxis()->SetRange(lo-2, hi+1);
952 }
953 /*
954 if (autorangez)
955 {
956 GetRangeZ(*fHist, lo, hi);
957 fHist->GetZaxis()->SetRange(lo-2, hi+1);
958 }
959 */
960 return kTRUE;
961}
962
963// --------------------------------------------------------------------------
964//
965// Apply the conversion function to the contents stored in fHist and
966// store the result in h.
967//
968// In the case of a TProfile we keep it a TProfile to keep the mean and
969// rms in y displayed. To get the error correctly we have to reverse
970// the calculation done in TProfile::GetBinError of course.
971//
972void MH3::Convert(TH1 &h) const
973{
974 const Bool_t prof = h.InheritsFrom(TProfile::Class()) || h.InheritsFrom(TProfile2D::Class()) || h.InheritsFrom(TProfile3D::Class());
975
976 for (Int_t z=0; z<=h.GetNbinsZ()+1; z++)
977 for (Int_t y=0; y<=h.GetNbinsY()+1; y++)
978 for (Int_t x=0; x<=h.GetNbinsX()+1; x++)
979 {
980 h.SetBinContent(x, y, z, fConversion->Eval(fHist->GetBinContent(x, y, z)));
981
982 if (prof)
983 h.SetBinError(x, y, z, TMath::Hypot(fConversion->Eval(fHist->GetBinContent(x, y, z)),
984 fConversion->Eval(fHist->GetBinError( x, y, z))));
985 else
986 h.SetBinError(x, y, z, fConversion->Eval(fHist->GetBinError(x, y, z)));
987 }
988
989 TProfile *p1 = dynamic_cast<TProfile*>(fHist);
990 if (p1)
991 for (Int_t i=0; i<p1->GetSize(); i++)
992 static_cast<TProfile&>(h).SetBinEntries(i, p1->GetBinEntries(i)>0 ? 1 : 0);
993
994 TProfile2D *p2 = dynamic_cast<TProfile2D*>(fHist);
995 if (p2)
996 for (Int_t i=0; i<p2->GetSize(); i++)
997 static_cast<TProfile2D&>(h).SetBinEntries(i, p2->GetBinEntries(i)>0 ? 1 : 0);
998
999 TProfile3D *p3 = dynamic_cast<TProfile3D*>(fHist);
1000 if (p3)
1001 for (Int_t i=0; i<p3->GetSize(); i++)
1002 static_cast<TProfile3D&>(h).SetBinEntries(i, p3->GetBinEntries(i)>0 ? 1 : 0);
1003}
1004
1005// --------------------------------------------------------------------------
1006//
1007// FIXME
1008//
1009void MH3::Paint(Option_t *o)
1010{
1011 TProfile *p=0;
1012
1013 if (TMath::Abs(fDimension)==2)
1014 MH::SetPalette("pretty");
1015
1016 if (fConversion)
1017 {
1018 TH1 *h = 0;
1019 if ((h=dynamic_cast<TH1*>(gPad->FindObject(fHist->GetName()))))
1020 Convert(*h);
1021 }
1022
1023 const TString pfx(MString::Format("%sProfX", fHist->GetName()));
1024 if ((p=dynamic_cast<TProfile*>(gPad->FindObject(pfx))))
1025 {
1026 Int_t col = p->GetLineColor();
1027 p = ((TH2*)fHist)->ProfileX(pfx, -1, -1, "s");
1028 p->SetLineColor(col);
1029 }
1030
1031 const TString pfy(MString::Format("%sProfY", fHist->GetName()));
1032 if ((p=dynamic_cast<TProfile*>(gPad->FindObject(pfy))))
1033 {
1034 Int_t col = p->GetLineColor();
1035 p = ((TH2*)fHist)->ProfileY(pfy, -1, -1, "s");
1036 p->SetLineColor(col);
1037 }
1038/*
1039 if (fHist->TestBit(kIsLogx) && fHist->GetEntries()>0) gPad->SetLogx();
1040 if (fHist->TestBit(kIsLogy) && fHist->GetEntries()>0) gPad->SetLogy();
1041 if (fHist->TestBit(kIsLogz) && fHist->GetEntries()>0) gPad->SetLogz();
1042 */
1043}
1044
1045// --------------------------------------------------------------------------
1046//
1047// If Xmax is < 3000*Xmin SetMoreLogLabels is called. If Xmax<5000
1048// the exponent is switched off (SetNoExponent)
1049//
1050void MH3::HandleLogAxis(TAxis &axe) const
1051{
1052 if (axe.GetXmax()>3000*axe.GetXmin())
1053 return;
1054
1055 axe.SetMoreLogLabels();
1056 if (axe.GetXmax()<5000)
1057 axe.SetNoExponent();
1058}
1059
1060// --------------------------------------------------------------------------
1061//
1062// Creates a new canvas and draws the histogram into it.
1063//
1064// Possible options are:
1065// PROFX: Draw a x-profile into the histogram (for 2D histograms only)
1066// PROFY: Draw a y-profile into the histogram (for 2D histograms only)
1067// ONLY: Draw the profile histogram only (for 2D histograms only)
1068// BLUE: Draw the profile in blue color instead of the histograms
1069// line color
1070//
1071// If the kIsLog?-Bit is set the axis is displayed lkogarithmically.
1072// eg this is set when applying a logarithmic MBinning
1073//
1074// Be careful: The histogram belongs to this object and won't get deleted
1075// together with the canvas.
1076//
1077void MH3::Draw(Option_t *opt)
1078{
1079 TVirtualPad *pad = gPad ? gPad : MakeDefCanvas(fHist);
1080 pad->SetBorderMode(0);
1081 pad->SetGridx();
1082 pad->SetGridy();
1083
1084 if (fHist->TestBit(kIsLogx))
1085 {
1086 pad->SetLogx();
1087 HandleLogAxis(*fHist->GetXaxis());
1088 }
1089 if (fHist->TestBit(kIsLogy))
1090 {
1091 pad->SetLogy();
1092 HandleLogAxis(*fHist->GetYaxis());
1093 }
1094 if (fHist->TestBit(kIsLogz))
1095 {
1096 pad->SetLogz();
1097 HandleLogAxis(*fHist->GetZaxis());
1098 }
1099
1100 fHist->SetFillStyle(4000);
1101
1102 TString str(opt);
1103 str.ToLower();
1104 str.ReplaceAll(" ", "");
1105
1106 if (GetLabels())
1107 {
1108 if (str.IsNull() && fDimension==2)
1109 str = "colz";
1110
1111 if (str.Contains("box", TString::kIgnoreCase) && fDimension==2)
1112 fHist->SetLineColor(kBlue);
1113 }
1114
1115 const Bool_t only = str.Contains("only") && TMath::Abs(fDimension)==2;
1116 const Bool_t same = str.Contains("same") && TMath::Abs(fDimension)<3;
1117 const Bool_t blue = str.Contains("blue") && TMath::Abs(fDimension)==2;
1118 const Bool_t profx = str.Contains("profx") && TMath::Abs(fDimension)==2;
1119 const Bool_t profy = str.Contains("profy") && TMath::Abs(fDimension)==2;
1120
1121 str.ReplaceAll("only", "");
1122 str.ReplaceAll("blue", "");
1123 str.ReplaceAll("profx", "");
1124 str.ReplaceAll("profy", "");
1125
1126 if (same && TMath::Abs(fDimension)==1)
1127 {
1128 fHist->SetLineColor(kBlue);
1129 fHist->SetMarkerColor(kBlue);
1130 }
1131
1132
1133 TH1 *h = fHist;
1134
1135 if (fConversion)
1136 {
1137 h = static_cast<TH1*>(fHist->Clone());
1138
1139 h->SetDirectory(0);
1140 h->SetBit(kCanDelete);
1141
1142 Convert(*h);
1143 }
1144
1145 // FIXME: We may have to remove all our own options from str!
1146 if (!only)
1147 h->Draw(str);
1148
1149 AppendPad();
1150
1151 TProfile *p=0;
1152 if (profx)
1153 {
1154 const TString pfx(MString::Format("%sProfX", h->GetName()));
1155
1156 if (same && (p=dynamic_cast<TProfile*>(gPad->FindObject(pfx))))
1157 *fLog << warn << "TProfile " << pfx << " already in pad." << endl;
1158
1159 p = ((TH2*)h)->ProfileX(pfx, -1, -1, "s");
1160 p->UseCurrentStyle();
1161 p->SetLineColor(blue ? kBlue : h->GetLineColor());
1162 p->SetBit(kCanDelete);
1163 p->SetDirectory(NULL);
1164 p->SetXTitle(h->GetXaxis()->GetTitle());
1165 p->SetYTitle(h->GetYaxis()->GetTitle());
1166 p->Draw(only&&!same?"":"same");
1167 }
1168 if (profy)
1169 {
1170 const TString pfy(MString::Format("%sProfY", h->GetName()));
1171
1172 if (same && (p=dynamic_cast<TProfile*>(gPad->FindObject(pfy))))
1173 *fLog << warn << "TProfile " << pfy << " already in pad." << endl;
1174
1175 p = ((TH2*)h)->ProfileY(pfy, -1, -1, "s");
1176 p->UseCurrentStyle();
1177 p->SetLineColor(blue ? kBlue : h->GetLineColor());
1178 p->SetBit(kCanDelete);
1179 p->SetDirectory(NULL);
1180 p->SetYTitle(h->GetXaxis()->GetTitle());
1181 p->SetXTitle(h->GetYaxis()->GetTitle());
1182 p->Draw(only&&!same?"":"same");
1183 }
1184
1185 //AppendPad("log");
1186}
1187
1188// --------------------------------------------------------------------------
1189//
1190// Implementation of SavePrimitive. Used to write the call to a constructor
1191// to a macro. In the original root implementation it is used to write
1192// gui elements to a macro-file.
1193//
1194void MH3::StreamPrimitive(ostream &out) const
1195{
1196 TString name = GetUniqueName();
1197
1198 out << " MH3 " << name << "(\"";
1199 out << fData[0]->GetRule() << "\"";
1200 if (fDimension>1 || fDimension<0)
1201 out << ", \"" << fData[1]->GetRule() << "\"";
1202 if (fDimension>2 || fDimension<-1)
1203 out << ", \"" << fData[2]->GetRule() << "\"";
1204
1205 out << ");" << endl;
1206
1207 if (fName!=gsDefName)
1208 out << " " << name << ".SetName(\"" << fName << "\");" << endl;
1209
1210 if (fTitle!=gsDefTitle)
1211 out << " " << name << ".SetTitle(\"" << fTitle << "\");" << endl;
1212
1213 if (fWeight)
1214 out << " " << name << ".SetWeight(\"" << fWeight->GetRule() << "\");" << endl;
1215
1216 switch (fDimension)
1217 {
1218 case -3:
1219 if (fScale[3]!=1)
1220 out << " " << name << ".SetScaleT(" << fScale[3] << ");" << endl;
1221 case -2:
1222 case 3:
1223 if (fScale[2]!=1)
1224 out << " " << name << ".SetScaleZ(" << fScale[2] << ");" << endl;
1225 case -1:
1226 case 2:
1227 if (fScale[1]!=1)
1228 out << " " << name << ".SetScaleY(" << fScale[1] << ");" << endl;
1229 case 1:
1230 if (fScale[0]!=1)
1231 out << " " << name << ".SetScaleX(" << fScale[0] << ");" << endl;
1232 }
1233}
1234
1235MH3::Type_t MH3::GetType() const
1236{
1237 switch (fDimension)
1238 {
1239 case -1:
1240 return TString(static_cast<TProfile*>(fHist)->GetErrorOption())=="s" ? kProfileSpread : kProfile;
1241 case -2:
1242 return TString(static_cast<TProfile2D*>(fHist)->GetErrorOption())=="s" ? kProfileSpread : kProfile;
1243 case -3:
1244 return TString(static_cast<TProfile3D*>(fHist)->GetErrorOption())=="s" ? kProfileSpread : kProfile;
1245 }
1246 return kHistogram;
1247}
1248
1249// --------------------------------------------------------------------------
1250//
1251// Used to rebuild a MH3 object of the same type (data members,
1252// dimension, ...)
1253//
1254MParContainer *MH3::New() const
1255{
1256 // FIXME: TREAT THE NEW OPTIONS CORRECTLY (PROFILE, LABELS)
1257
1258 MH3 *h = NULL;
1259
1260 if (fData[0] == NULL)
1261 h=new MH3(fDimension);
1262 else
1263 switch (fDimension)
1264 {
1265 case 1:
1266 h=new MH3(fData[0]->GetRule());
1267 break;
1268 case 2:
1269 case -1:
1270 h=new MH3(fData[0]->GetRule(), fData[1]->GetRule(), GetType());
1271 break;
1272 case 3:
1273 case -2:
1274 h=new MH3(fData[0]->GetRule(), fData[1]->GetRule(), fData[2]->GetRule(), GetType());
1275 break;
1276 case -3:
1277 h=new MH3(fData[0]->GetRule(), fData[1]->GetRule(), fData[2]->GetRule(), fData[3]->GetRule());
1278 break;
1279 }
1280
1281 switch (fDimension)
1282 {
1283 case -3:
1284 h->SetScaleZ(fScale[3]);
1285 case -2:
1286 case 3:
1287 h->SetScaleZ(fScale[2]);
1288 case 2:
1289 case -1:
1290 h->SetScaleY(fScale[1]);
1291 case 1:
1292 h->SetScaleX(fScale[0]);
1293 }
1294
1295 if (fWeight)
1296 h->SetWeight(fWeight->GetRule());
1297
1298 return h;
1299}
1300
1301// --------------------------------------------------------------------------
1302//
1303// FIXME
1304//
1305TString MH3::GetRule(const Char_t axis) const
1306{
1307 switch (tolower(axis))
1308 {
1309 case 'x':
1310 case 'X':
1311 return fData[0] ? fData[0]->GetRule() : TString("");
1312 case 'y':
1313 case 'Y':
1314 return fData[1] ? fData[1]->GetRule() : TString("");
1315 case 'z':
1316 case 'Z':
1317 return fData[2] ? fData[2]->GetRule() : TString("");
1318 case 't':
1319 case 'T':
1320 return fData[3] ? fData[3]->GetRule() : TString("");
1321 case 'w':
1322 case 'W':
1323 return fWeight ? fWeight->GetRule() : TString("");
1324 default:
1325 return "<n/a>";
1326 }
1327}
1328
1329// --------------------------------------------------------------------------
1330//
1331// Returns the total number of bins in a histogram (excluding under- and
1332// overflow bins)
1333//
1334Int_t MH3::GetNbins() const
1335{
1336 Int_t num = 1;
1337
1338 switch (TMath::Abs(fDimension))
1339 {
1340 case 3:
1341 num *= fHist->GetNbinsZ()+2;
1342 case 2:
1343 num *= fHist->GetNbinsY()+2;
1344 case 1:
1345 num *= fHist->GetNbinsX()+2;
1346 }
1347
1348 return num;
1349}
1350
1351// --------------------------------------------------------------------------
1352//
1353// Returns the total number of bins in a histogram (excluding under- and
1354// overflow bins) Return -1 if bin is underflow or overflow
1355//
1356Int_t MH3::FindFixBin(Double_t x, Double_t y, Double_t z) const
1357{
1358 const TAxis &axex = *fHist->GetXaxis();
1359 const TAxis &axey = *fHist->GetYaxis();
1360 const TAxis &axez = *fHist->GetZaxis();
1361
1362 Int_t binz = 0;
1363 Int_t biny = 0;
1364 Int_t binx = 0;
1365
1366 switch (fDimension)
1367 {
1368 case 3:
1369 case -2:
1370 binz = axez.FindFixBin(z);
1371 if (binz>axez.GetLast() || binz<axez.GetFirst())
1372 return -1;
1373 case 2:
1374 case -1:
1375 biny = axey.FindFixBin(y);
1376 if (biny>axey.GetLast() || biny<axey.GetFirst())
1377 return -1;
1378 case 1:
1379 binx = axex.FindFixBin(x);
1380 if (binx<axex.GetFirst() || binx>axex.GetLast())
1381 return -1;
1382 }
1383
1384 const Int_t nx = fHist->GetNbinsX()+2;
1385 const Int_t ny = fHist->GetNbinsY()+2;
1386
1387 return binx + nx*(biny +ny*binz);
1388}
1389
1390// --------------------------------------------------------------------------
1391//
1392// Return the MObjLookup corresponding to the axis/character.
1393// Note that only lower-case charecters (x, y, z) are supported.
1394// If for the axis no labels were set, the corresponding
1395// InitLabels is called.
1396//
1397MObjLookup *MH3::GetLabels(char axe)
1398{
1399 if (!fHist)
1400 return 0;
1401
1402 TAxis *x = 0;
1403
1404 switch (axe)
1405 {
1406 case 'x':
1407 x = fHist->GetXaxis();
1408 break;
1409 case 'y':
1410 x = fHist->GetYaxis();
1411 break;
1412 case 'z':
1413 x = fHist->GetZaxis();
1414 break;
1415 }
1416
1417 if (!x)
1418 return 0;
1419
1420 const Int_t idx = axe-'x';
1421
1422 if (!x->GetLabels())
1423 switch (idx)
1424 {
1425 case 0:
1426 InitLabels(kLabelsX);
1427 break;
1428 case 1:
1429 InitLabels(kLabelsY);
1430 break;
1431 case 2:
1432 InitLabels(kLabelsZ);
1433 break;
1434 }
1435
1436 return &fLabels[idx];
1437}
1438
1439// --------------------------------------------------------------------------
1440//
1441// Set a default label which is used if no other is found in the list
1442// of labels. if a default was set already it is overwritten. If the
1443// axis has not yet been initialized to use labels it it now.
1444//
1445void MH3::DefaultLabel(char axe, const char *name)
1446{
1447 MObjLookup *arr = GetLabels(axe);
1448 if (!arr)
1449 return;
1450
1451 if (arr->GetDefault())
1452 {
1453 delete arr->GetDefault();
1454 arr->SetDefault(0);
1455 }
1456
1457 if (name)
1458 arr->SetDefault(new TObjString(name));
1459}
1460
1461// --------------------------------------------------------------------------
1462//
1463// Define a name for a label. More than one label can have the same
1464// name. If the axis has not yet been initialized to use labels
1465// it it now.
1466//
1467void MH3::DefineLabel(char axe, Int_t label, const char *name)
1468{
1469 MObjLookup *arr = GetLabels(axe);
1470
1471 if (!arr || !name)
1472 return;
1473
1474 if (arr->GetObj(label)!=arr->GetDefault())
1475 return;
1476
1477 arr->Add(label, name);
1478}
1479
1480// --------------------------------------------------------------------------
1481//
1482// Define names for labels, like
1483// 1=Trig;2=Cal;4=Ped;8=Lvl2
1484// More than one label can have the same name. If the axis has not
1485// yet been initialized to use labels it it now.
1486//
1487// A default cannot be set here. Use DefaultLabel instead.
1488//
1489void MH3::DefineLabels(char axe, const TString &labels)
1490{
1491 TObjArray *arr = labels.Tokenize(';');
1492
1493 for (int i=0; i<arr->GetEntries(); i++)
1494 {
1495 const char *s = (*arr)[0]->GetName();
1496 const char *v = strchr(s, '=');
1497
1498 if (v)
1499 DefineLabel(axe, atoi(s), v+1);
1500 }
1501
1502 delete arr;
1503}
1504
1505void MH3::RecursiveRemove(TObject *obj)
1506{
1507 if (obj==fHist)
1508 fHist = 0;
1509
1510 MH::RecursiveRemove(obj);
1511}
Note: See TracBrowser for help on using the repository browser.