Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
THStack.cxx
Go to the documentation of this file.
1 // @(#)root/hist:$Id$
2 // Author: Rene Brun 10/12/2001
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TROOT.h"
13 #include "TClassRef.h"
14 #include "THStack.h"
15 #include "TVirtualPad.h"
16 #include "TVirtualHistPainter.h"
17 #include "THashList.h"
18 #include "TH2.h"
19 #include "TH3.h"
20 #include "TList.h"
21 #include "TStyle.h"
22 #include "Riostream.h"
23 #include "TBrowser.h"
24 #include "TMath.h"
25 #include "TObjString.h"
26 #include "TVirtualMutex.h"
27 
28 ClassImp(THStack);
29 
30 ////////////////////////////////////////////////////////////////////////////////
31 
32 /** \class THStack
33  \ingroup Hist
34 The Histogram stack class
35 
36 A THStack is a collection of TH1 or TH2 histograms.
37 Using THStack::Draw() the histogram collection is drawn in one go according
38 to the drawing option.
39 
40 THStack::Add() allows to add a new histogram to the list.
41 The THStack does not own the objects in the list.
42 
43 By default (if no option drawing option is specified), histograms will be paint
44 stacked on top of each other. TH2 are stacked as lego plots.
45 
46 If option "nostack" is specified the histograms are not drawn on top
47 of each other but as they would if drawn using the option "same".
48 
49 If option "nostackb" is specified the histograms are drawn next to
50 each other as bar charts.
51 
52 In all cases The axis range is computed automatically along the X and Y axis in
53 order to show the complete histogram collection.
54 
55 Example;
56 
57 Begin_Macro(source)
58 {
59  THStack *hs = new THStack("hs","");
60  TH1F *h1 = new TH1F("h1","test hstack",10,-4,4);
61  h1->FillRandom("gaus",20000);
62  h1->SetFillColor(kRed);
63  hs->Add(h1);
64  TH1F *h2 = new TH1F("h2","test hstack",10,-4,4);
65  h2->FillRandom("gaus",15000);
66  h2->SetFillColor(kBlue);
67  hs->Add(h2);
68  TH1F *h3 = new TH1F("h3","test hstack",10,-4,4);
69  h3->FillRandom("gaus",10000);
70  h3->SetFillColor(kGreen);
71  hs->Add(h3);
72  TCanvas *cs = new TCanvas("cs","cs",10,10,700,900);
73  TText T; T.SetTextFont(42); T.SetTextAlign(21);
74  cs->Divide(2,2);
75  cs->cd(1); hs->Draw(); T.DrawTextNDC(.5,.95,"Default drawing option");
76  cs->cd(2); hs->Draw("nostack"); T.DrawTextNDC(.5,.95,"Option \"nostack\"");
77  cs->cd(3); hs->Draw("nostackb"); T.DrawTextNDC(.5,.95,"Option \"nostackb\"");
78  cs->cd(4); hs->Draw("lego1"); T.DrawTextNDC(.5,.95,"Option \"lego1\"");
79  return cs;
80 }
81 End_Macro
82 
83 A more complex example:
84 
85 Begin_Macro(source)
86 ../../../tutorials/hist/hstack.C
87 End_Macro
88 
89 Note that picking is supported for all drawing modes.
90 
91 \since **ROOT version 6.07/07:**
92 Stacks of 2D histograms can also be painted as candle plots:
93 \since **ROOT version 6.09/02:**
94 Stacks of 2D histograms can also be painted as violin plots, combinations of candle and
95 violin plots are possible as well:
96 
97 Begin_Macro(source)
98 ../../../tutorials/hist/candleplotstack.C
99 End_Macro
100 
101 Automatic coloring according to the current palette is available as shown in the
102 following example:
103 
104 Begin_Macro(source)
105 ../../../tutorials/hist/thstackpalettecolor.C
106 End_Macro
107 */
108 
109 
110 ////////////////////////////////////////////////////////////////////////////////
111 /// THStack default constructor
112 
113 THStack::THStack(): TNamed()
114 {
115  fHists = 0;
116  fStack = 0;
117  fHistogram = 0;
118  fMaximum = -1111;
119  fMinimum = -1111;
120 }
121 
122 ////////////////////////////////////////////////////////////////////////////////
123 /// constructor with name and title
124 
125 THStack::THStack(const char *name, const char *title)
126  : TNamed(name,title)
127 {
128  fHists = 0;
129  fStack = 0;
130  fHistogram = 0;
131  fMaximum = -1111;
132  fMinimum = -1111;
133  R__LOCKGUARD(gROOTMutex);
134  gROOT->GetListOfCleanups()->Add(this);
135 }
136 
137 
138 ////////////////////////////////////////////////////////////////////////////////
139 /// Creates a new THStack from a TH2 or TH3
140 /// It is filled with the 1D histograms from GetProjectionX or GetProjectionY
141 /// for each bin of the histogram. It illustrates the differences and total
142 /// sum along an axis.
143 ///
144 /// Parameters:
145 /// - hist: the histogram used for the projections. Can be an object deriving
146 /// from TH2 or TH3.
147 /// - axis: for TH2: "x" for ProjectionX, "y" for ProjectionY.
148 /// for TH3: see TH3::Project3D.
149 /// - name: fName is set to name if given, otherwise to histo's name with
150 /// "_stack_<axis>" appended, where <axis> is the value of the
151 /// parameter axis.
152 /// - title: fTitle is set to title if given, otherwise to histo's title
153 /// with ", stack of <axis> projections" appended.
154 /// - firstbin, lastbin:
155 /// for each bin within [firstbin,lastbin] a stack entry is created.
156 /// See TH2::ProjectionX/Y for use overflow bins.
157 /// Defaults to "all bins but under- / overflow"
158 /// - firstbin2, lastbin2:
159 /// Other axis range for TH3::Project3D, defaults to "all bins but
160 /// under- / overflow". Ignored for TH2s
161 /// - proj_option:
162 /// option passed to TH2::ProjectionX/Y and TH3::Project3D (along
163 /// with axis)
164 /// - draw_option:
165 /// option passed to THStack::Add.
166 
167 THStack::THStack(TH1* hist, Option_t *axis /*="x"*/,
168  const char *name /*=0*/, const char *title /*=0*/,
169  Int_t firstbin /*=1*/, Int_t lastbin /*=-1*/,
170  Int_t firstbin2 /*=1*/, Int_t lastbin2 /*=-1*/,
171  Option_t* proj_option /*=""*/, Option_t* draw_option /*=""*/): TNamed(name, title) {
172  fHists = 0;
173  fStack = 0;
174  fHistogram = 0;
175  fMaximum = -1111;
176  fMinimum = -1111;
177  {
178  R__LOCKGUARD(gROOTMutex);
179  gROOT->GetListOfCleanups()->Add(this);
180  }
181  if (!axis) {
182  Warning("THStack", "Need an axis.");
183  return;
184  }
185  if (!hist) {
186  Warning("THStack", "Need a histogram.");
187  return;
188  }
189  Bool_t isTH2=hist->IsA()->InheritsFrom(TH2::Class());
190  Bool_t isTH3=hist->IsA()->InheritsFrom(TH3::Class());
191  if (!isTH2 && !isTH3) {
192  Warning("THStack", "Need a histogram deriving from TH2 or TH3.");
193  return;
194  }
195 
196  if (!fName.Length())
197  fName=Form("%s_stack%s", hist->GetName(), axis);
198  if (!fTitle.Length()) {
199  if (hist->GetTitle() && strlen(hist->GetTitle()))
200  fTitle=Form("%s, stack of %s projections", hist->GetTitle(), axis);
201  else
202  fTitle=Form("stack of %s projections", axis);
203  }
204 
205  if (isTH2) {
206  TH2* hist2=(TH2*) hist;
207  Bool_t useX=(strchr(axis,'x')) || (strchr(axis,'X'));
208  Bool_t useY=(strchr(axis,'y')) || (strchr(axis,'Y'));
209  if ((!useX && !useY) || (useX && useY)) {
210  Warning("THStack", "Need parameter axis=\"x\" or \"y\" for a TH2, not none or both.");
211  return;
212  }
213  TAxis* haxis= useX ? hist->GetYaxis() : hist->GetXaxis();
214  if (!haxis) {
215  Warning("HStack","Histogram axis is NULL");
216  return;
217  }
218  Int_t nbins = haxis->GetNbins();
219  if (firstbin < 0) firstbin = 1;
220  if (lastbin < 0) lastbin = nbins;
221  if (lastbin > nbins+1) lastbin = nbins;
222  for (Int_t iBin=firstbin; iBin<=lastbin; iBin++) {
223  TH1* hProj=0;
224  if (useX) hProj=hist2->ProjectionX(Form("%s_px%d",hist2->GetName(), iBin),
225  iBin, iBin, proj_option);
226  else hProj=hist2->ProjectionY(Form("%s_py%d",hist2->GetName(), iBin),
227  iBin, iBin, proj_option);
228  Add(hProj, draw_option);
229  }
230  } else {
231  // hist is a TH3
232  TH3* hist3=(TH3*) hist;
233  TString sAxis(axis);
234  sAxis.ToLower();
235  Int_t dim=3-sAxis.Length();
236  if (dim<1 || dim>2) {
237  Warning("THStack", "Invalid length for parameter axis.");
238  return;
239  }
240 
241  if (dim==1) {
242  TAxis* haxis = 0;
243  // look for the haxis _not_ in axis
244  if (sAxis.First('x')==kNPOS)
245  haxis=hist->GetXaxis();
246  else if (sAxis.First('y')==kNPOS)
247  haxis=hist->GetYaxis();
248  else if (sAxis.First('z')==kNPOS)
249  haxis=hist->GetZaxis();
250  if (!haxis) {
251  Warning("HStack","Histogram axis is NULL");
252  return;
253  }
254 
255  Int_t nbins = haxis->GetNbins();
256  if (firstbin < 0) firstbin = 1;
257  if (lastbin < 0) lastbin = nbins;
258  if (lastbin > nbins+1) lastbin = nbins;
259  Int_t iFirstOld=haxis->GetFirst();
260  Int_t iLastOld=haxis->GetLast();
261  for (Int_t iBin=firstbin; iBin<=lastbin; iBin++) {
262  haxis->SetRange(iBin, iBin);
263  // build projection named axis_iBin (passed through "option")
264  TH1* hProj=hist3->Project3D(Form("%s_%s%s_%d", hist3->GetName(),
265  axis, proj_option, iBin));
266  Add(hProj, draw_option);
267  }
268  haxis->SetRange(iFirstOld, iLastOld);
269  } else {
270  // if dim==2
271  TAxis* haxis1 = 0;
272  TAxis* haxis2 = 0;
273  // look for the haxis _not_ in axis
274  if (sAxis.First('x')!=kNPOS) {
275  haxis1=hist->GetYaxis();
276  haxis2=hist->GetZaxis();
277  } else if (sAxis.First('y')!=kNPOS) {
278  haxis1=hist->GetXaxis();
279  haxis2=hist->GetZaxis();
280  } else if (sAxis.First('z')!=kNPOS) {
281  haxis1=hist->GetXaxis();
282  haxis2=hist->GetYaxis();
283  }
284  if (!haxis1 || !haxis2) {
285  Warning("HStack","Histogram axis is NULL");
286  return;
287  }
288 
289  Int_t nbins1 = haxis1->GetNbins();
290  Int_t nbins2 = haxis2->GetNbins();
291  if (firstbin < 0) firstbin = 1;
292  if (lastbin < 0) lastbin = nbins1;
293  if (lastbin > nbins1+1) lastbin = nbins1;
294  if (firstbin2 < 0) firstbin2 = 1;
295  if (lastbin2 < 0) lastbin2 = nbins2;
296  if (lastbin2 > nbins2+1) lastbin2 = nbins2;
297  Int_t iFirstOld1=haxis1->GetFirst();
298  Int_t iLastOld1=haxis1->GetLast();
299  Int_t iFirstOld2=haxis2->GetFirst();
300  Int_t iLastOld2=haxis2->GetLast();
301  for (Int_t iBin=firstbin; iBin<=lastbin; iBin++) {
302  haxis1->SetRange(iBin, iBin);
303  for (Int_t jBin=firstbin2; jBin<=lastbin2; jBin++) {
304  haxis2->SetRange(jBin, jBin);
305  // build projection named axis_iBin (passed through "option")
306  TH1* hProj=hist3->Project3D(Form("%s_%s%s_%d", hist3->GetName(),
307  axis, proj_option, iBin));
308  Add(hProj, draw_option);
309  }
310  }
311  haxis1->SetRange(iFirstOld1, iLastOld1);
312  haxis2->SetRange(iFirstOld2, iLastOld2);
313  }
314  } // if hist is TH2 or TH3
315 }
316 
317 ////////////////////////////////////////////////////////////////////////////////
318 /// THStack destructor
319 
320 THStack::~THStack()
321 {
322 
323  {
324  R__LOCKGUARD(gROOTMutex);
325  gROOT->GetListOfCleanups()->Remove(this);
326  }
327  if (!fHists) return;
328  fHists->Clear("nodelete");
329  delete fHists;
330  fHists = 0;
331  if (fStack) {fStack->Delete(); delete fStack;}
332  delete fHistogram;
333  fHistogram = 0;
334 }
335 
336 ////////////////////////////////////////////////////////////////////////////////
337 /// THStack copy constructor
338 
339 THStack::THStack(const THStack &hstack) :
340  TNamed(hstack),
341  fHists(0),
342  fStack(0),
343  fHistogram(0),
344  fMaximum(hstack.fMaximum),
345  fMinimum(hstack.fMinimum)
346 {
347  if (hstack.GetHists()) {
348  TIter next(hstack.GetHists());
349  TH1 *h;
350  while ((h=(TH1*)next())) Add(h);
351  }
352 }
353 
354 ////////////////////////////////////////////////////////////////////////////////
355 /// add a new histogram to the list
356 /// Only 1-d and 2-d histograms currently supported.
357 /// A drawing option may be specified
358 
359 void THStack::Add(TH1 *h1, Option_t *option)
360 {
361  if (!h1) return;
362  if (h1->GetDimension() > 2) {
363  Error("Add","THStack supports only 1-d and 2-d histograms");
364  return;
365  }
366  if (!fHists) fHists = new TList();
367  fHists->Add(h1,option);
368  Modified(); //invalidate stack
369 }
370 
371 ////////////////////////////////////////////////////////////////////////////////
372 /// Browse.
373 
374 void THStack::Browse(TBrowser *b)
375 {
376  Draw(b ? b->GetDrawOption() : "");
377  gPad->Update();
378 }
379 
380 ////////////////////////////////////////////////////////////////////////////////
381 /// build sum of all histograms
382 /// Build a separate list fStack containing the running sum of all histograms
383 
384 void THStack::BuildStack()
385 {
386  if (fStack) return;
387  if (!fHists) return;
388  Int_t nhists = fHists->GetSize();
389  if (!nhists) return;
390  fStack = new TObjArray(nhists);
391  Bool_t add = TH1::AddDirectoryStatus();
392  TH1::AddDirectory(kFALSE);
393  TH1 *h = (TH1*)fHists->At(0)->Clone();
394  fStack->Add(h);
395  for (Int_t i=1;i<nhists;i++) {
396  h = (TH1*)fHists->At(i)->Clone();
397  h->Add((TH1*)fStack->At(i-1));
398  fStack->AddAt(h,i);
399  }
400  TH1::AddDirectory(add);
401 }
402 
403 ////////////////////////////////////////////////////////////////////////////////
404 /// Compute distance from point px,py to each graph
405 ///
406 
407 Int_t THStack::DistancetoPrimitive(Int_t px, Int_t py)
408 {
409  //*-*- Are we on the axis?
410  const Int_t kMaxDiff = 10;
411  Int_t distance = 9999;
412  if (fHistogram) {
413  distance = fHistogram->DistancetoPrimitive(px,py);
414  if (distance <= 0) {return distance;}
415  if (distance <= 1) {gPad->SetSelected(fHistogram);return distance;}
416  }
417 
418 
419  //*-*- Loop on the list of histograms
420  if (!fHists) return distance;
421  TH1 *h = 0;
422  const char *doption = GetDrawOption();
423  Int_t nhists = fHists->GetSize();
424  for (Int_t i=0;i<nhists;i++) {
425  h = (TH1*)fHists->At(i);
426  if (fStack && !strstr(doption,"nostack")) h = (TH1*)fStack->At(i);
427  Int_t dist = h->DistancetoPrimitive(px,py);
428  if (dist <= 0) return 0;
429  if (dist < kMaxDiff) {
430  gPad->SetSelected(fHists->At(i));
431  gPad->SetCursor(kPointer);
432  return dist;
433  }
434  }
435  return distance;
436 }
437 
438 ////////////////////////////////////////////////////////////////////////////////
439 /// Draw this multihist with its current attributes.
440 ///
441 /// Options to draw histograms are described in THistPainter::Paint
442 /// By default (if option "nostack" is not specified), histograms will be paint
443 /// stacked on top of each other.
444 
445 void THStack::Draw(Option_t *option)
446 {
447  TString opt = option;
448  opt.ToLower();
449  if (gPad) {
450  if (!gPad->IsEditable()) gROOT->MakeDefCanvas();
451  if (!opt.Contains("same")) {
452  //the following statement is necessary in case one attempts to draw
453  //a temporary histogram already in the current pad
454  if (TestBit(kCanDelete)) gPad->GetListOfPrimitives()->Remove(this);
455  gPad->Clear();
456  }
457  }
458  AppendPad(opt.Data());
459 }
460 
461 ////////////////////////////////////////////////////////////////////////////////
462 /// Returns a pointer to the histogram used to draw the axis
463 /// Takes into account the two following cases.
464 /// 1- option 'A' was specified in THStack::Draw. Return fHistogram
465 /// 2- user had called TPad::DrawFrame. return pointer to hframe histogram
466 ///
467 /// IMPORTANT NOTES
468 /// - You must call Draw before calling this function. The returned histogram
469 /// depends on the selected Draw options.
470 /// - This function returns a pointer to an intermediate fixed bin size
471 /// histogram used to set the range and for picking.
472 /// You cannot use this histogram to return the bin information.
473 /// You must get a pointer to one of the histograms in the stack,
474 /// the first one, for example.
475 
476 TH1 *THStack::GetHistogram() const
477 {
478  if (fHistogram) return fHistogram;
479  if (!gPad) return 0;
480  gPad->Modified();
481  gPad->Update();
482  if (fHistogram) return fHistogram;
483  TH1 *h1 = (TH1*)gPad->FindObject("hframe");
484  return h1;
485 }
486 
487 ////////////////////////////////////////////////////////////////////////////////
488 /// returns the maximum of all added histograms
489 /// returns the maximum of all histograms if option "nostack".
490 
491 Double_t THStack::GetMaximum(Option_t *option)
492 {
493  TString opt = option;
494  opt.ToLower();
495  Bool_t lerr = kFALSE;
496  if (opt.Contains("e")) lerr = kTRUE;
497  Double_t them=0, themax = -1e300, c1, e1;
498  if (!fHists) return 0;
499  Int_t nhists = fHists->GetSize();
500  TH1 *h;
501  Int_t first,last;
502 
503  if (!opt.Contains("nostack")) {
504  BuildStack();
505  h = (TH1*)fStack->At(nhists-1);
506  themax = h->GetMaximum();
507  } else {
508  for (Int_t i=0;i<nhists;i++) {
509  h = (TH1*)fHists->At(i);
510  them = h->GetMaximum();
511  if (them > themax) themax = them;
512  }
513  }
514 
515  if (lerr) {
516  for (Int_t i=0;i<nhists;i++) {
517  h = (TH1*)fHists->At(i);
518  first = h->GetXaxis()->GetFirst();
519  last = h->GetXaxis()->GetLast();
520  for (Int_t j=first; j<=last;j++) {
521  e1 = h->GetBinError(j);
522  c1 = h->GetBinContent(j);
523  themax = TMath::Max(themax,c1+e1);
524  }
525  }
526  }
527 
528  return themax;
529 }
530 
531 ////////////////////////////////////////////////////////////////////////////////
532 /// returns the minimum of all added histograms
533 /// returns the minimum of all histograms if option "nostack".
534 
535 Double_t THStack::GetMinimum(Option_t *option)
536 {
537  TString opt = option;
538  opt.ToLower();
539  Bool_t lerr = kFALSE;
540  if (opt.Contains("e")) lerr = kTRUE;
541  Double_t them=0, themin = 1e300, c1, e1;
542  if (!fHists) return 0;
543  Int_t nhists = fHists->GetSize();
544  Int_t first,last;
545  TH1 *h;
546 
547  if (!opt.Contains("nostack")) {
548  BuildStack();
549  h = (TH1*)fStack->At(nhists-1);
550  themin = h->GetMinimum();
551  } else {
552  for (Int_t i=0;i<nhists;i++) {
553  h = (TH1*)fHists->At(i);
554  them = h->GetMinimum();
555  if (them <= 0 && gPad && gPad->GetLogy()) them = h->GetMinimum(0);
556  if (them < themin) themin = them;
557  }
558  }
559 
560  if (lerr) {
561  for (Int_t i=0;i<nhists;i++) {
562  h = (TH1*)fHists->At(i);
563  first = h->GetXaxis()->GetFirst();
564  last = h->GetXaxis()->GetLast();
565  for (Int_t j=first; j<=last;j++) {
566  e1 = h->GetBinError(j);
567  c1 = h->GetBinContent(j);
568  themin = TMath::Min(themin,c1-e1);
569  }
570  }
571  }
572 
573  return themin;
574 }
575 
576 ////////////////////////////////////////////////////////////////////////////////
577 /// Return the number of histograms in the stack
578 
579 Int_t THStack::GetNhists() const
580 {
581  if (fHists) return fHists->GetSize();
582  return 0;
583 }
584 
585 ////////////////////////////////////////////////////////////////////////////////
586 /// Return pointer to Stack. Build it if not yet done
587 
588 TObjArray *THStack::GetStack()
589 {
590  BuildStack();
591  return fStack;
592 }
593 
594 ////////////////////////////////////////////////////////////////////////////////
595 /// Get x axis of the histogram used to draw the stack.
596 ///
597 /// IMPORTANT NOTE
598 /// You must call Draw before calling this function. The returned histogram
599 /// depends on the selected Draw options.
600 
601 TAxis *THStack::GetXaxis() const
602 {
603  if (!gPad) return 0;
604  TH1 *h = GetHistogram();
605  if (!h) return 0;
606  return h->GetXaxis();
607 }
608 
609 ////////////////////////////////////////////////////////////////////////////////
610 /// Get x axis of the histogram used to draw the stack.
611 ///
612 /// IMPORTANT NOTE
613 /// You must call Draw before calling this function. The returned histogram
614 /// depends on the selected Draw options.
615 
616 TAxis *THStack::GetYaxis() const
617 {
618  if (!gPad) return 0;
619  TH1 *h = GetHistogram();
620  if (!h) return 0;
621  return h->GetYaxis();
622 }
623 
624 ////////////////////////////////////////////////////////////////////////////////
625 /// List histograms in the stack
626 
627 void THStack::ls(Option_t *option) const
628 {
629  TROOT::IndentLevel();
630  std::cout <<IsA()->GetName()
631  <<" Name= "<<GetName()<<" Title= "<<GetTitle()<<" Option="<<option<<std::endl;
632  TROOT::IncreaseDirLevel();
633  if (fHists) fHists->ls(option);
634  TROOT::DecreaseDirLevel();
635 }
636 ////////////////////////////////////////////////////////////////////////////////
637 /// Merge the THStack in the TList into this stack.
638 /// Returns the total number of histograms in the result or -1 in case of an error.
639 
640 Long64_t THStack::Merge(TCollection* li, TFileMergeInfo * /* info */)
641 {
642  if (li==0 || li->GetEntries()==0) {
643  return fHists->GetEntries();
644  }
645  TIter next(li);
646  TList histLists;
647  while (TObject* o = next()) {
648  THStack *stack = dynamic_cast<THStack*> (o);
649  if (!stack) {
650  Error("Merge",
651  "Cannot merge - an object which doesn't inherit from THStack found in the list");
652  return -1;
653  }
654  histLists.Add(stack->GetHists());
655  }
656  fHists->Merge(&histLists);
657  return fHists->GetEntries();
658 }
659 
660 ////////////////////////////////////////////////////////////////////////////////
661 /// invalidate sum of histograms
662 
663 void THStack::Modified()
664 {
665  if (!fStack) return;
666  fStack->Delete();
667  delete fStack;
668  fStack = 0;
669  delete fHistogram;
670  fHistogram = 0;
671 }
672 
673 ////////////////////////////////////////////////////////////////////////////////
674 /// Paint the list of histograms.
675 /// By default, histograms are shown stacked.
676 /// - the first histogram is paint
677 /// - then the sum of the first and second, etc
678 ///
679 /// If option "nostack" is specified, histograms are all paint in the same pad
680 /// as if the option "same" had been specified.
681 ///
682 /// If the option nostackb is specified histograms are all paint in the same pad
683 /// next to each other as bar plots.
684 ///
685 /// if option "pads" is specified, the current pad/canvas is subdivided into
686 /// a number of pads equal to the number of histograms and each histogram
687 /// is paint into a separate pad.
688 ///
689 /// By default the background of the histograms is erased before drawing the
690 /// histograms. The option "noclear" avoid this behaviour. This is useful
691 /// when drawing a THStack on top of an other plot. If the patterns used to
692 /// draw the histograms in the stack are transparents, then the plot behind
693 /// will be visible.
694 ///
695 /// See THistPainter::Paint for a list of valid options.
696 
697 void THStack::Paint(Option_t *choptin)
698 {
699  if (!fHists) return;
700  if (!fHists->GetSize()) return;
701 
702  char option[128];
703  strlcpy(option,choptin,128);
704 
705  // Automatic color
706  char *l1 = strstr(option,"pfc"); // Automatic Fill Color
707  char *l2 = strstr(option,"plc"); // Automatic Line Color
708  char *l3 = strstr(option,"pmc"); // Automatic Marker Color
709  if (l1 || l2 || l3) {
710  TString opt1 = option;
711  if (l1) memcpy(l1," ",3);
712  if (l2) memcpy(l2," ",3);
713  if (l3) memcpy(l3," ",3);
714  TString ws = option;
715  if (ws.IsWhitespace()) strncpy(option,"\0",1);
716  TObjOptLink *lnk = (TObjOptLink*)fHists->FirstLink();
717  TH1* hAti;
718  TH1* hsAti;
719  Int_t nhists = fHists->GetSize();
720  Int_t ic;
721  gPad->IncrementPaletteColor(nhists, opt1);
722  for (Int_t i=0;i<nhists;i++) {
723  ic = gPad->NextPaletteColor();
724  hAti = (TH1F*)(fHists->At(i));
725  if (l1) hAti->SetFillColor(ic);
726  if (l2) hAti->SetLineColor(ic);
727  if (l3) hAti->SetMarkerColor(ic);
728  if (fStack) {
729  hsAti = (TH1*)fStack->At(i);
730  if (l1) hsAti->SetFillColor(ic);
731  if (l2) hsAti->SetLineColor(ic);
732  if (l3) hsAti->SetMarkerColor(ic);
733  }
734  lnk = (TObjOptLink*)lnk->Next();
735  }
736  }
737 
738  TString opt = option;
739  opt.ToLower();
740  opt.ReplaceAll(" ","");
741  Bool_t lsame = kFALSE;
742  if (opt.Contains("same")) {
743  lsame = kTRUE;
744  opt.ReplaceAll("same","");
745  }
746  Bool_t lclear = kTRUE;
747  if (opt.Contains("noclear")) {
748  lclear = kFALSE;
749  opt.ReplaceAll("noclear","");
750  }
751  if (opt.Contains("pads")) {
752  Int_t npads = fHists->GetSize();
753  TVirtualPad *padsav = gPad;
754  //if pad is not already divided into subpads, divide it
755  Int_t nps = 0;
756  TObject *obj;
757  TIter nextp(padsav->GetListOfPrimitives());
758  while ((obj = nextp())) {
759  if (obj->InheritsFrom(TVirtualPad::Class())) nps++;
760  }
761  if (nps < npads) {
762  padsav->Clear();
763  Int_t nx = (Int_t)TMath::Sqrt((Double_t)npads);
764  if (nx*nx < npads) nx++;
765  Int_t ny = nx;
766  if (((nx*ny)-nx) >= npads) ny--;
767  padsav->Divide(nx,ny);
768  }
769  TH1 *h;
770  Int_t i = 0;
771  TObjOptLink *lnk = (TObjOptLink*)fHists->FirstLink();
772  while (lnk) {
773  i++;
774  padsav->cd(i);
775  h = (TH1*)lnk->GetObject();
776  h->Draw(lnk->GetOption());
777  lnk = (TObjOptLink*)lnk->Next();
778  }
779  padsav->cd();
780  return;
781  }
782 
783  // compute the min/max of each axis
784  TH1 *h;
785  TIter next(fHists);
786  Double_t xmin = 1e100;
787  Double_t xmax = -xmin;
788  Double_t ymin = 1e100;
789  Double_t ymax = -xmin;
790  while ((h=(TH1*)next())) {
791  // in case of automatic binning
792  if (h->GetBuffer()) h->BufferEmpty(-1);
793  if (h->GetXaxis()->GetXmin() < xmin) xmin = h->GetXaxis()->GetXmin();
794  if (h->GetXaxis()->GetXmax() > xmax) xmax = h->GetXaxis()->GetXmax();
795  if (h->GetYaxis()->GetXmin() < ymin) ymin = h->GetYaxis()->GetXmin();
796  if (h->GetYaxis()->GetXmax() > ymax) ymax = h->GetYaxis()->GetXmax();
797  }
798 
799  TString loption = opt;
800  char *nostack = (char *)strstr(loption.Data(),"nostack");
801  char *nostackb = (char *)strstr(loption.Data(),"nostackb");
802  char *candle = (char *)strstr(loption.Data(),"candle");
803  char *violin = (char *)strstr(loption.Data(),"violin");
804 
805  // do not delete the stack. Another pad may contain the same object
806  // drawn in stack mode!
807  //if (nostack && fStack) {fStack->Delete(); delete fStack; fStack = 0;}
808 
809  if (!opt.Contains("nostack") && (!opt.Contains("candle")) && (!opt.Contains("violin"))) BuildStack();
810 
811  Double_t themax,themin;
812  if (fMaximum == -1111) themax = GetMaximum(option);
813  else themax = fMaximum;
814  if (fMinimum == -1111) {
815  themin = GetMinimum(option);
816  if (gPad->GetLogy()){
817  if (themin>0) themin *= .9;
818  else themin = themax*1.e-3;
819  }
820  else if (themin > 0)
821  themin = 0;
822  }
823  else themin = fMinimum;
824  if (!fHistogram) {
825  Bool_t add = TH1::AddDirectoryStatus();
826  TH1::AddDirectory(kFALSE);
827  h = (TH1*)fHists->At(0);
828  TAxis *xaxis = h->GetXaxis();
829  TAxis *yaxis = h->GetYaxis();
830  const TArrayD *xbins = xaxis->GetXbins();
831  if (h->GetDimension() > 1) {
832  if (loption.Length()<=0) loption.Form("%s","lego1");
833  const TArrayD *ybins = yaxis->GetXbins();
834  if (xbins->fN != 0 && ybins->fN != 0) {
835  fHistogram = new TH2F(GetName(),GetTitle(),
836  xaxis->GetNbins(), xbins->GetArray(),
837  yaxis->GetNbins(), ybins->GetArray());
838  } else if (xbins->fN != 0 && ybins->fN == 0) {
839  fHistogram = new TH2F(GetName(),GetTitle(),
840  xaxis->GetNbins(), xbins->GetArray(),
841  yaxis->GetNbins(), ymin, ymax);
842  } else if (xbins->fN == 0 && ybins->fN != 0) {
843  fHistogram = new TH2F(GetName(),GetTitle(),
844  xaxis->GetNbins(), xmin, xmax,
845  yaxis->GetNbins(), ybins->GetArray());
846  } else {
847  fHistogram = new TH2F(GetName(),GetTitle(),
848  xaxis->GetNbins(), xmin, xmax,
849  yaxis->GetNbins(), ymin, ymax);
850  }
851  } else {
852  if (xbins->fN != 0) {
853  fHistogram = new TH1F(GetName(),GetTitle(),
854  xaxis->GetNbins(), xbins->GetArray());
855  } else {
856  fHistogram = new TH1F(GetName(),GetTitle(),xaxis->GetNbins(),xmin, xmax);
857  }
858  }
859  fHistogram->SetStats(0);
860  TH1::AddDirectory(add);
861  } else {
862  fHistogram->SetTitle(GetTitle());
863  }
864 
865  if (nostack) {*nostack = 0; strncat(nostack,nostack+7,7);}
866  if (nostackb) {*nostackb = 0; strncat(nostackb,nostackb+8,8);}
867  else fHistogram->GetPainter()->SetStack(fHists);
868 
869  if (!fHistogram->TestBit(TH1::kIsZoomed)) {
870  if (nostack && fMaximum != -1111) fHistogram->SetMaximum(fMaximum);
871  else {
872  if (gPad->GetLogy()) fHistogram->SetMaximum(themax*(1+0.2*TMath::Log10(themax/themin)));
873  else fHistogram->SetMaximum((1+gStyle->GetHistTopMargin())*themax);
874  }
875  if (nostack && fMinimum != -1111) fHistogram->SetMinimum(fMinimum);
876  else {
877  if (gPad->GetLogy()) fHistogram->SetMinimum(themin/(1+0.5*TMath::Log10(themax/themin)));
878  else fHistogram->SetMinimum(themin);
879  }
880  }
881 
882  // Copy the axis labels if needed.
883  TH1 *hfirst;
884  TObjOptLink *lnk = (TObjOptLink*)fHists->FirstLink();
885  hfirst = (TH1*)lnk->GetObject();
886  THashList* labels = hfirst->GetXaxis()->GetLabels();
887  if (labels) {
888  TIter iL(labels);
889  TObjString* lb;
890  Int_t ilab = 1;
891  while ((lb=(TObjString*)iL())) {
892  fHistogram->GetXaxis()->SetBinLabel(ilab,lb->String().Data());
893  ilab++;
894  }
895  }
896 
897  if (!lsame) fHistogram->Paint(loption.Data());
898 
899  if (fHistogram->GetDimension() > 1) SetDrawOption(loption.Data());
900  if (loption.Index("lego")>=0) return;
901 
902  char noption[32];
903  strlcpy(noption,loption.Data(),32);
904  Int_t nhists = fHists->GetSize();
905  if (nostack || candle || violin) {
906  lnk = (TObjOptLink*)fHists->FirstLink();
907  TH1* hAti;
908  Double_t bo=0.03;
909  Double_t bw = (1.-(2*bo))/nhists;
910  for (Int_t i=0;i<nhists;i++) {
911  if (strstr(lnk->GetOption(),"same")) {
912  if (nostackb) loption.Form("%s%s b",noption,lnk->GetOption());
913  else loption.Form("%s%s",noption,lnk->GetOption());
914  } else {
915  TString indivOpt = lnk->GetOption();
916  indivOpt.ToLower();
917  if (nostackb) loption.Form("%ssame%s b",noption,lnk->GetOption());
918  else if (candle && (indivOpt.Contains("candle") || indivOpt.Contains("violin"))) loption.Form("%ssame",lnk->GetOption());
919  else loption.Form("%ssame%s",noption,lnk->GetOption());
920  }
921  hAti = (TH1F*)(fHists->At(i));
922  if (nostackb) {
923  hAti->SetBarWidth(bw);
924  hAti->SetBarOffset(bo);
925  bo += bw;
926  }
927  if (candle || violin) {
928  float candleSpace = 1./(nhists*2);
929  float candleOffset = - 1./2 + candleSpace + 2*candleSpace*i;
930  candleSpace *= 1.66; //width of the candle per bin: 1.0 means space is as great as the candle, 2.0 means there is no space
931  hAti->SetBarWidth(candleSpace);
932  hAti->SetBarOffset(candleOffset);
933  }
934  hAti->Paint(loption.Data());
935  lnk = (TObjOptLink*)lnk->Next();
936  }
937  } else {
938  lnk = (TObjOptLink*)fHists->LastLink();
939  TH1 *h1;
940  Int_t h1col, h1fill;
941  for (Int_t i=0;i<nhists;i++) {
942  if (strstr(lnk->GetOption(),"same")) {
943  loption.Form("%s%s",noption,lnk->GetOption());
944  } else {
945  loption.Form("%ssame%s",noption,lnk->GetOption());
946  }
947  h1 = (TH1*)fStack->At(nhists-i-1);
948  if (i>0 && lclear) {
949  // Erase before drawing the histogram
950  h1col = h1->GetFillColor();
951  h1fill = h1->GetFillStyle();
952  h1->SetFillColor(10);
953  h1->SetFillStyle(1001);
954  h1->Paint(loption.Data());
955  static TClassRef clTFrame = TClass::GetClass("TFrame",kFALSE);
956  TAttFill *frameFill = (TAttFill*)clTFrame->DynamicCast(TAttFill::Class(),gPad->GetFrame());
957  if (frameFill) {
958  h1->SetFillColor(frameFill->GetFillColor());
959  h1->SetFillStyle(frameFill->GetFillStyle());
960  }
961  h1->Paint(loption.Data());
962  h1->SetFillColor(h1col);
963  h1->SetFillStyle(h1fill);
964  }
965  h1->Paint(loption.Data());
966  lnk = (TObjOptLink*)lnk->Prev();
967  }
968  }
969 
970  opt.ReplaceAll("nostack","");
971  opt.ReplaceAll("candle","");
972  if (!lsame && !opt.Contains("a")) fHistogram->Paint("axissame");
973 }
974 
975 ////////////////////////////////////////////////////////////////////////////////
976 /// Print the list of histograms
977 
978 void THStack::Print(Option_t *option) const
979 {
980  TH1 *h;
981  if (fHists) {
982  TIter next(fHists);
983  while ((h = (TH1*) next())) {
984  h->Print(option);
985  }
986  }
987 }
988 
989 ////////////////////////////////////////////////////////////////////////////////
990 /// Recursively remove object from the list of histograms
991 
992 void THStack::RecursiveRemove(TObject *obj)
993 {
994  if (!fHists) return;
995  fHists->RecursiveRemove(obj);
996  while (fHists->IndexOf(obj) >= 0) fHists->Remove(obj);
997 }
998 
999 ////////////////////////////////////////////////////////////////////////////////
1000 /// Save primitive as a C++ statement(s) on output stream out
1001 
1002 void THStack::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
1003 {
1004  char quote = '"';
1005  out<<" "<<std::endl;
1006  if (gROOT->ClassSaved(THStack::Class())) {
1007  out<<" ";
1008  } else {
1009  out<<" THStack *";
1010  }
1011  out<<GetName()<<" = new THStack();"<<std::endl;
1012  out<<" "<<GetName()<<"->SetName("<<quote<<GetName()<<quote<<");"<<std::endl;
1013  out<<" "<<GetName()<<"->SetTitle("<<quote<<GetTitle()<<quote<<");"<<std::endl;
1014 
1015  if (fMinimum != -1111) {
1016  out<<" "<<GetName()<<"->SetMinimum("<<fMinimum<<");"<<std::endl;
1017  }
1018  if (fMaximum != -1111) {
1019  out<<" "<<GetName()<<"->SetMaximum("<<fMaximum<<");"<<std::endl;
1020  }
1021 
1022  static Int_t frameNumber = 0;
1023  if (fHistogram) {
1024  frameNumber++;
1025  TString hname = fHistogram->GetName();
1026  hname += "_stack_";
1027  hname += frameNumber;
1028  fHistogram->SetName(hname.Data());
1029  fHistogram->SavePrimitive(out,"nodraw");
1030  out<<" "<<GetName()<<"->SetHistogram("<<fHistogram->GetName()<<");"<<std::endl;
1031  out<<" "<<std::endl;
1032  }
1033 
1034  TH1 *h;
1035  if (fHists) {
1036  TObjOptLink *lnk = (TObjOptLink*)fHists->FirstLink();
1037  Int_t hcount = 0;
1038  while (lnk) {
1039  h = (TH1*)lnk->GetObject();
1040  TString hname = h->GetName();
1041  hname += Form("_stack_%d",++hcount);
1042  h->SetName(hname);
1043  h->SavePrimitive(out,"nodraw");
1044  out<<" "<<GetName()<<"->Add("<<h->GetName()<<","<<quote<<lnk->GetOption()<<quote<<");"<<std::endl;
1045  lnk = (TObjOptLink*)lnk->Next();
1046  }
1047  }
1048  out<<" "<<GetName()<<"->Draw("
1049  <<quote<<option<<quote<<");"<<std::endl;
1050 }
1051 
1052 ////////////////////////////////////////////////////////////////////////////////
1053 /// Set maximum.
1054 
1055 void THStack::SetMaximum(Double_t maximum)
1056 {
1057  fMaximum = maximum;
1058  if (fHistogram) fHistogram->SetMaximum(maximum);
1059 }
1060 
1061 ////////////////////////////////////////////////////////////////////////////////
1062 /// Set minimum.
1063 
1064 void THStack::SetMinimum(Double_t minimum)
1065 {
1066  fMinimum = minimum;
1067  if (fHistogram) fHistogram->SetMinimum(minimum);
1068 }
1069 
1070 
1071 ////////////////////////////////////////////////////////////////////////////////
1072 /// Get iterator over internal hists list.
1073 TIter THStack::begin() const
1074 {
1075  return TIter(fHists);
1076 }