]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWGLF/FORWARD/analysis2/scripts/SummaryDrawer.C
Merge branch 'master' of https://git.cern.ch/reps/AliRoot
[u/mrichter/AliRoot.git] / PWGLF / FORWARD / analysis2 / scripts / SummaryDrawer.C
1 /**
2  * @file   SummaryDrawer.C
3  * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
4  * @date   Sun Nov 25 11:36:41 2012
5  * 
6  * @brief  Base class for classes to draw summaries 
7  * 
8  * 
9  */
10 #ifndef SUMMARYDRAWER_C
11 # define SUMMARYDRAWER_C
12 # ifndef __CINT__
13 #  include <THStack.h>
14 #  include <TH1.h>
15 #  include <TH2.h>
16 #  include <TH3.h>
17 #  include <TParameter.h>
18 #  include <TCanvas.h>
19 #  include <TList.h>
20 #  include <TFile.h>
21 #  include <TError.h>
22 #  include <TLatex.h>
23 #  include <TLegend.h>
24 #  include <TLegendEntry.h>
25 #  include <TMath.h>
26 #  include <TString.h>
27 #  include <TStyle.h>
28 #  include <TSystem.h>
29 #  include <TProfile.h>
30 #  include <TGaxis.h>
31 #  include <TPad.h>
32 #  include <TRegexp.h>
33 #  include <TGraph.h>
34 # else 
35 #  ifdef __ACLIC__
36 class THStack;
37 class TH1;
38 class TH2;
39 class TH3;
40 class TCollection;
41 class TCanvas;
42 class TVirtualPad;
43 class TPad;
44 class TLatex;
45 class TAxis;
46 #  endif
47 # endif
48
49 /**
50  * Base class for summary drawers
51  * 
52  */
53 class SummaryDrawer 
54 {
55 public:
56   enum { 
57     kLogx   = 0x1, 
58     kLogy   = 0x2, 
59     kLogz   = 0x4, 
60     kLegend = 0x10, 
61     kGridx  = 0x100, 
62     kGridy  = 0x200, 
63     kGridz  = 0x400,
64     kSilent = 0x800
65   };
66   enum { 
67     kLandscape         = 0x100, 
68     kPause             = 0x200
69   };    
70   SummaryDrawer() 
71     : fCanvas(0), 
72       fTop(0), 
73       fBody(0),
74       fHeader(0),
75       fParName(0),
76       fParVal(0),
77       fPause(false),
78       fLandscape(false), 
79       fRingMap(0), 
80       fPDF(true),
81       fLastTitle("")
82   {
83     fRingMap = new TVirtualPad*[6];
84     fRingMap[0] = 0;
85     fRingMap[1] = 0;
86     fRingMap[2] = 0;
87     fRingMap[3] = 0;
88     fRingMap[4] = 0;
89     fRingMap[5] = 0;
90   }
91   virtual ~SummaryDrawer() {}
92
93 protected:
94   /** 
95    * Get the standard color for a ring  
96    *
97    * @param d Detector
98    * @param r Ring 
99    * 
100    * @return 
101    */
102   static Color_t RingColor(UShort_t d, Char_t r)
103   { 
104     return ((d == 1 ? kRed : (d == 2 ? kGreen : kBlue))
105             + ((r == 'I' || r == 'i') ? 2 : -3));
106   }
107   static void SysString(UShort_t sys, TString& str)
108   {
109     str = "?";
110     switch (sys) { 
111     case 1: str = "pp"; break;
112     case 2: str = "PbPb"; break;
113     case 3: str = "pPb"; break;
114     }
115   }
116   static void SNNString(UShort_t sNN, TString& str)
117   {
118     str = "?";
119     if      (sNN < 1000) str = Form("%dGeV", sNN);
120     else if (sNN < 3000) str = Form("%4.2fTeV", 0.001*sNN);
121     else                 str = Form("%dTeV", sNN/1000);
122   }
123   /** 
124    * Append an & to a string and the next term.
125    * 
126    * @param trg  Output string
127    * @param what Term
128    */
129   static void AppendAnd(TString& trg, const TString& what)
130   {
131     if (!trg.IsNull()) trg.Append(" & ");
132     trg.Append(what);
133   }
134   static void TriggerString(ULong_t trigger, TString& str)
135   {
136     str = "";
137         /** 
138      * Bits of the trigger pattern
139      */
140     enum { 
141       /** In-elastic collision */
142       kInel        = 0x0001, 
143       /** In-elastic collision with at least one SPD tracklet */
144       kInelGt0     = 0x0002, 
145       /** Non-single diffractive collision */
146       kNSD         = 0x0004, 
147       /** Empty bunch crossing */
148       kEmpty       = 0x0008, 
149       /** A-side trigger */
150       kA           = 0x0010, 
151       /** B(arrel) trigger */
152       kB           = 0x0020, 
153       /** C-side trigger */
154       kC           = 0x0080,  
155       /** Empty trigger */
156       kE           = 0x0100,
157       /** pileup from SPD */
158       kPileUp      = 0x0200,    
159       /** true NSD from MC */
160       kMCNSD       = 0x0400,    
161       /** Offline MB triggered */
162       kOffline     = 0x0800,
163       /** At least one SPD cluster */ 
164       kNClusterGt0 = 0x1000,
165       /** V0-AND trigger */
166       kV0AND       = 0x2000, 
167       /** Satellite event */
168       kSatellite   = 0x4000
169     };
170     if ((trigger & kInel)        != 0x0) AppendAnd(str, "INEL");
171     if ((trigger & kInelGt0)     != 0x0) AppendAnd(str, "INEL>0");
172     if ((trigger & kNSD)         != 0x0) AppendAnd(str, "NSD");
173     if ((trigger & kV0AND)       != 0x0) AppendAnd(str, "V0AND");
174     if ((trigger & kA)           != 0x0) AppendAnd(str, "A");
175     if ((trigger & kB)           != 0x0) AppendAnd(str, "B");
176     if ((trigger & kC)           != 0x0) AppendAnd(str, "C");
177     if ((trigger & kE)           != 0x0) AppendAnd(str, "E");
178     if ((trigger & kMCNSD)       != 0x0) AppendAnd(str, "MCNSD");
179     if ((trigger & kNClusterGt0) != 0x0) AppendAnd(str, "NCluster>0");
180     if ((trigger & kSatellite)   != 0x0) AppendAnd(str, "Satellite");
181   }
182     
183   //__________________________________________________________________
184   /** 
185    * Find an object in a collection
186    * 
187    * @param parent Parent directory
188    * @param name   Name of object
189    * @param verb   Be verbose 
190    * 
191    * @return Pointer to object or null 
192    */
193   static TObject* GetObject(const TObject* parent, 
194                             const TString& name, 
195                             Bool_t verb=true)
196   {
197     if (!parent) {
198       if (verb) Warning("GetObject", "No parent given");
199       return 0;
200     }
201     if (name.IsNull()) { 
202       if (verb) Warning("GetObject", "No name specified");
203       return 0;
204     }
205     TObject* o = 0;
206     if (parent->IsA()->InheritsFrom(TCollection::Class())) {
207       const TCollection* p = static_cast<const TCollection*>(parent);
208       o = p->FindObject(name);
209     }
210     else if (parent->IsA()->InheritsFrom(TDirectory::Class())) {
211       const TDirectory* d = static_cast<const TDirectory*>(parent);
212       o = const_cast<TDirectory*>(d)->Get(name);
213     }
214     else 
215       Warning("GetObject", "Do not know how to find an object (%s) in "
216               "%s (of class %s)", name.Data(), 
217               parent ? parent->GetName() : "?", 
218               parent ? parent->ClassName() : "?");
219     if (!o) {
220       if (verb) Warning("GetObject", "Object \"%s\" not found in parent \"%s\"",
221                         name.Data(), parent->GetName());
222       return 0;
223     }
224     return o;    
225   }
226   //____________________________________________________________________
227   /** 
228    * Check the type of a found object 
229    * 
230    * @param o   Object 
231    * @param cl  Class 
232    * @param src Source of object
233    * 
234    * @return true on success, false otherwise 
235    */
236   static Bool_t CheckType(const TObject* o, 
237                           const TClass*  cl, 
238                           const TString& src)
239   {
240     if (!o->IsA()->InheritsFrom(cl)) { 
241       Warning("CheckType", "Object \"%s\" retrieved from \"%s\" is not a "
242               "%s but a %s", o->GetName(), src.Data(), cl->GetName(), 
243               o->ClassName());
244       return false;
245     }
246     return true;
247   }
248   //__________________________________________________________________
249   /** 
250    * Check a possibly returned object. 
251    * 
252    * @param o  Object found - if any
253    * @param p  Parent of object
254    * 
255    * @return A pointer to the object cast to the right type
256    */
257   template <typename T>
258   static T* DoGetObject(TObject* o, const TObject* p) 
259   {
260     if (!o) return 0;
261     if (!CheckType(o, T::Class(), p->GetName())) return 0;
262     return static_cast<T*>(o);
263   }
264   //__________________________________________________________________
265   /** 
266    * Check a returned parameter from a parent
267    * 
268    * @param o     Possibly found object
269    * @param p     Parent object
270    * @param value Value 
271    * 
272    * @return true on success, false otherwise 
273    */
274   template <typename T>
275   static Bool_t DoGetParameter(TObject* o, const TObject* p, T& value) 
276   {
277     TParameter<T>* r = DoGetObject<TParameter<T> >(o, p);
278     if (!r) return false;
279     // if (r->TestBit(TParameter<T>::kFirst)) value = r->GetVal();
280     // else                                   value = r->GetUniqueID();
281     value = r->GetVal();
282     if (!r->TestBit(BIT(19))) {
283       TObject* oc = GetObject(p, "count", false);
284       if (oc) {
285         TParameter<int>* pc = static_cast<TParameter<int>*>(oc);
286         int cnt = pc->GetVal();
287         value /= cnt;
288       }
289       else 
290         value = r->GetUniqueID();
291     }
292     // value = r->GetUniqueID();
293     return true;
294   }
295     
296   //___________________________________________________________________
297   /** 
298    * Get a UShort_t parameter value 
299    * 
300    * @param c      Parent collection
301    * @param name   Name of parameter
302    * @param value  On return the value
303    * @param verb   If true, complain if not found 
304    */
305   static Bool_t GetParameter(const TObject*  c, 
306                              const TString&  name, 
307                              UShort_t&       value,
308                              Bool_t          verb=true)
309   {
310     int v;
311     Bool_t r = DoGetParameter(GetObject(c, name, verb), c, v); 
312     value = v;
313     return r;
314   }
315   //___________________________________________________________________
316   /** 
317    * Get a UShort_t parameter value 
318    * 
319    * @param c      Parent collection
320    * @param name   Name of parameter
321    * @param value  On return the value
322    * @param verb   If true, complain if not found 
323    */
324   static Bool_t GetParameter(const TObject*  c, 
325                              const TString&  name, 
326                              ULong_t&        value,
327                              Bool_t          verb=true)
328   {
329     Long_t v;
330     Bool_t r = DoGetParameter(GetObject(c, name, verb), c, v); 
331     value = v;
332     return r;
333   }
334   //_____________________________________________________________________
335   /** 
336    * Get a Int_t parameter value 
337    * 
338    * @param c      Parent collection
339    * @param name   Name of parameter
340    * @param value  On return the value
341    * @param verb   If true, complain if not found 
342    */
343   static Bool_t GetParameter(const TObject*  c, 
344                              const TString&  name, 
345                              Int_t&          value,
346                              Bool_t          verb=true)
347   {
348     return DoGetParameter(GetObject(c, name, verb), c, value);
349   }
350   //_____________________________________________________________________
351   /** 
352    * Get a Double_t parameter value 
353    * 
354    * @param c      Parent collection
355    * @param name   Name of parameter
356    * @param value  On return the value
357    * @param verb   If true, complain if not found 
358    */
359   static Bool_t GetParameter(const TObject*      c, 
360                              const TString&      name, 
361                              Double_t&           value,
362                              Bool_t              verb=true);
363   //_____________________________________________________________________
364   /** 
365    * Get a Bool_t parameter value 
366    * 
367    * @param c      Parent collection
368    * @param name   Name of parameter
369    * @param value  On return the value
370    * @param verb   If true, complain if not found 
371    */
372   static Bool_t GetParameter(const TObject*  c, 
373                              const TString&      name, 
374                              Bool_t&             value,
375                              Bool_t              verb=true)
376   {
377     return DoGetParameter(GetObject(c, name, verb), c, value);
378   }
379   //____________________________________________________________________
380   /** 
381    * Find a collection in another collection 
382    * 
383    * @param parent Parent collection 
384    * @param name   Name of the collection 
385    * @param verb   If true and not found, complain
386    *
387    * @return pointer to collection on success, otherwise null 
388    */
389   static TCollection* GetCollection(const TObject*     parent, 
390                                     const TString&     name,
391                                     Bool_t             verb=true)
392   {
393     return DoGetObject<TCollection>(GetObject(parent, name, verb), parent);
394   }
395   //____________________________________________________________________
396   /** 
397    * Check a 1D histogram object from a parent
398    * 
399    * @param parent Parent collection 
400    * @param name   Name of histogram
401    * @param verb   Possibly be verbose
402    * 
403    * @return pointer or null
404    */
405   static TH1* GetH1(const TObject*     parent, 
406                     const TString&     name,
407                     Bool_t             verb=true)
408   {
409     return DoGetObject<TH1>(GetObject(parent, name, verb), parent);
410   }
411   //____________________________________________________________________
412   /** 
413    * Get a 2D histogram from a collection
414    * 
415    * @param parent Parent collection 
416    * @param name   Name of histogram 
417    * @param verb   If true and not found, complain
418    * 
419    * @return pointer or null
420    */
421   static TH2* GetH2(const TObject*     parent, 
422                     const TString&     name, 
423                     Bool_t             verb=true)
424   {
425     return DoGetObject<TH2>(GetObject(parent, name, verb), parent);
426   }
427   //____________________________________________________________________
428   /** 
429    * Get a 2D histogram from a collection
430    * 
431    * @param parent Parent collection 
432    * @param name   Name of histogram 
433    * @param verb   If true and not found, complain
434    * 
435    * @return pointer or null
436    */
437   static TH3* GetH3(const TCollection* parent, 
438                     const TString&     name, 
439                     Bool_t             verb=true)
440   {
441     // Info("GetH2", "Getting 2D histogram of %s from %p", name.Data(), c);
442     // --- Find the object -------------------------------------------
443     return DoGetObject<TH3>(GetObject(parent, name, verb), parent);
444   }
445   //__________________________________________________________________
446   /** 
447    * Get a histogram stack from a collection
448    * 
449    * @param parent Parent collection 
450    * @param name   Name of histogram 
451    * @param sub    If set, fill from sub-component 
452    * @param verb   If true and not found, complain
453    * 
454    * @return pointer or null
455    */
456   static THStack* GetStack(const TObject*  parent, 
457                            const TString&  name,
458                            const char*     sub=0,
459                            Bool_t          verb=true)
460   {
461     THStack* stack = DoGetObject<THStack>(GetObject(parent,name,verb),parent);
462     if (!stack) return 0;
463     if (sub == 0) return stack;
464   
465     if (stack->GetHists()->GetEntries() <= 0 ||stack->GetMaximum() < 1) { 
466       // Info("GetStack", "No entries in %s", name.Data());
467       stack->GetHists()->Delete();
468       const char* subs[] = { "FMD1I", "FMD2I", "FMD2O", "FMD3O", "FMD3I", 0 };
469       const char** ptr   = subs;
470       while (*ptr) { 
471         TCollection* sc = GetCollection(parent, *ptr, true);
472         if (!sc) { ptr++; continue; }
473
474         TObject* obj = GetObject(sc, sub);
475         if (!obj) {
476           continue;
477           ptr++;
478         }
479
480         if (obj->IsA()->InheritsFrom(TH2::Class())) {
481           TH2* h = static_cast<TH2*>(obj);
482           TH1* p = h->ProjectionX(*ptr, 1, h->GetNbinsY(), "e");
483           p->Scale(1., "width");
484           p->SetTitle(*ptr);
485           p->SetDirectory(0);
486           stack->Add(p);
487         }
488         else if (obj->IsA()->InheritsFrom(TH1::Class())) {
489           TH1* hh = static_cast<TH1*>(obj);
490           hh->SetTitle(*ptr);
491           stack->Add(hh);
492         }
493         ptr++;
494       }
495     }
496     // --- Return the collection -------------------------------------
497     return stack;
498   }
499   //____________________________________________________________________
500   /** 
501    * Clear canvas 
502    * 
503    */
504   void ClearCanvas()
505   {
506     fTop->Clear();
507     fTop->SetNumber(1);
508     fTop->SetFillColor(kBlue-5);
509     fTop->SetBorderSize(0);
510     fTop->SetBorderMode(0);
511
512     fBody->Clear();
513     fBody->SetNumber(2);
514     fBody->SetFillColor(0);
515     fBody->SetFillStyle(0);
516     fBody->SetBorderSize(0);
517     fBody->SetBorderMode(0);
518     fBody->SetTopMargin(0.01);
519     fBody->SetLeftMargin(0.10);
520     fBody->SetRightMargin(0.01);
521     fBody->SetBottomMargin(0.10);
522
523     fRingMap[0] = 0;
524     fRingMap[1] = 0;
525     fRingMap[2] = 0;
526     fRingMap[3] = 0;
527     fRingMap[4] = 0;
528     fRingMap[5] = 0;
529     
530     fCanvas->cd();    
531   }
532   //____________________________________________________________________
533   /** 
534    * Create a canvas 
535    * 
536    * @param pname     Name of PDF file to make 
537    * @param landscape If true, print in landscape 
538    * @param pdf       Make PDF
539    *
540    * @return Created canvas 
541    */
542   void CreateCanvas(const TString& pname, 
543                     Bool_t landscape=false, 
544                     Bool_t pdf=true)
545   {
546     // Info("CreateCanvas", "Creating canvas");
547     fLandscape = landscape;
548     fPDF       = pdf;
549     Int_t height = 1000;
550     Int_t width  = height / TMath::Sqrt(2);
551     if (fLandscape) {
552       Int_t tmp = height; 
553       height    = width;
554       width     = tmp;
555     }
556     fCanvas = new TCanvas("c", pname.Data(), width, height);
557     fCanvas->SetFillColor(0);
558     fCanvas->SetBorderSize(0);
559     fCanvas->SetBorderMode(0);
560     if (fPDF) 
561       fCanvas->Print(Form("%s[", pname.Data()), 
562                      Form("pdf %s", fLandscape ? "Landscape" : ""));
563     fCanvas->SetLeftMargin(.1);
564     fCanvas->SetRightMargin(.05);
565     fCanvas->SetBottomMargin(.1);
566     fCanvas->SetTopMargin(.05);
567   
568     gStyle->SetOptStat(0);
569     gStyle->SetTitleColor(0);
570     gStyle->SetTitleStyle(0);
571     gStyle->SetTitleBorderSize(0);
572     gStyle->SetTitleX(.5);
573     gStyle->SetTitleY(1);
574     gStyle->SetTitleW(.8);
575     gStyle->SetTitleH(.09);
576     gStyle->SetFrameFillColor(kWhite);
577     gStyle->SetFrameBorderSize(1);
578     gStyle->SetFrameBorderMode(1);
579     gStyle->SetPalette(1);
580
581     Float_t dy = .05;
582     fTop = new TPad("top", "Top", 0, 1-dy, 1, 1, 0, 0);
583     fTop->SetNumber(1);
584     fTop->SetFillColor(kBlue-5);
585     fTop->SetBorderSize(0);
586     fTop->SetBorderMode(0);
587     fCanvas->cd();
588     fTop->Draw();
589     
590     fBody = new TPad("body", "Body", 0, 0, 1, 1-dy, 0, 0);
591     fBody->SetNumber(2);
592     fBody->SetFillColor(0);
593     fBody->SetFillStyle(0);
594     fBody->SetBorderSize(0);
595     fBody->SetBorderMode(0);
596     fCanvas->cd();
597     fBody->Draw();
598
599     fHeader = new TLatex(.5, .5, "Title");
600     fHeader->SetNDC();
601     fHeader->SetTextAlign(22);
602     fHeader->SetTextSize(.7);
603     fHeader->SetTextColor(kWhite);
604     fHeader->SetTextFont(62);
605
606     Double_t x1 = .1;
607     Double_t x2 = .6;
608     Double_t y  = .8;
609     Double_t s  = fLandscape ? 0.08 : 0.05;
610     fParName = new TLatex(x1, y, "");
611     fParName->SetTextAlign(13);
612     fParName->SetNDC();
613     fParName->SetTextSize(s);
614     fParName->SetTextFont(62);
615     
616     fParVal = new TLatex(x2, y, "");
617     fParVal->SetTextAlign(13);
618     fParVal->SetNDC();
619     fParVal->SetTextSize(s);
620     fParVal->SetTextFont(42);
621
622     fCanvas->cd();
623   }
624
625   //____________________________________________________________________
626   /** 
627    * Close the PDF
628    * 
629    */
630   void CloseCanvas()
631   {
632     // Info("CloseCanvas", "Closing canvas");
633     // ClearCanvas();
634     if (fPDF && fCanvas) {
635       // Printf("Closing canvas with last title %s", fLastTitle.Data());
636       fCanvas->Print(Form("%s]", fCanvas->GetTitle()),
637                      Form("pdf %s Title:%s", 
638                           fLandscape ? "Landscape" : "",
639                           fLastTitle.Data()));
640     }
641     if (fCanvas)
642       fCanvas->Close();
643     fCanvas = 0;
644   }
645
646   //__________________________________________________________________
647   /** 
648    * Print the canvas 
649    * 
650    * @param title  Title 
651    * @param size   Size of text 
652    */
653   void PrintCanvas(const TString& title, Float_t size=.7)
654   {
655     TString tit;
656     tit.Form("pdf %s Title:%s", fLandscape ? "Landscape" : "",
657              title.Data());
658
659     fTop->cd();
660     fHeader->SetTextSize(size);
661     fHeader->DrawLatex(.5,.5,title);
662   
663     fCanvas->Modified();
664     fCanvas->Update();
665     fCanvas->cd();
666
667     if (fPDF) {
668       gSystem->RedirectOutput("/dev/null");
669       fCanvas->Print(fCanvas->GetTitle(), tit);
670       gSystem->RedirectOutput(0);
671       fLastTitle = title;
672       Pause();
673
674       ClearCanvas();
675     }
676   }
677   //__________________________________________________________________
678   /** 
679    * Make a chapter page 
680    * 
681    * @param title Title 
682    */
683   void MakeChapter(const TString& title)
684   {
685     fBody->cd();
686
687     TLatex* ltx = new TLatex(.5, .5, title);
688     ltx->SetNDC();
689     ltx->SetTextAlign(22);
690     ltx->Draw();
691     
692     PrintCanvas(title);
693   }
694   //__________________________________________________________________
695   /** 
696    * Draw an object in pad 
697    * 
698    * @param c       PArent pad 
699    * @param padNo   Sub-pad number (0 is self)
700    * @param h       Object to draw 
701    * @param opts    Options
702    * @param flags   Flags
703    * @param title   Title on plot
704    */
705   void DrawInPad(TVirtualPad* c, 
706                  Int_t        padNo, 
707                  TObject*     h, 
708                  Option_t*    opts="",
709                  UShort_t     flags=0x0,
710                  const char*  title="")
711   {
712     TVirtualPad* p = c->GetPad(padNo);
713     if (!p) { 
714       Warning("DrawInPad", "Pad # %d not found in %s", padNo, c->GetName());
715       return;
716     }
717     DrawInPad(p, h, opts, flags, title);
718   }
719   /** 
720    * Draw a clone of an object
721    * 
722    * @param o       Object
723    * @param options Draw options
724    * @param title   Title of object
725    */
726   virtual void DrawObjClone(TObject* o, Option_t* options, const char* title)
727   {
728     if (o->IsA()->InheritsFrom(TH1::Class())) 
729       DrawObjClone(static_cast<TH1*>(o), options, title);
730     else if (o->IsA()->InheritsFrom(THStack::Class())) 
731       DrawObjClone(static_cast<THStack*>(o), options, title);
732     else if (o->IsA()->InheritsFrom(TGraph::Class()))
733       o->DrawClone(options);
734     else 
735       o->Draw(options);
736   }
737   /** 
738    * Draw an object clone 
739    * 
740    * @param o        Stack object
741    * @param options  Draw options 
742    * @param title    Title on plot
743    */
744   virtual void DrawObjClone(THStack* o, Option_t* options, const char* title)
745   {
746     // THStack* tmp = static_cast<THStack*>(o->Clone());
747     o->Draw(options);
748     if (title && title[0] != '\0') o->GetHistogram()->SetTitle(title);
749     TAxis*   xAxis = o->GetXaxis();
750     if (!xAxis) {
751       Warning("DrawObjClone", "No X-axis for drawn stack %s", o->GetName());
752       return;
753     }
754     TH1*     h     = 0;
755     Int_t    nBins = xAxis->GetNbins();
756     Double_t xMin  = xAxis->GetXmin();
757     Double_t xMax  = xAxis->GetXmax();
758     TIter  next(o->GetHists());
759     while ((h = static_cast<TH1*>(next()))) {
760       TAxis* a = h->GetXaxis();
761       nBins    = TMath::Max(nBins, a->GetNbins()); 
762       xMin     = TMath::Min(xMin, a->GetXmin());
763       xMax     = TMath::Max(xMax, a->GetXmax());
764     }
765     if (nBins != xAxis->GetNbins() || 
766         xMin  != xAxis->GetXmin() || 
767         xMax  != xAxis->GetXmax()) {
768       xAxis->Set(nBins, xMin, xMax);
769       o->GetHistogram()->Rebuild();
770     }
771   }
772   /** 
773    * Draw an object clone 
774    * 
775    * @param o        Histogram
776    * @param options  Draw options 
777    * @param title    Title on plot 
778    */
779   virtual void DrawObjClone(TH1* o, Option_t* options, const char* title)
780   {
781     TH1* tmp = o->DrawCopy(options);
782     if (title && title[0] != '\0') tmp->SetTitle(title);
783   }    
784   //__________________________________________________________________
785   /** 
786    * Draw an object in pad 
787    * 
788    * @param p       Pad
789    * @param h       Object to draw 
790    * @param opts    Options
791    * @param flags   Flags
792    * @param title   Title on plot
793    */
794   void DrawInPad(TVirtualPad* p, 
795                  TObject*     h, 
796                  Option_t*    opts="",
797                  UShort_t     flags=0x0,
798                  const char*  title="")
799   {
800     if (!p) { 
801       Warning("DrawInPad", "No pad specified");
802       return;
803     }
804     p->cd();
805     // Info("DrawInPad", "Drawing in pad %p", p);
806     // fBody->ls();
807     if (flags & kLogx) p->SetLogx();
808     if (flags & kLogy) p->SetLogy();
809     if (flags & kLogz) p->SetLogz();
810     if (flags & kGridx) p->SetGridx();
811     if (flags & kGridy) p->SetGridy();
812     // if (flags & kGridz) p->SetGridz();
813     p->SetFillColor(0);
814     TString o(opts);
815     if (o.Contains("colz", TString::kIgnoreCase)) 
816       p->SetRightMargin(0.15);
817     if (!h) {
818       if (!(flags & kSilent))
819         Warning("DrawInPad", "Nothing to draw in pad # %s", p->GetName());
820       return;
821     }
822     if (o.Contains("text", TString::kIgnoreCase)) {
823       TH1* hh = static_cast<TH1*>(h);
824       hh->SetMaximum(1.1*hh->GetMaximum());
825       hh->SetMarkerSize(2);
826       o.Append("30");
827     }
828     DrawObjClone(h, o, title);
829     
830     if (flags& kLegend) { 
831       Double_t x1 = fParVal->GetX();
832       Double_t y1 = fParVal->GetY();
833       Double_t x2 = TMath::Min(x1+.5, .99);
834       Double_t y2 = TMath::Min(y1+.5, .99-p->GetTopMargin());
835       //Printf("Legend at (%f,%f)x(%f,%f)", x1, y1, x2, y2);
836       TLegend* l = p->BuildLegend(x1, y1, x2, y2);
837       l->SetFillColor(0);
838       l->SetFillStyle(0);
839       l->SetBorderSize(0);
840     }
841     p->Modified();
842     p->Update();
843     p->cd();
844   }
845   //__________________________________________________________________
846   /** 
847    * Draw two graphs in the same frame, but with separate y-axis 
848    * 
849    * @param c      Mother pad 
850    * @param padNo  Sub-pad number (0 is self)
851    * @param h1     First histogram
852    * @param h2     Second histogram
853    * @param opts   Options
854    * @param flags  Flags
855    */
856   void DrawTwoInPad(TVirtualPad* c, Int_t padNo, TH1* h1, TH1* h2,
857                     Option_t* opts="", UShort_t flags=0x0)
858   {
859     TVirtualPad* p = c->cd(padNo);
860     if (!p) { 
861       Warning("DrawInPad", "Pad # %d not found in %s", padNo, c->GetName());
862       return;
863     }
864     if (flags & kLogx) p->SetLogx();
865     if (flags & kLogy) p->SetLogy();
866     if (flags & kLogz) p->SetLogz();
867     if (flags & kGridx) p->SetGridx();
868     if (flags & kGridy) p->SetGridy();
869     // if (flags & kGridz) p->SetGridz();
870     p->SetFillColor(0);
871
872     TString o(opts);
873     o.ToLower();
874     TString fopts(o);
875     Bool_t e3 = o.Contains("e3");
876     if (e3) {
877       fopts.ReplaceAll("e3", " same");
878     }
879     
880     h1->GetYaxis()->SetLabelSize(0);
881     h1->GetYaxis()->SetTicks("");
882     h1->GetYaxis()->SetNdivisions(0);
883     h1->DrawCopy(o); // First draw with opts 
884     if (e3) h1->DrawCopy(fopts);
885     p->Update();
886
887     Double_t m1 = 1.05 * h1->GetMaximum();
888     if (m1 > 0) {
889       TGaxis*  a1 = new TGaxis(p->GetUxmin(), p->GetUymin(), 
890                                p->GetUxmin(), p->GetUymax(), 
891                                0, m1, 510);
892       a1->SetLineColor(h1->GetLineColor());
893       a1->Draw();
894     }
895
896     o.Append(" same");
897     Double_t m2    = 1.1 * h2->GetMaximum();
898     Double_t scale = m2 > 0 ? m1 / m2 : 1;
899     h2->Scale(scale);
900     h2->DrawCopy(o);
901     if (e3) h2->DrawCopy(fopts);
902
903     if (m2 > 0) {
904       TGaxis*  a2 = new TGaxis(p->GetUxmax(), p->GetUymin(), 
905                                p->GetUxmax(), p->GetUymax(), 
906                                0, m2, 510, "+L");
907       a2->SetLineColor(h2->GetLineColor());
908       a2->Draw();
909     }
910     if (flags& kLegend) { 
911       TLegend* l = p->BuildLegend();
912       l->SetFillColor(0);
913       l->SetFillStyle(0);
914       l->SetBorderSize(0);
915     }
916     p->Modified();
917     p->Update();
918     p->cd();
919   }  
920   
921   //____________________________________________________________________
922   /** 
923    * Draw a parameter.  
924    * 
925    * @param y       Current y position. On return new y position
926    * @param name    Parameter name
927    * @param value   Parameter value 
928    * @param size    Optional text size
929    */
930   void DrawParameter(Double_t&      y, 
931                      const TString& name, 
932                      const TString& value,
933                      Double_t       size=0)
934   {
935     Double_t s = fParName->GetTextSize();
936     Double_t t = fParVal->GetTextSize();
937     if (name.IsNull() && value.IsNull()) return;
938     if (size > 0) { 
939       fParName->SetTextSize(size);
940       fParVal->SetTextSize(size);
941     }
942     if (!name.IsNull())
943       fParName->DrawLatex(fParName->GetX(), y, Form("%s:", name.Data()));
944     if (!value.IsNull())
945       fParVal->DrawLatex(fParVal->GetX(), y, value.Data());
946     if (!name.IsNull())
947       y -= 1.2 * fParName->GetTextSize();
948     else if (!value.IsNull())
949       y -= 1.2 * fParVal->GetTextSize();
950
951     fParName->SetTextSize(s);
952     fParVal->SetTextSize(t);
953   }  
954   //__________________________________________________________________
955   void DivideForRings(Bool_t commonX, Bool_t commonY)
956   {
957     // 
958     // Divide canvas for rings 
959     // 
960     if ((!commonX && !commonY) || 
961         (commonX  && commonY)) {
962     // Portrait:
963     //    +----------+----------+
964     //    | 1: FMD1i | 2: Free  |
965     //    +----------+----------+
966     //    | 3: FMD2i | 4: FMD2o |
967     //    +----------+----------+
968     //    | 5: FMD3i | 6: FMD3o |
969     //    +----------+----------+
970     // 
971     // Landscape:
972     //    +----------+----------+----------+
973     //    | 1: FMD1i | 2: FMD2i | 3: FMD3i |
974     //    +----------+----------+----------+
975     //    | 4: Free  | 5: FMD2o | 6: FMD3o |
976     //    +----------+----------+----------+
977     // 
978       fBody->Divide(fLandscape ? 3 : 2, fLandscape ? 2 : 3,
979                     commonX ? 0 : 0.01, commonY ? 0 : 0.01);
980       fRingMap[0] = fBody->GetPad(1);                  // FMD1i;
981       fRingMap[1] = fBody->GetPad(fLandscape ? 2 : 3); // FMD2i;
982       fRingMap[2] = fBody->GetPad(fLandscape ? 5 : 4); // FMD2o;
983       fRingMap[3] = fBody->GetPad(fLandscape ? 3 : 5); // FMD3i;
984       fRingMap[4] = fBody->GetPad(6);                  // FMD3o;
985       fRingMap[5] = fBody->GetPad(fLandscape ? 4 : 2); // Free
986     }
987     else if (commonX && !commonY) {
988       // Divide into two  - left/right
989       // Portrait:
990       //    +----------++----------+
991       //    | 1: FMD1i || 1: Free  |
992       //    +----------++----------+
993       //    | 2: FMD2i || 2: FMD2o |
994       //    +----------++----------+
995       //    | 3: FMD3i || 3: FMD3o |
996       //    +----------++----------+
997       // 
998       // Landscape:
999       //    +----------++----------++----------+
1000       //    | 1: FMD1i || 1: FMD2i || 1: FMD3i |
1001       //    +----------++----------++----------+
1002       //    | 2: Free  || 2: FMD2o || 2: FMD3o |
1003       //    +----------++----------++----------+
1004       // 
1005       fBody->Divide(fLandscape ? 3 : 2, 1);
1006       TVirtualPad* left = fBody->cd(1);
1007       left->Divide(fLandscape ? 2 : 3);
1008       TVirtualPad* middle = fBody->cd(2);
1009       middle->Divide(fLandscape ? 2 : 3);
1010
1011       Info("left","%p",left); left->ls();
1012       Info("middle","%p",middle); middle->ls();
1013
1014       fRingMap[0] = left->GetPad(1); // FMD1i;
1015       if (!fLandscape) {
1016         fRingMap[1] = left->GetPad(2);   // FMD2i
1017         fRingMap[2] = middle->GetPad(2); // FMD2o
1018         fRingMap[3] = left->GetPad(3);   // FMD3i
1019         fRingMap[4] = middle->GetPad(3); // FMD3o
1020         fRingMap[5] = middle->GetPad(1); // Free
1021       }
1022       else {
1023         TVirtualPad* right = fBody->cd(3);
1024         right->Divide(fLandscape ? 2 : 3);
1025         fRingMap[1] = middle->GetPad(1); // FMD2i
1026         fRingMap[2] = middle->GetPad(2); // FMD2o
1027         fRingMap[3] = right->GetPad(1);  // FMD3i
1028         fRingMap[4] = right->GetPad(2);  // FMD3o
1029         fRingMap[5] = left->GetPad(2);   // Free
1030       }
1031     }
1032     else { 
1033       // Divide into two  - left/right
1034       // Portrait:
1035       //    +----------+----------+
1036       //    | 1: FMD1i | 2: Free  |
1037       //    +----------+----------+
1038       //    +----------+----------+
1039       //    | 1: FMD2i | 2: FMD2o |
1040       //    +----------+----------+
1041       //    +----------+----------+
1042       //    | 1: FMD3i | 2: FMD3o |
1043       //    +----------+----------+
1044       // 
1045       // Landscape:
1046       //    +----------+----------+----------+
1047       //    | 1: FMD1i | 2: FMD2i | 3: FMD3i |
1048       //    +----------+----------+----------+
1049       //    +----------+----------+----------+
1050       //    | 1: Free  | 2: FMD2o | 3: FMD3o |
1051       //    +----------+----------+----------+
1052       // 
1053       fBody->Divide(1, fLandscape ? 2 : 3);
1054       TVirtualPad* top = fBody->cd(1);
1055       top->Divide(fLandscape ? 3 : 2);
1056       TVirtualPad* middle = fBody->cd(2);
1057       middle->Divide(fLandscape ? 3 : 2);
1058
1059       fRingMap[0] = top->GetPad(1); // FMD1i;
1060       if (!fLandscape) {
1061         TVirtualPad* bottom = fBody->cd(2);
1062         bottom->Divide(2);
1063
1064         fRingMap[1] = middle->GetPad(1); // FMD2i
1065         fRingMap[2] = middle->GetPad(2); // FMD2o
1066         fRingMap[3] = bottom->GetPad(1); // FMD3i
1067         fRingMap[4] = bottom->GetPad(2); // FMD3o
1068         fRingMap[5] = top->GetPad(2);    // Free
1069       }
1070       else {
1071         fRingMap[1] = top->GetPad(2);    // FMD2i
1072         fRingMap[2] = middle->GetPad(2); // FMD2o
1073         fRingMap[3] = top->GetPad(3);    // FMD3i
1074         fRingMap[4] = middle->GetPad(3); // FMD3o
1075         fRingMap[5] = middle->GetPad(1); // Free
1076       }
1077     }
1078     if (fRingMap[0]) fRingMap[0]->SetTitle("FMD1i");
1079     if (fRingMap[1]) fRingMap[1]->SetTitle("FMD2i");
1080     if (fRingMap[2]) fRingMap[2]->SetTitle("FMD2o");
1081     if (fRingMap[3]) fRingMap[3]->SetTitle("FMD3i");
1082     if (fRingMap[4]) fRingMap[4]->SetTitle("FMD3o");
1083     if (fRingMap[5]) fRingMap[5]->SetTitle("Other");
1084   }
1085   //__________________________________________________________________
1086   TVirtualPad* RingPad(UShort_t d, Char_t r) const
1087   {
1088     Int_t idx = 0;
1089     switch (d) { 
1090     case 0:     idx = 5; break;
1091     case 1:     idx = 0; break;
1092     case 2:     idx = 1 + ((r == 'I' || r == 'i') ? 0 : 1); break;
1093     case 3:     idx = 3 + ((r == 'I' || r == 'i') ? 0 : 1); break;
1094     default: return 0;
1095     }
1096     return fRingMap[idx];
1097     // return fBody->GetPad(no);
1098   }
1099   //__________________________________________________________________
1100   /** 
1101    * Draw an object in pad 
1102    * 
1103    * @param d       Detector 
1104    * @param r       Ring 
1105    * @param h       Object to draw 
1106    * @param opts    Options
1107    * @param flags   Flags
1108    * @param title   Title on plot
1109    */
1110   void DrawInRingPad(UShort_t    d, 
1111                      Char_t      r, 
1112                      TObject*    h, 
1113                      Option_t*   opts="",
1114                      UShort_t    flags=0x0,
1115                      const char* title="")
1116   {
1117     TVirtualPad* p = RingPad(d, r);
1118     if (!p) {
1119       Warning("DrawInRingPad", "No pad found for FMD%d%c", d, r);
1120       return;
1121     }
1122     DrawInPad(p, h, opts, flags, title);
1123   }
1124     
1125
1126   //__________________________________________________________________
1127   /** 
1128    * Pause after each plot
1129    * 
1130    */
1131   void Pause()
1132   {
1133     if (!fPause) return;
1134     printf("Press enter to continue");
1135     std::cin.get();
1136   }
1137
1138   //____________________________________________________________________
1139   virtual void DrawEventInspector(TCollection* parent)
1140   {
1141     Info("DrawEventInspector", "Drawing event inspector");
1142     TCollection* c = GetCollection(parent, "fmdEventInspector");
1143     if (!c) return;
1144
1145     UShort_t sys=0, sNN=0;
1146     Int_t field=0;
1147     ULong_t runNo=0;
1148     Int_t lowFlux=0, nPileUp=0;
1149     ULong_t aliRev=0, aliBra=0;
1150     Bool_t fpVtx=false, v0and=false;
1151     Double_t dPileUp=0.;
1152     Double_t y = .8;
1153
1154     fBody->cd();
1155
1156     Double_t save = fParName->GetTextSize();
1157     fParName->SetTextSize(0.03);
1158     fParVal->SetTextSize(0.03);
1159     
1160     GetParameter(c, "sys", sys);
1161     GetParameter(c, "sNN", sNN);
1162     GetParameter(c, "field", field);
1163     GetParameter(c, "runNo", runNo);
1164     GetParameter(c, "lowFlux", lowFlux);
1165     GetParameter(c, "fpVtx", fpVtx);
1166     GetParameter(c, "v0and", v0and);
1167     GetParameter(c, "nPileUp", nPileUp);
1168     GetParameter(c, "dPileup", dPileUp);
1169     GetParameter(c, "alirootRev", aliRev);
1170     GetParameter(c, "alirootBranch", aliBra);
1171     
1172     TString tS; SysString(sys, tS); DrawParameter(y, "System", tS);
1173     TString tE; SNNString(sNN, tE); DrawParameter(y, "#sqrt{s_{NN}}", tE);
1174     DrawParameter(y, "L3 B field", Form("%+2dkG", field));
1175     DrawParameter(y, "Run #", Form("%lu", runNo));
1176     DrawParameter(y, "Low flux cut", Form("%d", lowFlux));
1177     DrawParameter(y, "Use PWG-UD vertex", (fpVtx ? "yes" : "no"));
1178     DrawParameter(y, "Use V0AND for NSD", (v0and ? "yes" : "no"));
1179     DrawParameter(y, "Least # of pile-up vertex", Form("%d", nPileUp));
1180     DrawParameter(y, "Least distance of pile-up vertex",
1181                   Form("%fcm", dPileUp));
1182     DrawParameter(y, "AliROOT", Form("%lu/0x%08lx", ULong_t(aliRev), 
1183                                      ULong_t(aliBra)));
1184
1185     TH1*    triggers     = GetH1(c, "triggers");
1186     TH1*    vertex       = GetH1(c, "vertex", false);
1187     Bool_t  mc           = (vertex != 0);
1188     if (mc) { 
1189       Int_t nInelMC = vertex->GetEntries();
1190       Int_t nInel   = triggers->GetBinContent(1);
1191       Int_t nNSDMC  = triggers->GetBinContent(11);
1192       Int_t nNSD    = triggers->GetBinContent(4);
1193       DrawParameter(y, 
1194                     Form("#varepsilon_{INEL} = #bf{%d/%d}", nInel, nInelMC),
1195                     Form("%5.3f", float(nInel)/nInelMC));
1196       DrawParameter(y, 
1197                     Form("#varepsilon_{NSD} = #bf{%d/%d}", nNSD, nNSDMC),
1198                     Form("%5.3f", float(nNSD)/nNSDMC));
1199     }
1200
1201     PrintCanvas("Event Inspector");
1202     fParName->SetTextSize(save);
1203     fParVal->SetTextSize(save);
1204
1205     if (fLandscape) fBody->Divide(4,2);
1206     else            fBody->Divide(2,4);
1207     
1208     TH1*    nEventsTr    = GetH1(c, "nEventsTr");
1209     TH1*    nEventsTrVtx = GetH1(c, "nEventsTrVtx");
1210     TH1*    nEventsAcc   = GetH1(c, "nEventsAccepted");
1211     if (nEventsTr)    nEventsTr->Rebin(2);
1212     if (nEventsTrVtx) nEventsTrVtx->Rebin(2);
1213     if (vertex) {
1214       // vertex->Rebin(2);
1215       vertex->SetFillColor(kMagenta+2);
1216     }
1217     DrawInPad(fBody, 1, nEventsTr, "", kLogy, 
1218               "Events w/trigger, trigger+vertex, accepted");
1219     if (vertex) DrawInPad(fBody, 1, vertex, "same");
1220     DrawInPad(fBody, 1, nEventsTrVtx, "same"); 
1221     DrawInPad(fBody, 1, nEventsAcc, "same", kLegend);
1222
1223
1224     DrawInPad(fBody, 2, GetH2(c, "nEventsAcceptedXY"), "colz", kLogz);
1225     DrawInPad(fBody, 3, triggers,          "hist text");
1226     if (GetH1(c, "trgStatus"))
1227       DrawInPad(fBody, 4, GetH1(c, "trgStatus"),       "hist text");
1228     else  // Old one 
1229       DrawInPad(fBody, 4, GetH2(c, "triggerCorr"),     "colz", kLogz);
1230     DrawInPad(fBody, 5, GetH1(c, "status"),            "hist text");
1231     if (GetH1(c, "vtxStatus"))
1232       DrawInPad(fBody, 6, GetH1(c, "vtxStatus"),       "hist text");
1233     else // old 
1234       DrawInPad(fBody, 6, GetH1(c, "type"),            "hist text");
1235
1236     TH1* cent     = GetH1(c, "cent");
1237     TH2* centQual = GetH2(c, "centVsQuality");
1238     if (cent && centQual) { 
1239       cent->Scale(1, "width");
1240       centQual->Scale(1, "width");
1241       DrawInPad(fBody, 7, cent, "", kLogy);
1242       DrawInPad(fBody, 8, centQual, "colz", kLogz);
1243     }
1244     
1245     PrintCanvas("EventInspector - Histograms");  
1246
1247     if (!mc) return; // not MC 
1248   
1249     TH1* phiR         = GetH1(c, "phiR");
1250     TH1* b            = GetH1(c, "b");
1251     TH2* bVsNpart     = GetH2(c, "bVsParticipants");
1252     TH2* bVsNbin      = GetH2(c, "bVsBinary");
1253     TH2* bVsCent      = GetH2(c, "bVsCentrality");
1254     TH2* vzComparison = GetH2(c, "vzComparison");
1255     TH2* centVsNpart  = GetH2(c, "centralityVsParticipans");// Spelling!
1256     TH2* centVsNbin   = GetH2(c, "centralityVsBinary");
1257   
1258     fBody->Divide(2,3);
1259
1260     DrawInPad(fBody, 1, phiR);
1261     DrawInPad(fBody, 2, vzComparison, "colz", kLogz);
1262     DrawInPad(fBody, 3, b);
1263
1264     TProfile* nPartB = bVsNpart->ProfileX("nPartB",1,-1,"s");
1265     TProfile* nBinB  = bVsNbin->ProfileX("nBinB",1,-1,"s");
1266     nPartB->SetMarkerColor(kBlue+2);
1267     nPartB->SetMarkerStyle(20);
1268     nPartB->SetLineColor(kBlue+2);
1269     nPartB->SetFillColor(kBlue-10);
1270     nPartB->SetFillStyle(1001);
1271     nPartB->SetMarkerSize(0.7);
1272     nBinB->SetMarkerColor(kRed+2);
1273     nBinB->SetMarkerStyle(21);
1274     nBinB->SetLineColor(kRed+2);
1275     nBinB->SetFillColor(kRed-10);
1276     nBinB->SetMarkerSize(0.7);
1277     nBinB->SetFillStyle(1001);
1278
1279     DrawTwoInPad(fBody, 4, nPartB, nBinB, "e3 p", kLegend);
1280
1281     DrawInPad(fBody, 5, bVsCent, "colz", kLogz);
1282
1283     TProfile* nPartC = centVsNpart->ProfileY("nPartC",1,-1,"s");
1284     TProfile* nBinC  = centVsNbin->ProfileY("nBinC",1,-1,"s");
1285     nPartC->SetMarkerColor(kBlue+2);
1286     nPartC->SetMarkerStyle(20);
1287     nPartC->SetLineColor(kBlue+2);
1288     nPartC->SetFillColor(kBlue-10);
1289     nPartC->SetFillStyle(1001);
1290     nPartC->SetMarkerSize(0.7);
1291     nBinC->SetMarkerColor(kRed+2);
1292     nBinC->SetMarkerStyle(21);
1293     nBinC->SetLineColor(kRed+2);
1294     nBinC->SetFillColor(kRed-10);
1295     nBinC->SetMarkerSize(0.7);
1296     nBinC->SetFillStyle(1001);
1297
1298     DrawTwoInPad(fBody, 6, nPartC, nBinC, "e3 p", kLegend);
1299
1300     PrintCanvas("EventInspector - Monte-Carlo");  
1301   }
1302   //____________________________________________________________________
1303   void DrawTrackDensity(TCollection* parent)
1304   {
1305     Info("DrawTrackDensity", "Drawing track density");
1306
1307     // --- MC --------------------------------------------------------
1308     TCollection* mc = GetCollection(parent, "mcTrackDensity", false);
1309     if (!mc) return; // Not MC 
1310
1311     fBody->Divide(2,3);
1312     DrawInPad(fBody, 1, GetH2(mc, "binFlow"),    "colz", kLogz);
1313     DrawInPad(fBody, 2, GetH2(mc, "binFlowEta"), "colz", kLogz);
1314     DrawInPad(fBody, 3, GetH2(mc, "binFlowPhi"), "colz", kLogz);
1315     DrawInPad(fBody, 4, GetH1(mc, "nRefs"),       "",    kLogy,
1316               "# of references");
1317     DrawInPad(fBody, 4, GetH1(mc, "clusterRefs",   false), "same");
1318     DrawInPad(fBody, 4, GetH1(mc, "clusterSize",   false), "same");
1319     DrawInPad(fBody, 4, GetH1(mc, "nClusters",     false), "same", kLegend);
1320     DrawInPad(fBody, 5, GetH2(mc, "clusterVsRefs", false),"colz", kLogz);
1321
1322     PrintCanvas("Track density");  
1323   }
1324
1325   //__________________________________________________________________
1326   TCanvas* fCanvas;  // Our canvas 
1327   TPad*    fTop;     // Top part 
1328   TPad*    fBody;    // Body part 
1329   TLatex*  fHeader;  // Header text 
1330   TLatex*  fParName; // Parameter name 
1331   TLatex*  fParVal;  // Parameter value 
1332   Bool_t   fPause;   // Whether to pause after drawing a canvas
1333   Bool_t   fLandscape; // Landscape or Portrait orientation
1334   TVirtualPad** fRingMap;
1335   Bool_t   fPDF;
1336   TString  fLastTitle;
1337 };
1338 #if 0
1339 template <> 
1340 inline Bool_t 
1341 SummaryDrawer::DoGetParameter<Double_t>(TObject* o, const TObject* p, 
1342                                         Double_t& value)
1343 {
1344   TParameter<Double_t>* r = DoGetObject<TParameter<Double_t>(o, p);
1345   UInt_t  i = o->GetUniqueID();
1346   Float_t v = *reinterpret_cast<Float_t*>(&i);
1347   value = v;
1348   return true;
1349 }
1350 #endif
1351 inline Bool_t 
1352 SummaryDrawer::GetParameter(const TObject*   c, 
1353                             const TString&   name, 
1354                             Double_t&        value,
1355                             Bool_t           verb)
1356   
1357 {
1358   return DoGetParameter(GetObject(c, name, verb), c, value);
1359 }
1360
1361 #endif
1362 //
1363 // EOF
1364 //
1365