source: trunk/MagicSoft/Mars/mhist/MHArray.cc@ 1941

Last change on this file since 1941 was 1895, checked in by tbretz, 22 years ago
*** empty log message ***
File size: 20.2 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// MHArray
28//
29// is a sequential collection of mars histograms. If the given index to
30// call the Fill function of the histogram excceeds the size of the
31// array by 1 a new entry is created.
32//
33// With Set/Inc/DecIndex you may specify the actual index of the histogram
34// wich should be filles by Fill.
35//
36// Use GetH to get the current histogram, the []-operator get the histogram
37// by its index.
38//
39// To access the histograms by a key instead of an index use SetIndexByKey
40// instead of Set/Inc/DecIndex. It will take the integerpart of the
41// floating point value (2 in case of 2.9). For each new key a new
42// index in the Mapping Table is created. So that you can access your
43// histograms by the key (eg in case of the Angle Theta=23.2deg use
44// SetIndexByKey(23.2)
45//
46// If the index is equal to the number of histograms in the array a call
47// to the Fill-member-function will create a new histogram.
48//
49// In the constructor istempl leads to two different behaviours of the
50// MHArray:
51//
52// - istempl=kTRUE tells MHArray to use the first histogram retrieved from
53// the Parameterlist by hname to be used as a template. New histograms
54// are not created using the root dictionary, but the New-member function
55// (see MParConatiner)
56// - In the case istempl=kFALSE new histograms are created using the root
57// dictionary while hname is the class name. For the creation their
58// default constructor is used.
59//
60//////////////////////////////////////////////////////////////////////////////
61#include "MHArray.h"
62
63#include <TH1.h>
64#include <TH2.h>
65#include <TH3.h>
66#include <TStyle.h>
67#include <TGaxis.h>
68#include <TCanvas.h>
69#include <TLegend.h>
70#include <TPaveStats.h>
71
72#include "MLog.h"
73#include "MLogManip.h"
74
75#include "MParList.h"
76#include "MParContainer.h"
77
78#include "MBinning.h"
79
80ClassImp(MHArray);
81
82//////////////////////////////////////////////////////////////////////////////
83//
84// MMap
85//
86// This class maps a key-value to a given value. In its simple versions it
87// maps a key to an index.
88//
89//////////////////////////////////////////////////////////////////////////////
90#include <TArrayI.h>
91
92class MMap
93{
94private:
95 TArrayI fKeys;
96 TArrayI fValues;
97
98 Int_t K(Int_t i) const { return ((TArrayI)fKeys)[i]; }
99 Int_t V(Int_t i) const { return ((TArrayI)fValues)[i]; }
100
101public:
102 // --------------------------------------------------------------------------
103 //
104 // Return the size of the table
105 //
106 Int_t GetSize() const
107 {
108 return fKeys.GetSize();
109 }
110
111 // --------------------------------------------------------------------------
112 //
113 // Get the value which corresponds to the given key-value
114 //
115 Int_t GetValue(Int_t key) const
116 {
117 const Int_t n = fKeys.GetSize();
118 for (int i=0; i<n; i++)
119 {
120 if (K(i)==key)
121 return V(i);
122 }
123 return -1;
124 }
125
126 // --------------------------------------------------------------------------
127 //
128 // Get the key which corresponds to the given index
129 //
130 Int_t GetKey(Int_t value) const
131 {
132 const Int_t n = fKeys.GetSize();
133 for (int i=0; i<n; i++)
134 {
135 if (V(i)==value)
136 return K(i);
137 }
138 return -1;
139 }
140
141 // --------------------------------------------------------------------------
142 //
143 // Adds a new pair key-value. While the key is the key to the value.
144 // if the key already exists the pair is ignored.
145 //
146 void Add(Int_t key, Int_t value)
147 {
148 if (GetValue(key)>=0)
149 return;
150
151 const Int_t n = fKeys.GetSize();
152
153 fKeys.Set(n+1);
154 fValues.Set(n+1);
155
156 fKeys[n] = key;
157 fValues[n] = value;
158 }
159
160 // --------------------------------------------------------------------------
161 //
162 // Adds a new pair key-value. While the key is the key to the value.
163 // In this case the value is an automatically sequential created index.
164 // if the key already exists the pair is ignored.
165 //
166 Int_t Add(Int_t key)
167 {
168 const Int_t k = GetValue(key);
169 if (k>=0)
170 return k;
171
172 const Int_t n = fKeys.GetSize();
173
174 fKeys.Set(n+1);
175 fValues.Set(n+1);
176
177 fKeys[n] = key;
178 fValues[n] = n;
179
180 return n;
181 }
182};
183
184void MHArray::Init(const char *name)
185{
186 fName = name ? name : "MHArray";
187
188 fMapIdx = new MMap;
189
190 fArray = new TList;
191 fArray->SetOwner();
192}
193
194// --------------------------------------------------------------------------
195//
196// Can replace a constructor. Use the default constructor and afterwards
197// the Set function of your need.
198//
199void MHArray::Set(const TString hname, Bool_t istempl)
200{
201 if (fTemplate || fClass || fTemplateName!="<dummy>")
202 {
203 *fLog << warn << "WARNING - MHArray already setup... Set ignored." << endl;
204 return;
205 }
206
207 if (istempl)
208 {
209 fTemplateName = hname;
210 return;
211 }
212
213 //
214 // try to get class from root environment
215 //
216 fClass = gROOT->GetClass(hname);
217 if (!fClass)
218 {
219 //
220 // if class is not existing in the root environment
221 //
222 *fLog << err << dbginf << "Class '" << hname << "' not existing in dictionary." << endl;
223 }
224
225 //
226 // check for ineritance from MH
227 //
228 if (!fClass->InheritsFrom(MH::Class()))
229 {
230 //
231 // if class doesn't inherit from MH --> error
232 //
233 *fLog << err << dbginf << "Class '" << hname << "' doesn't inherit from MH." << endl;
234 fClass = NULL;
235 }
236}
237
238// --------------------------------------------------------------------------
239//
240// Can replace a constructor. Use the default constructor and afterwards
241// the Set function of your need.
242//
243void MHArray::Set(const MH *hist)
244{
245 fIdx=0;
246 fClass=NULL;
247 fTemplate=hist;
248 fTemplateName="<dummy>";
249}
250
251
252// --------------------------------------------------------------------------
253//
254// hname is the name of the histogram class which is in the array.
255//
256// istempl=kTRUE tells MHArray to use the first histogram retrieved from the
257// ParameterList by hname to be used as a template. New histograms are not
258// created using the root dictionary, but the New-member function (see
259// MParConatiner)
260// In the case istempl=kFALSE new histograms are created using the root
261// dictionary while hname is the class name. For the creation their
262// default constructor is used.
263//
264MHArray::MHArray(const TString hname, Bool_t istempl, const char *name, const char *title)
265 : fIdx(0), fClass(NULL), fTemplate(NULL)
266{
267 //
268 // set the name and title of this object
269 //
270 Init(name);
271 fTitle = title ? TString(title) : (TString("Base class for Mars histogram arrays:") + hname);
272
273 Set(hname, istempl);
274}
275
276// --------------------------------------------------------------------------
277//
278// Default constructor. Use MHArray::Set to setup the MHArray afterwards
279//
280MHArray::MHArray(const char *name, const char *title)
281 : fIdx(0), fClass(NULL), fTemplate(NULL), fTemplateName("<dummy>")
282{
283 //
284 // set the name and title of this object
285 //
286 Init(name);
287 fTitle = title ? title : "A Mars histogram array";
288}
289
290// --------------------------------------------------------------------------
291//
292// hname is the name of the histogram class which is in the array.
293//
294// istempl=kTRUE tells MHArray to use the first histogram retrieved from the
295// ParameterList by hname to be used as a template. New histograms are not
296// created using the root dictionary, but the New-member function (see
297// MParConatiner)
298// In the case istempl=kFALSE new histograms are created using the root
299// dictionary while hname is the class name. For the creation their
300// default constructor is used.
301//
302MHArray::MHArray(const MH *hist, const char *name, const char *title)
303 : fIdx(0), fClass(NULL), fTemplate(hist), fTemplateName("<dummy>")
304{
305 //
306 // set the name and title of this object
307 //
308 Init(name);
309 fTitle = title ? TString(title) : (TString("Base class for Mars histogram arrays:") + hist->GetName());
310}
311
312// --------------------------------------------------------------------------
313//
314// Destructor: Deleteing the array and all histograms which are part of the
315// array.
316//
317MHArray::~MHArray()
318{
319 fArray->Delete();
320 delete fArray;
321 delete fMapIdx;
322}
323
324// --------------------------------------------------------------------------
325//
326// Use this to access the histograms by a key. If you use values like
327// (in this order) 2.5, 7.2, 2.5, 9.3, 9.3, 3.3, 2.2, 1.1
328// it will be mapped to the following indices internally:
329// 0 1 0 2 2 3 4 5
330//
331// WARNING: Make sure that you don't create new histograms by setting
332// a new index (SetIndex or IncIndex) which is equal the size
333// of the array and create new histogram by CreateH. In this
334// case you will confuse the mapping completely.
335//
336void MHArray::SetIndexByKey(Double_t key)
337{
338 fIdx = fMapIdx->Add((Int_t)key);
339}
340
341// --------------------------------------------------------------------------
342//
343// Use this function to access a histogram by its index in the array.
344// Becarefull the index isn't checked!
345//
346MH &MHArray::operator[](Int_t i)
347{
348 return *(MH*)fArray->At(i);
349}
350
351// --------------------------------------------------------------------------
352//
353// Use this function to access a histogram by its index in the array.
354// Becarefull the index isn't checked!
355//
356MH *MHArray::At(Int_t i)
357{
358 return (MH*)fArray->At(i);
359}
360
361// --------------------------------------------------------------------------
362//
363// Use this function to access the histogram corresponding to the
364// currently set index (by Set/Inc/DecIndex or SetIndexByKey)
365// Becarefull the index set isn't checked!
366//
367MH *MHArray::GetH()
368{
369 return (MH*)fArray->At(fIdx);
370}
371
372// --------------------------------------------------------------------------
373//
374// Tries to create a new histogram, adds it as last entry to the array
375// and tries to call SetupFill for it. In case of success the last entry
376// in the array is the new histogram and kTRUE is returned. Otherwise
377// kFALSE is returned.
378//
379Bool_t MHArray::CreateH()
380{
381 TString cname = fClass ? fClass->GetName() : fTemplate->IsA()->GetName();
382
383 MH *hist = NULL;
384 if (fTemplate)
385 {
386 //
387 // create the parameter container as a clone of the existing
388 // template histogram.
389 //
390 hist = (MH*)fTemplate->New();
391 }
392 else
393 {
394 //
395 // create the parameter container of the the given class type
396 //
397 hist = (MH*)fClass->New();
398 }
399 if (!hist)
400 {
401 *fLog << err << dbginf << "Cannot create new instance of class '";
402 *fLog << cname << "' (Maybe no def. constructor)" << endl;
403 return kFALSE;
404 }
405
406 //
407 // Set the name of the container
408 //
409 if (!fTemplate)
410 {
411 TString name = TString(hist->GetName())+";";
412 name += fIdx;
413
414 hist->SetName(name);
415 }
416
417 //
418 // Try to setup filling for the histogram
419 //
420 if (!hist->SetupFill(fParList))
421 {
422 *fLog << err << dbginf << "SetupFill for new histogram of type '";
423 *fLog << cname << "' with Index #" << fIdx << " failed." << endl;
424 delete hist;
425 return kFALSE;
426 }
427
428 fArray->AddLast(hist);
429
430 return kTRUE;
431}
432
433// --------------------------------------------------------------------------
434//
435// Returns kFALSE if the class couldn't be found in the root dictionary or
436// if it doesn't inherit from MH.
437// The parameter list is remembert to be used for SetupFill in case a new
438// histogram is created.
439// The index is reset to 0
440//
441Bool_t MHArray::SetupFill(const MParList *pList)
442{
443 fParList = pList;
444 fIdx = 0;
445
446 if (fTemplate)
447 return kTRUE;
448
449 if (!fTemplateName.IsNull())
450 {
451 fTemplate = (MH*)pList->FindObject(fTemplateName, "MH");
452 return fTemplate ? kTRUE : kFALSE;
453 }
454
455 return fClass ? kTRUE : kFALSE;
456}
457
458// --------------------------------------------------------------------------
459//
460// Call Fill for the present histogram index. If the index is out of
461// bounds the event is skipped. If the index is the number of current
462// histograms in the array a new histogram is created and if creation was
463// successfull filled.
464//
465Bool_t MHArray::Fill(const MParContainer *par)
466{
467 const Int_t n = fArray->GetSize();
468
469 if (fIdx<0 || fIdx>n)
470 {
471 *fLog << warn << "Histogram Index #" << fIdx << " out of bounds (>";
472 *fLog << n << ")... skipped." << endl;
473 return kCONTINUE;
474 }
475
476 if (fIdx==n)
477 if (!CreateH())
478 return kFALSE;
479
480 return GetH()->Fill(par);
481}
482
483Bool_t MHArray::AddHistogram()
484{
485 fIdx=fArray->GetSize();
486
487 return CreateH();
488}
489
490// --------------------------------------------------------------------------
491//
492// Calls Finalize for all histograms in the list. If at least one Finalize
493// fails kFALSE is returned.
494//
495Bool_t MHArray::Finalize()
496{
497 Bool_t rc = kTRUE;
498
499 TIter Next(fArray);
500 MH *hist = NULL;
501
502 while ((hist=(MH*)Next()))
503 if (!hist->Finalize())
504 rc = kFALSE;
505
506 return rc;
507}
508
509// --------------------------------------------------------------------------
510//
511// Print the number of entries in the array
512//
513void MHArray::Print(Option_t *option) const
514{
515 *fLog << all << GetDescriptor() << " contains " << fArray->GetSize();
516 *fLog << " histograms." << endl;
517
518 if (fMapIdx->GetSize()<=0)
519 return;
520
521 *fLog << " idx\t key" << endl;
522 for (int i=0; i<fMapIdx->GetSize(); i++)
523 *fLog << " " << i << "\t<--> " << fMapIdx->GetKey(i) << endl;
524 *fLog << endl;
525}
526
527// --------------------------------------------------------------------------
528//
529// Adds the given object to the given legend (if != NULL). The Legend
530// entry name is created from the key...
531//
532void MHArray::AddLegendEntry(TLegend *leg, TObject *obj, Int_t idx) const
533{
534 if (!leg)
535 return;
536
537 TString name = " ";
538 name += fMapIdx->GetKey(idx);
539 leg->AddEntry(obj, name, "lpf"); // l=line, p=polymarker, f=fill
540}
541
542
543// --------------------------------------------------------------------------
544//
545// The option is the name of the histogram, used to get a histogram from
546// the MH entries by calling their GetHist function.
547//
548void MHArray::Draw(Option_t *opt)
549{
550 if (!gPad)
551 MH::MakeDefCanvas(this);
552
553 const Stat_t sstyle = gStyle->GetOptStat();
554 gStyle->SetOptStat(0);
555
556 //
557 // if the keymapping is used create a legend to identify the histograms
558 //
559 TLegend *leg = NULL;
560 if (fMapIdx->GetSize()>0)
561 {
562 leg = new TLegend(0.85, 0.80, 0.99, 0.99);
563 leg->SetBit(kCanDelete);
564 }
565
566 TIter Next(fArray);
567 MH *hist = (MH*)Next();
568
569 Int_t idx=0;
570 Double_t max=0;
571 Double_t min=0;
572
573 TH1 *h1=NULL;
574
575 //
576 // If the array has at least one entry:
577 // - find the starting boundaries
578 // - draw it and set its line color
579 //
580 if (hist)
581 {
582 if ((h1 = hist->GetHistByName(opt)))
583 {
584 h1->Draw();
585 h1->SetLineColor(idx+2);
586 max = h1->GetMaximum();
587 min = h1->GetMinimum();
588
589 AddLegendEntry(leg, h1, idx);
590 }
591 }
592
593 //
594 // For all following histograms:
595 // - update the boundaries
596 // - draw it and set its line color
597 //
598 while ((hist=(MH*)Next()))
599 {
600 TH1 *h=NULL;
601
602 if (!(h = hist->GetHistByName(opt)))
603 continue;
604
605 h->Draw("same");
606 h->SetLineColor(idx+2);
607 if (max<h->GetMaximum())
608 max = h->GetMaximum();
609 if (min>h->GetMinimum())
610 min = h->GetMinimum();
611
612 AddLegendEntry(leg, h, idx++);
613 }
614
615 //
616 // Now update the drawing region so that everything is displayed
617 //
618 if (h1)
619 {
620 h1->SetMinimum(min>0 ? min*0.95 : min*1.05);
621 h1->SetMaximum(max>0 ? max*1.05 : max*0.95);
622 }
623
624 if (leg)
625 leg->Draw();
626
627 gPad->Modified();
628 gPad->Update();
629
630 gStyle->SetOptStat(sstyle);
631}
632
633// --------------------------------------------------------------------------
634//
635// The option is the name of the histogram, used to get a histogram from
636// the MH entries by calling their GetHistByName function.
637// If the option also contains 'nonew' no new canvas is created.
638// The option "Scale=1" scales the area of all histogram to 1
639// The option "Scale=max" scales the maximum of all histogram to 1
640//
641TObject *MHArray::DrawClone(Option_t *opt) const
642{
643 TString o(opt);
644
645 TCanvas *c = NULL;
646
647 Int_t scale1 = o.Index("scale=1", TString::kIgnoreCase);
648 Int_t scalemax = o.Index("scale=max", TString::kIgnoreCase);
649 Int_t nonew = o.Index("nonew", TString::kIgnoreCase);
650
651 if (o.BeginsWith("scale=1", TString::kIgnoreCase))
652 scale1 = 0;
653 if (o.BeginsWith("scale=max", TString::kIgnoreCase))
654 scalemax = 0;
655 if (o.BeginsWith("nonew", TString::kIgnoreCase))
656 nonew = 0;
657
658 if (nonew>=0)
659 {
660 c = MH::MakeDefCanvas(this);
661
662 //
663 // This is necessary to get the expected bahviour of DrawClone
664 //
665 gROOT->SetSelectedPad(NULL);
666
667 o.Remove(nonew, 5);
668 }
669 if (scale1>=0)
670 o.Remove(scale1, 7);
671 if (scalemax>=0)
672 o.Remove(scalemax, 9);
673
674 const Stat_t sstyle = gStyle->GetOptStat();
675 gStyle->SetOptStat(0);
676
677 //
678 // if the keymapping is used create a legend to identify the histograms
679 //
680 TLegend *leg = NULL;
681 if (fMapIdx->GetSize()>0)
682 {
683 leg = new TLegend(0.85, 0.80, 0.99, 0.99);
684 leg->SetBit(kCanDelete);
685 }
686
687 TIter Next(fArray);
688 MH *hist = (MH*)Next();
689
690 Int_t idx=0;
691 Double_t max=0;
692 Double_t min=0;
693
694 TH1 *h1=NULL;
695
696 //
697 // If the array has at least one entry:
698 // - find the starting boundaries
699 // - draw it and set its line color
700 //
701 if (hist)
702 {
703 if ((h1 = hist->GetHistByName(o)))
704 {
705 h1 = (TH1*)h1->DrawCopy();
706
707 if (scale1>=0)
708 h1->Scale(1./h1->Integral());
709 if (scalemax>=0)
710 h1->Scale(1./h1->GetMaximum());
711
712 h1->SetMarkerColor(idx);
713 h1->SetLineColor(idx+2);
714 h1->SetFillStyle(4000);
715 max = h1->GetMaximum();
716 min = h1->GetMinimum();
717
718 AddLegendEntry(leg, h1, idx++);
719 }
720 }
721
722 //
723 // For all following histograms:
724 // - update the boundaries
725 // - draw it and set its line color
726 //
727 while ((hist=(MH*)Next()))
728 {
729 TH1 *h=NULL;
730
731 if (!(h = hist->GetHistByName(o)))
732 continue;
733
734 h = (TH1*)h->DrawCopy("same");
735
736 if (scale1>=0)
737 h->Scale(1./h->Integral());
738 if (scalemax>=0)
739 h->Scale(1./h->GetMaximum());
740
741 h->SetMarkerColor(idx);
742 h->SetLineColor(idx+2);
743 h->SetFillStyle(4000); // transperent (why is this necessary?)
744 if (max<h->GetMaximum())
745 max = h->GetMaximum();
746 if (min>h->GetMinimum())
747 min = h->GetMinimum();
748
749 AddLegendEntry(leg, h, idx++);
750 }
751
752 //
753 // Now update the drawing region so that everything is displayed
754 //
755 if (h1)
756 {
757 h1->SetMinimum(min>0 ? min*0.95 : min*1.05);
758 h1->SetMaximum(max>0 ? max*1.05 : max*0.95);
759 }
760
761 if (leg)
762 leg->Draw();
763
764 gPad->Modified();
765 gPad->Update();
766
767 gStyle->SetOptStat(sstyle);
768
769 return c;
770}
Note: See TracBrowser for help on using the repository browser.