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

Last change on this file since 1765 was 1629, checked in by tbretz, 22 years ago
*** empty log message ***
File size: 19.0 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
440// --------------------------------------------------------------------------
441//
442// Calls Finalize for all histograms in the list. If at least one Finalize
443// fails kFALSE is returned.
444//
445Bool_t MHArray::Finalize()
446{
447 Bool_t rc = kTRUE;
448
449 TIter Next(fArray);
450 MH *hist = NULL;
451
452 while ((hist=(MH*)Next()))
453 if (!hist->Finalize())
454 rc = kFALSE;
455
456 return rc;
457}
458
459// --------------------------------------------------------------------------
460//
461// Print the number of entries in the array
462//
463void MHArray::Print(Option_t *option) const
464{
465 *fLog << all << GetDescriptor() << " contains " << fArray->GetSize();
466 *fLog << " histograms." << endl;
467
468 if (fMapIdx->GetSize()<=0)
469 return;
470
471 *fLog << " idx\t key" << endl;
472 for (int i=0; i<fMapIdx->GetSize(); i++)
473 *fLog << " " << i << "\t<--> " << fMapIdx->GetKey(i) << endl;
474 *fLog << endl;
475}
476
477// --------------------------------------------------------------------------
478//
479// Adds the given object to the given legend (if != NULL). The Legend
480// entry name is created from the key...
481//
482void MHArray::AddLegendEntry(TLegend *leg, TObject *obj, Int_t idx) const
483{
484 if (!leg)
485 return;
486
487 TString name = " ";
488 name += fMapIdx->GetKey(idx);
489 leg->AddEntry(obj, name, "lpf"); // l=line, p=polymarker, f=fill
490}
491
492
493// --------------------------------------------------------------------------
494//
495// The option is the name of the histogram, used to get a histogram from
496// the MH entries by calling their GetHist function.
497//
498void MHArray::Draw(Option_t *opt)
499{
500 if (!gPad)
501 MH::MakeDefCanvas(this);
502
503 const Stat_t sstyle = gStyle->GetOptStat();
504 gStyle->SetOptStat(0);
505
506 //
507 // if the keymapping is used create a legend to identify the histograms
508 //
509 TLegend *leg = NULL;
510 if (fMapIdx->GetSize()>0)
511 {
512 leg = new TLegend(0.85, 0.80, 0.99, 0.99);
513 leg->SetBit(kCanDelete);
514 }
515
516 TIter Next(fArray);
517 MH *hist = (MH*)Next();
518
519 Int_t idx=0;
520 Double_t max=0;
521 Double_t min=0;
522
523 TH1 *h1=NULL;
524
525 //
526 // If the array has at least one entry:
527 // - find the starting boundaries
528 // - draw it and set its line color
529 //
530 if (hist)
531 {
532 if ((h1 = hist->GetHistByName(opt)))
533 {
534 h1->Draw();
535 h1->SetLineColor(idx+2);
536 max = h1->GetMaximum();
537 min = h1->GetMinimum();
538
539 AddLegendEntry(leg, h1, idx);
540 }
541 }
542
543 //
544 // For all following histograms:
545 // - update the boundaries
546 // - draw it and set its line color
547 //
548 while ((hist=(MH*)Next()))
549 {
550 TH1 *h=NULL;
551
552 if (!(h = hist->GetHistByName(opt)))
553 continue;
554
555 h->Draw("same");
556 h->SetLineColor(idx+2);
557 if (max<h->GetMaximum())
558 max = h->GetMaximum();
559 if (min>h->GetMinimum())
560 min = h->GetMinimum();
561
562 AddLegendEntry(leg, h, idx++);
563 }
564
565 //
566 // Now update the drawing region so that everything is displayed
567 //
568 if (h1)
569 {
570 h1->SetMinimum(min>0 ? min*0.95 : min*1.05);
571 h1->SetMaximum(max>0 ? max*1.05 : max*0.95);
572 }
573
574 if (leg)
575 leg->Draw();
576
577 gPad->Modified();
578 gPad->Update();
579
580 gStyle->SetOptStat(sstyle);
581}
582
583// --------------------------------------------------------------------------
584//
585// The option is the name of the histogram, used to get a histogram from
586// the MH entries by calling their GetHistByName function.
587// If the option also contains 'nonew' no new canvas is created.
588// The option "Scale=1" scales the area of all histogram to 1
589// The option "Scale=max" scales the maximum of all histogram to 1
590//
591TObject *MHArray::DrawClone(Option_t *opt) const
592{
593 TString o(opt);
594
595 TCanvas *c = NULL;
596
597 Int_t scale1 = o.Index("scale=1", TString::kIgnoreCase);
598 Int_t scalemax = o.Index("scale=max", TString::kIgnoreCase);
599 Int_t nonew = o.Index("nonew", TString::kIgnoreCase);
600
601 if (o.BeginsWith("scale=1", TString::kIgnoreCase))
602 scale1 = 0;
603 if (o.BeginsWith("scale=max", TString::kIgnoreCase))
604 scalemax = 0;
605 if (o.BeginsWith("nonew", TString::kIgnoreCase))
606 nonew = 0;
607
608 if (nonew>=0)
609 {
610 c = MH::MakeDefCanvas(this);
611
612 //
613 // This is necessary to get the expected bahviour of DrawClone
614 //
615 gROOT->SetSelectedPad(NULL);
616
617 o.Remove(nonew, 5);
618 }
619 if (scale1>=0)
620 o.Remove(scale1, 7);
621 if (scalemax>=0)
622 o.Remove(scalemax, 9);
623
624 const Stat_t sstyle = gStyle->GetOptStat();
625 gStyle->SetOptStat(0);
626
627 //
628 // if the keymapping is used create a legend to identify the histograms
629 //
630 TLegend *leg = NULL;
631 if (fMapIdx->GetSize()>0)
632 {
633 leg = new TLegend(0.85, 0.80, 0.99, 0.99);
634 leg->SetBit(kCanDelete);
635 }
636
637 TIter Next(fArray);
638 MH *hist = (MH*)Next();
639
640 Int_t idx=0;
641 Double_t max=0;
642 Double_t min=0;
643
644 TH1 *h1=NULL;
645
646 //
647 // If the array has at least one entry:
648 // - find the starting boundaries
649 // - draw it and set its line color
650 //
651 if (hist)
652 {
653 if ((h1 = hist->GetHistByName(o)))
654 {
655 h1 = (TH1*)h1->DrawCopy();
656
657 if (scale1>=0)
658 h1->Scale(1./h1->Integral());
659 if (scalemax>=0)
660 h1->Scale(1./h1->GetMaximum());
661
662 h1->SetMarkerColor(idx);
663 h1->SetLineColor(idx+2);
664 h1->SetFillStyle(4000);
665 max = h1->GetMaximum();
666 min = h1->GetMinimum();
667
668 AddLegendEntry(leg, h1, idx++);
669 }
670 }
671
672 //
673 // For all following histograms:
674 // - update the boundaries
675 // - draw it and set its line color
676 //
677 while ((hist=(MH*)Next()))
678 {
679 TH1 *h=NULL;
680
681 if (!(h = hist->GetHistByName(o)))
682 continue;
683
684 h = (TH1*)h->DrawCopy("same");
685
686 if (scale1>=0)
687 h->Scale(1./h->Integral());
688 if (scalemax>=0)
689 h->Scale(1./h->GetMaximum());
690
691 h->SetMarkerColor(idx);
692 h->SetLineColor(idx+2);
693 h->SetFillStyle(4000); // transperent (why is this necessary?)
694 if (max<h->GetMaximum())
695 max = h->GetMaximum();
696 if (min>h->GetMinimum())
697 min = h->GetMinimum();
698
699 AddLegendEntry(leg, h, idx++);
700 }
701
702 //
703 // Now update the drawing region so that everything is displayed
704 //
705 if (h1)
706 {
707 h1->SetMinimum(min>0 ? min*0.95 : min*1.05);
708 h1->SetMaximum(max>0 ? max*1.05 : max*0.95);
709 }
710
711 if (leg)
712 leg->Draw();
713
714 gPad->Modified();
715 gPad->Update();
716
717 gStyle->SetOptStat(sstyle);
718
719 return c;
720}
Note: See TracBrowser for help on using the repository browser.