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

Last change on this file since 1863 was 1833, checked in by tbretz, 22 years ago
*** empty log message ***
File size: 19.1 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
184// --------------------------------------------------------------------------
185//
186// hname is the name of the histogram class which is in the array.
187//
188// istempl=kTRUE tells MHArray to use the first histogram retrieved from the
189// ParameterList by hname to be used as a template. New histograms are not
190// created using the root dictionary, but the New-member function (see
191// MParConatiner)
192// In the case istempl=kFALSE new histograms are created using the root
193// dictionary while hname is the class name. For the creation their
194// default constructor is used.
195//
196MHArray::MHArray(const TString hname, Bool_t istempl, const char *name, const char *title)
197 : fIdx(0), fClass(NULL), fTemplate(NULL)
198{
199 //
200 // set the name and title of this object
201 //
202 fName = name ? name : "MHArray";
203 fTitle = title ? TString(title) : (TString("Base class for Mars histogram arrays:") + hname);
204
205 fMapIdx = new MMap;
206
207 fArray = new TList;
208 fArray->SetOwner();
209
210 if (istempl)
211 {
212 fTemplateName = hname;
213 return;
214 }
215
216 //
217 // try to get class from root environment
218 //
219 fClass = gROOT->GetClass(hname);
220 if (!fClass)
221 {
222 //
223 // if class is not existing in the root environment
224 //
225 *fLog << err << dbginf << "Class '" << hname << "' not existing in dictionary." << endl;
226 }
227
228 //
229 // check for ineritance from MH
230 //
231 if (!fClass->InheritsFrom(MH::Class()))
232 {
233 //
234 // if class doesn't inherit from MH --> error
235 //
236 *fLog << err << dbginf << "Class '" << hname << "' doesn't inherit from MH." << endl;
237 fClass = NULL;
238 }
239}
240
241// --------------------------------------------------------------------------
242//
243// Default Constructor. hname is the name of the histogram class which
244// is in the array.
245//
246// istempl=kTRUE tells MHArray to use the first histogram retrieved from the
247// ParameterList by hname to be used as a template. New histograms are not
248// created using the root dictionary, but the New-member function (see
249// MParConatiner)
250// In the case istempl=kFALSE new histograms are created using the root
251// dictionary while hname is the class name. For the creation their
252// default constructor is used.
253//
254MHArray::MHArray(const MH *hist, const char *name, const char *title)
255 : fIdx(0), fClass(NULL), fTemplate(hist), fTemplateName("<dummy>")
256{
257 //
258 // set the name and title of this object
259 //
260 fName = name ? name : "MHArray";
261 fTitle = title ? TString(title) : (TString("Base class for Mars histogram arrays:") + hist->GetName());
262
263 fMapIdx = new MMap;
264
265 fArray = new TList;
266 fArray->SetOwner();
267}
268
269// --------------------------------------------------------------------------
270//
271// Destructor: Deleteing the array and all histograms which are part of the
272// array.
273//
274MHArray::~MHArray()
275{
276 fArray->Delete();
277 delete fArray;
278 delete fMapIdx;
279}
280
281// --------------------------------------------------------------------------
282//
283// Use this to access the histograms by a key. If you use values like
284// (in this order) 2.5, 7.2, 2.5, 9.3, 9.3, 3.3, 2.2, 1.1
285// it will be mapped to the following indices internally:
286// 0 1 0 2 2 3 4 5
287//
288// WARNING: Make sure that you don't create new histograms by setting
289// a new index (SetIndex or IncIndex) which is equal the size
290// of the array and create new histogram by CreateH. In this
291// case you will confuse the mapping completely.
292//
293void MHArray::SetIndexByKey(Double_t key)
294{
295 fIdx = fMapIdx->Add((Int_t)key);
296}
297
298// --------------------------------------------------------------------------
299//
300// Use this function to access a histogram by its index in the array.
301// Becarefull the index isn't checked!
302//
303MH &MHArray::operator[](Int_t i)
304{
305 return *(MH*)fArray->At(i);
306}
307
308// --------------------------------------------------------------------------
309//
310// Use this function to access a histogram by its index in the array.
311// Becarefull the index isn't checked!
312//
313MH *MHArray::At(Int_t i)
314{
315 return (MH*)fArray->At(i);
316}
317
318// --------------------------------------------------------------------------
319//
320// Use this function to access the histogram corresponding to the
321// currently set index (by Set/Inc/DecIndex or SetIndexByKey)
322// Becarefull the index set isn't checked!
323//
324MH *MHArray::GetH()
325{
326 return (MH*)fArray->At(fIdx);
327}
328
329// --------------------------------------------------------------------------
330//
331// Tries to create a new histogram, adds it as last entry to the array
332// and tries to call SetupFill for it. In case of success the last entry
333// in the array is the new histogram and kTRUE is returned. Otherwise
334// kFALSE is returned.
335//
336Bool_t MHArray::CreateH()
337{
338 TString cname = fClass ? fClass->GetName() : fTemplate->IsA()->GetName();
339
340 MH *hist = NULL;
341 if (fTemplate)
342 {
343 //
344 // create the parameter container as a clone of the existing
345 // template histogram.
346 //
347 hist = (MH*)fTemplate->New();
348 }
349 else
350 {
351 //
352 // create the parameter container of the the given class type
353 //
354 hist = (MH*)fClass->New();
355 }
356 if (!hist)
357 {
358 *fLog << err << dbginf << "Cannot create new instance of class '";
359 *fLog << cname << "' (Maybe no def. constructor)" << endl;
360 return kFALSE;
361 }
362
363 //
364 // Set the name of the container
365 //
366 if (!fTemplate)
367 {
368 TString name = TString(hist->GetName())+";";
369 name += fIdx;
370
371 hist->SetName(name);
372 }
373
374 //
375 // Try to setup filling for the histogram
376 //
377 if (!hist->SetupFill(fParList))
378 {
379 *fLog << err << dbginf << "SetupFill for new histogram of type '";
380 *fLog << cname << "' with Index #" << fIdx << " failed." << endl;
381 delete hist;
382 return kFALSE;
383 }
384
385 fArray->AddLast(hist);
386
387 return kTRUE;
388}
389
390// --------------------------------------------------------------------------
391//
392// Returns kFALSE if the class couldn't be found in the root dictionary or
393// if it doesn't inherit from MH.
394// The parameter list is remembert to be used for SetupFill in case a new
395// histogram is created.
396// The index is reset to 0
397//
398Bool_t MHArray::SetupFill(const MParList *pList)
399{
400 fParList = pList;
401 fIdx = 0;
402
403 if (fTemplate)
404 return kTRUE;
405
406 if (!fTemplateName.IsNull())
407 {
408 fTemplate = (MH*)pList->FindObject(fTemplateName, "MH");
409 return fTemplate ? kTRUE : kFALSE;
410 }
411
412 return fClass ? kTRUE : kFALSE;
413}
414
415// --------------------------------------------------------------------------
416//
417// Call Fill for the present histogram index. If the index is out of
418// bounds the event is skipped. If the index is the number of current
419// histograms in the array a new histogram is created and if creation was
420// successfull filled.
421//
422Bool_t MHArray::Fill(const MParContainer *par)
423{
424 const Int_t n = fArray->GetSize();
425
426 if (fIdx<0 || fIdx>n)
427 {
428 *fLog << warn << "Histogram Index #" << fIdx << " out of bounds (>";
429 *fLog << n << ")... skipped." << endl;
430 return kCONTINUE;
431 }
432
433 if (fIdx==n)
434 if (!CreateH())
435 return kFALSE;
436
437 return GetH()->Fill(par);
438}
439
440Bool_t MHArray::AddHistogram()
441{
442 fIdx=fArray->GetSize();
443
444 return CreateH();
445}
446
447// --------------------------------------------------------------------------
448//
449// Calls Finalize for all histograms in the list. If at least one Finalize
450// fails kFALSE is returned.
451//
452Bool_t MHArray::Finalize()
453{
454 Bool_t rc = kTRUE;
455
456 TIter Next(fArray);
457 MH *hist = NULL;
458
459 while ((hist=(MH*)Next()))
460 if (!hist->Finalize())
461 rc = kFALSE;
462
463 return rc;
464}
465
466// --------------------------------------------------------------------------
467//
468// Print the number of entries in the array
469//
470void MHArray::Print(Option_t *option) const
471{
472 *fLog << all << GetDescriptor() << " contains " << fArray->GetSize();
473 *fLog << " histograms." << endl;
474
475 if (fMapIdx->GetSize()<=0)
476 return;
477
478 *fLog << " idx\t key" << endl;
479 for (int i=0; i<fMapIdx->GetSize(); i++)
480 *fLog << " " << i << "\t<--> " << fMapIdx->GetKey(i) << endl;
481 *fLog << endl;
482}
483
484// --------------------------------------------------------------------------
485//
486// Adds the given object to the given legend (if != NULL). The Legend
487// entry name is created from the key...
488//
489void MHArray::AddLegendEntry(TLegend *leg, TObject *obj, Int_t idx) const
490{
491 if (!leg)
492 return;
493
494 TString name = " ";
495 name += fMapIdx->GetKey(idx);
496 leg->AddEntry(obj, name, "lpf"); // l=line, p=polymarker, f=fill
497}
498
499
500// --------------------------------------------------------------------------
501//
502// The option is the name of the histogram, used to get a histogram from
503// the MH entries by calling their GetHist function.
504//
505void MHArray::Draw(Option_t *opt)
506{
507 if (!gPad)
508 MH::MakeDefCanvas(this);
509
510 const Stat_t sstyle = gStyle->GetOptStat();
511 gStyle->SetOptStat(0);
512
513 //
514 // if the keymapping is used create a legend to identify the histograms
515 //
516 TLegend *leg = NULL;
517 if (fMapIdx->GetSize()>0)
518 {
519 leg = new TLegend(0.85, 0.80, 0.99, 0.99);
520 leg->SetBit(kCanDelete);
521 }
522
523 TIter Next(fArray);
524 MH *hist = (MH*)Next();
525
526 Int_t idx=0;
527 Double_t max=0;
528 Double_t min=0;
529
530 TH1 *h1=NULL;
531
532 //
533 // If the array has at least one entry:
534 // - find the starting boundaries
535 // - draw it and set its line color
536 //
537 if (hist)
538 {
539 if ((h1 = hist->GetHistByName(opt)))
540 {
541 h1->Draw();
542 h1->SetLineColor(idx+2);
543 max = h1->GetMaximum();
544 min = h1->GetMinimum();
545
546 AddLegendEntry(leg, h1, idx);
547 }
548 }
549
550 //
551 // For all following histograms:
552 // - update the boundaries
553 // - draw it and set its line color
554 //
555 while ((hist=(MH*)Next()))
556 {
557 TH1 *h=NULL;
558
559 if (!(h = hist->GetHistByName(opt)))
560 continue;
561
562 h->Draw("same");
563 h->SetLineColor(idx+2);
564 if (max<h->GetMaximum())
565 max = h->GetMaximum();
566 if (min>h->GetMinimum())
567 min = h->GetMinimum();
568
569 AddLegendEntry(leg, h, idx++);
570 }
571
572 //
573 // Now update the drawing region so that everything is displayed
574 //
575 if (h1)
576 {
577 h1->SetMinimum(min>0 ? min*0.95 : min*1.05);
578 h1->SetMaximum(max>0 ? max*1.05 : max*0.95);
579 }
580
581 if (leg)
582 leg->Draw();
583
584 gPad->Modified();
585 gPad->Update();
586
587 gStyle->SetOptStat(sstyle);
588}
589
590// --------------------------------------------------------------------------
591//
592// The option is the name of the histogram, used to get a histogram from
593// the MH entries by calling their GetHistByName function.
594// If the option also contains 'nonew' no new canvas is created.
595// The option "Scale=1" scales the area of all histogram to 1
596// The option "Scale=max" scales the maximum of all histogram to 1
597//
598TObject *MHArray::DrawClone(Option_t *opt) const
599{
600 TString o(opt);
601
602 TCanvas *c = NULL;
603
604 Int_t scale1 = o.Index("scale=1", TString::kIgnoreCase);
605 Int_t scalemax = o.Index("scale=max", TString::kIgnoreCase);
606 Int_t nonew = o.Index("nonew", TString::kIgnoreCase);
607
608 if (o.BeginsWith("scale=1", TString::kIgnoreCase))
609 scale1 = 0;
610 if (o.BeginsWith("scale=max", TString::kIgnoreCase))
611 scalemax = 0;
612 if (o.BeginsWith("nonew", TString::kIgnoreCase))
613 nonew = 0;
614
615 if (nonew>=0)
616 {
617 c = MH::MakeDefCanvas(this);
618
619 //
620 // This is necessary to get the expected bahviour of DrawClone
621 //
622 gROOT->SetSelectedPad(NULL);
623
624 o.Remove(nonew, 5);
625 }
626 if (scale1>=0)
627 o.Remove(scale1, 7);
628 if (scalemax>=0)
629 o.Remove(scalemax, 9);
630
631 const Stat_t sstyle = gStyle->GetOptStat();
632 gStyle->SetOptStat(0);
633
634 //
635 // if the keymapping is used create a legend to identify the histograms
636 //
637 TLegend *leg = NULL;
638 if (fMapIdx->GetSize()>0)
639 {
640 leg = new TLegend(0.85, 0.80, 0.99, 0.99);
641 leg->SetBit(kCanDelete);
642 }
643
644 TIter Next(fArray);
645 MH *hist = (MH*)Next();
646
647 Int_t idx=0;
648 Double_t max=0;
649 Double_t min=0;
650
651 TH1 *h1=NULL;
652
653 //
654 // If the array has at least one entry:
655 // - find the starting boundaries
656 // - draw it and set its line color
657 //
658 if (hist)
659 {
660 if ((h1 = hist->GetHistByName(o)))
661 {
662 h1 = (TH1*)h1->DrawCopy();
663
664 if (scale1>=0)
665 h1->Scale(1./h1->Integral());
666 if (scalemax>=0)
667 h1->Scale(1./h1->GetMaximum());
668
669 h1->SetMarkerColor(idx);
670 h1->SetLineColor(idx+2);
671 h1->SetFillStyle(4000);
672 max = h1->GetMaximum();
673 min = h1->GetMinimum();
674
675 AddLegendEntry(leg, h1, idx++);
676 }
677 }
678
679 //
680 // For all following histograms:
681 // - update the boundaries
682 // - draw it and set its line color
683 //
684 while ((hist=(MH*)Next()))
685 {
686 TH1 *h=NULL;
687
688 if (!(h = hist->GetHistByName(o)))
689 continue;
690
691 h = (TH1*)h->DrawCopy("same");
692
693 if (scale1>=0)
694 h->Scale(1./h->Integral());
695 if (scalemax>=0)
696 h->Scale(1./h->GetMaximum());
697
698 h->SetMarkerColor(idx);
699 h->SetLineColor(idx+2);
700 h->SetFillStyle(4000); // transperent (why is this necessary?)
701 if (max<h->GetMaximum())
702 max = h->GetMaximum();
703 if (min>h->GetMinimum())
704 min = h->GetMinimum();
705
706 AddLegendEntry(leg, h, idx++);
707 }
708
709 //
710 // Now update the drawing region so that everything is displayed
711 //
712 if (h1)
713 {
714 h1->SetMinimum(min>0 ? min*0.95 : min*1.05);
715 h1->SetMaximum(max>0 ? max*1.05 : max*0.95);
716 }
717
718 if (leg)
719 leg->Draw();
720
721 gPad->Modified();
722 gPad->Update();
723
724 gStyle->SetOptStat(sstyle);
725
726 return c;
727}
Note: See TracBrowser for help on using the repository browser.