1    	//////////////////////////////////////////////////////////////////////////
2    	//                                                                      //
3    	//  StMultiH1F allows multiple similar TH1F histograms to be            //
4    	//  easily plotted on one graph                                         //
5    	//                                                                      //
6    	//////////////////////////////////////////////////////////////////////////
7    	
8    	#ifdef __HP_aCC
9    	#include <Stiostream.h>
10   	#else
11   	#include "Stiostream.h"
12   	#endif
13   	#include "StMultiH1F.h"
14   	#include "TString.h"
15   	#include "TLegend.h"
16   	#include "TPad.h"
17   	#include "TDirectory.h"
18   	#include "TMath.h"
19   	ClassImp(StMultiH1F)
20   	
21   	StMultiH1F::StMultiH1F() : fMOffset(0.), subHists(0), aHist(0) {}
22   	
23   	StMultiH1F::StMultiH1F(const char *name,const char *title,Int_t nbinsx,
24   			       Axis_t xlow,Axis_t xup ,Int_t nbinsy) :
25   	  TH2F(name,title,nbinsx,xlow,xup,nbinsy,-0.5,-0.5+nbinsy),
26   	  fMOffset(0.), subHists(0), aHist(0) {}
27   	
28   	StMultiH1F::StMultiH1F(const char *name,const char *title,Int_t nbinsx,
29   			       Double_t *xbins,Int_t nbinsy) :
30   	  TH2F(name,title,nbinsx,xbins,nbinsy,-0.5,-0.5+nbinsy),
31   	  fMOffset(0.), subHists(0), aHist(0) {}
32   	
33   	StMultiH1F::~StMultiH1F() {
34   	  if (subHists) {
35   	    int ybins = TMath::Min(GetNbinsY(),StMultiH1FMaxBins);
36   	    for (int ybin=0; ybin<ybins; ybin++) delete subHists[ybin];
37   	  }
38   	}
39   	
40   	void StMultiH1F::Draw(Option_t *option) {
41   	
42   	  int x0 = fXaxis.GetFirst();
43   	  int x1 = fXaxis.GetLast();
44   	  fXaxis.SetRange();
45   	  int ybins = TMath::Min(GetNbinsY(),StMultiH1FMaxBins);
46   	
47   	  // dummy histogram pointer(s)
48   	  if (!subHists) { subHists = new TH1F*[ybins]; memset(subHists,0,ybins*sizeof(TH1F*)); }
49   	
50   	  if (ybins == 1) {
51   	    delete subHists[0];
52   	    subHists[0] = XProjection(GetName());
53   	    subHists[0]->SetStats((!TestBit(kNoStats)));
54   	    TAxis* taxis = subHists[0]->GetXaxis();
55   	    fXaxis.Copy(*taxis);
56   	    taxis->SetRange(x0,x1);
57   	    fXaxis.SetRange(x0,x1);
58   	    if (fMinimum != -1111)  subHists[0]->SetMinimum(fMinimum);
59   	    if (fMaximum != -1111)  subHists[0]->SetMaximum(fMaximum);
60   	    subHists[0]->Draw();
61   	    return;
62   	  }
63   	
64   	  // overlay the y bins of the 2d histogram into a 1d histogram
65   	  // using different line styles
66   	
67   	  // make a legend
68   	  TLegend *legend = new TLegend(0.80,0.84,0.98,0.98,"Legend","NDC");
69   	  legend->SetFillColor(0);
70   	  legend->SetFillStyle(0);
71   	  legend->SetMargin(0.25);
72   	
73   	  int ybin;
74   	  double maxval = -1e31;
75   	  double minval = 1e31;
76   	  int maxbin = -1;
77   	  int minbin = -1;
78   	  float offset = fMOffset;
79   	  if (fMOffset && gPad->GetLogy()) {
80   	    float max_offset = TMath::Power(
81   	      1.0e10*GetNonZeroMinimum()/GetNonZeroMaximum(),
82   	      1.0/(ybins-1.0));
83   	    if (offset > max_offset) offset = max_offset;
84   	  }
85   	
86   	  TString n0;
87   	  for (ybin=0; ybin<ybins; ybin++) {
88   	    if (names[ybin].IsNull()) n0 = GetName();
89   	    else n0 = names[ybin];
90   	    int slice = ybin+1;
91   	    delete subHists[ybin];
92   	    subHists[ybin] = XProjection(n0.Data(),slice);
93   	    subHists[ybin]->SetLineStyle(slice);
94   	    subHists[ybin]->SetStats(kFALSE);
95   	    TAxis* taxis = subHists[ybin]->GetXaxis();
96   	    fXaxis.Copy(*taxis);
97   	    taxis->SetRange(x0,x1);
98   	
99   	    if (fMOffset && ybin) {
100  	      subHists[ybin]->SetLineColor(slice);
101  	      if (gPad->GetLogy()) {
102  	        subHists[ybin]->Scale(TMath::Power(offset,ybin));
103  	      } else {
104  	        for (int xbin=0; xbin<GetNbinsX(); xbin++)
105  	          subHists[ybin]->AddBinContent(xbin,offset*ybin);
106  	      }
107  	    }
108  	
109  	    double binmax = subHists[ybin]->GetMaximum();
110  	    double binmin = subHists[ybin]->GetMinimum();
111  	    if (binmax > maxval) { maxval = binmax; maxbin = ybin; }
112  	    if (binmin < minval) { minval = binmin; minbin = ybin; }
113  	    legend->AddEntry(subHists[ybin],n0.Data(),"l");
114  	  }
115  	
116  	  // can't use the option argument in Draw() since this is called from
117  	  // StHistUtil::DrawHists(), which defaults 2D histograms to a box plot
118  	  if (maxbin == minbin) {
119  	    if (fMinimum != -1111)  subHists[maxbin]->SetMinimum(fMinimum);
120  	    if (fMaximum != -1111)  subHists[maxbin]->SetMaximum(fMaximum);
121  	    subHists[maxbin]->Draw();
122  	  } else {
123  	    delete aHist;
124  	    aHist = new TH1F(*(subHists[maxbin]));
125  	    aHist->SetName(Form("%s_%d",GetName(),ybins+1));
126  	    aHist->SetBinContent(1,maxval);
127  	    aHist->SetBinContent(2,minval);
128  	    aHist->SetMarkerStyle(1); aHist->SetMarkerColor(0);
129  	    if (fMinimum != -1111)  aHist->SetMinimum(fMinimum);
130  	    if (fMaximum != -1111)  aHist->SetMaximum(fMaximum);
131  	    aHist->Draw("p");
132  	    maxbin = -1;
133  	  }
134  	  for (ybin=0; ybin<ybins; ybin++) {
135  	    if (ybin != maxbin) subHists[ybin]->Draw("same");
136  	  }
137  	
138  	  // Draw statistics for full set if stats are turned on
139  	  if (!TestBit(kNoStats)) {
140  	    subHists[0] = XProjection(GetName());
141  	    subHists[0]->SetEntries(GetEntries());
142  	    subHists[0]->SetStats(kTRUE);
143  	    subHists[0]->Draw("boxsames");
144  	    legend->SetX1(0.59);
145  	    legend->SetX2(0.77);
146  	  }
147  	
148  	  legend->Draw();
149  	
150  	  fXaxis.SetRange(x0,x1);
151  	}
152  	
153  	TH1F* StMultiH1F::XProjection(const char* name, Int_t ybin) {
154  	  static char buf[256];
155  	  if (ybin<0) sprintf(buf,"%s.",name);
156  	  else sprintf(buf,"%s_%d_%s",GetName(),ybin,name);
157  	
158  	  TList* tgList = gDirectory->GetList();
159  	  TH1F* temp = (TH1F*) tgList->FindObject(buf);
160  	  if (temp) tgList->Remove(temp);
161  	
162  	  if (ybin<0) temp = (TH1F*) ProjectionX(buf);
163  	  else temp = (TH1F*) ProjectionX(buf,ybin,ybin);
164  	  TAttLine::Copy(*temp);
165  	  TAttFill::Copy(*temp);
166  	  TAttMarker::Copy(*temp);
167  	  return temp; // up to the user of this function to delete
168  	}
169  	
170  	void StMultiH1F::SetBarOffset(Float_t offset) {
171  	  if (offset == 0.25) {
172  	    fMOffset = 1.2 * (GetMaximum() - GetMinimum());
173  	    if (!fMOffset) fMOffset = 10.0;
174  	  } else {
175  	    fMOffset = offset;
176  	  }
177  	}
178  	
179  	Double_t StMultiH1F::GetNonZeroMinimum() const {
180  	  Double_t value, minimum = GetMinimum();
181  	  if (minimum) return minimum;
182  	  minimum = GetMaximum();
183  	  int bin, binx, biny, binz;
184  	  int xfirst  = fXaxis.GetFirst();
185  	  int xlast   = fXaxis.GetLast();
186  	  int yfirst  = fYaxis.GetFirst();
187  	  int ylast   = TMath::Min(fYaxis.GetLast(),StMultiH1FMaxBins);
188  	  int zfirst  = fZaxis.GetFirst();
189  	  int zlast   = fZaxis.GetLast();
190  	  for (binz=zfirst;binz<=zlast;binz++) {
191  	     for (biny=yfirst;biny<=ylast;biny++) {
192  	        for (binx=xfirst;binx<=xlast;binx++) {
193  	           bin = GetBin(binx,biny,binz);
194  	           value = GetBinContent(bin);
195  	           if (value && value < minimum) minimum = value;
196  	        }
197  	     }
198  	  }
199  	  if (!minimum) minimum = -1.0;
200  	  return minimum;
201  	}
202  	
203  	Double_t StMultiH1F::GetNonZeroMaximum() const {
204  	  Double_t value, maximum = GetMaximum();
205  	  if (maximum) return maximum;
206  	  maximum = GetMinimum();
207  	  int bin, binx, biny, binz;
208  	  int xfirst  = fXaxis.GetFirst();
209  	  int xlast   = fXaxis.GetLast();
210  	  int yfirst  = fYaxis.GetFirst();
211  	  int ylast   = TMath::Min(fYaxis.GetLast(),StMultiH1FMaxBins);
212  	  int zfirst  = fZaxis.GetFirst();
213  	  int zlast   = fZaxis.GetLast();
214  	  for (binz=zfirst;binz<=zlast;binz++) {
215  	     for (biny=yfirst;biny<=ylast;biny++) {
216  	        for (binx=xfirst;binx<=xlast;binx++) {
217  	           bin = GetBin(binx,biny,binz);
218  	           value = GetBinContent(bin);
219  	           if (value && value > maximum) maximum = value;
220  	        }
221  	     }
222  	  }
223  	  if (!maximum) maximum = -1.0;
224  	  return maximum;
225  	}
226  	
227  	void StMultiH1F::SavePrimitive(ostream& out, Option_t* option) {
228  	  // Save primitive as a C++ statement(s) on output stream out
229  	
230  	  bool nonEqiX = kFALSE;
231  	  int i;
232  	
233  	  // Check if the histogram has equidistant X bins or not.  If not, we
234  	  // create an array holding the bins.
235  	  if (GetXaxis()->GetXbins()->fN && GetXaxis()->GetXbins()->fArray) {
236  	    nonEqiX = kTRUE;
237  	    out << "   Double_t xAxis[" << GetXaxis()->GetXbins()->fN
238  	        << "] = {";
239  	    for (i = 0; i < GetXaxis()->GetXbins()->fN; i++) {
240  	      if (i != 0) out << ", ";
241  	      out << GetXaxis()->GetXbins()->fArray[i];
242  	    }
243  	    out << "}; " << endl;
244  	  }
245  	
246  	  char quote = '"';
247  	  out <<"   "<<endl;
248  	  out <<"   TH1 *" << GetName() << " = new " << ClassName() << "("
249  	      << quote << GetName() << quote << "," << quote << GetTitle() << quote
250  	      << "," << GetXaxis()->GetNbins();
251  	  if (nonEqiX)
252  	    out << ", xAxis";
253  	  else
254  	    out << "," << GetXaxis()->GetXmin()
255  	        << "," << GetXaxis()->GetXmax();
256  	  out << "," << GetYaxis()->GetNbins() << ");" << endl;
257  	
258  	  // save bin contents
259  	  int bin;
260  	  for (bin=0;bin<fNcells;bin++) {
261  	    double bc = GetBinContent(bin);
262  	    if (bc) {
263  	      out<<"   "<<GetName()<<"->SetBinContent("<<bin<<","<<bc<<");"<<endl;
264  	    }
265  	  }
266  	
267  	  // save bin errors
268  	  if (fSumw2.fN) {
269  	    for (bin=0;bin<fNcells;bin++) {
270  	      double be = GetBinError(bin);
271  	      if (be) {
272  	        out <<"   "<<GetName()<<"->SetBinError("<<bin<<","<<be<<");"<<endl;
273  	      }
274  	    }
275  	  }
276  	
277  	  for (bin=0;bin<GetYaxis()->GetNbins();bin++) {
278  	    if (!(names[bin].IsNull()))
279  	      out <<"   "<<GetName()<< "->Rebin(" << bin << ","
280  	          << quote << names[bin] << quote << ");" << endl;
281  	  }
282  	  if (fMOffset != 0)
283  	    out <<"   "<<GetName()<< "->SetBarOffset(" << fMOffset << ");" << endl;
284  	
285  	  TH1::SavePrimitiveHelp(out, option);
286  	}
287  	
288  	// $Id: StMultiH1F.cxx,v 1.17 2016/05/27 18:02:41 genevb Exp $
289  	// $Log: StMultiH1F.cxx,v $
290  	// Revision 1.17  2016/05/27 18:02:41  genevb
291  	// Garbage collection (Coverity), remove unnecessary ROOT types
292  	//
293  	// Revision 1.16  2015/05/26 15:40:30  genevb
294  	// Handle set min/maxima
295  	//
296  	// Revision 1.15  2013/11/21 22:22:47  genevb
297  	// Protect against array out-of-bounds, use inherited axis handles
298  	//
299  	// Revision 1.14  2008/07/10 21:26:59  genevb
300  	// Allow SavePrimitive of fully drawn TPad to work properly
301  	//
302  	// Revision 1.13  2008/07/09 20:52:38  genevb
303  	// Implement SavePrimitive functions
304  	//
305  	// Revision 1.12  2007/07/12 20:26:03  fisyak
306  	// Add includes for ROOT 5.16
307  	//
308  	// Revision 1.11  2007/04/24 17:45:32  genevb
309  	// Patched for problems with limited axis ranges
310  	//
311  	// Revision 1.10  2007/04/06 20:05:30  genevb
312  	// Allow for lower minima
313  	//
314  	// Revision 1.9  2003/09/02 17:59:20  perev
315  	// gcc 3.2 updates + WarnOff
316  	//
317  	// Revision 1.8  2003/01/21 18:33:27  genevb
318  	// Better handling of temporary hists
319  	//
320  	// Revision 1.7  2002/04/23 01:59:16  genevb
321  	// New offset abilities
322  	//
323  	// Revision 1.6  2000/09/15 21:23:36  fisyak
324  	// HP does not have iostream
325  	//
326  	// Revision 1.5  2000/08/28 19:21:05  genevb
327  	// Improved projection code
328  	//
329  	// Revision 1.4  2000/08/28 18:47:50  genevb
330  	// Better handling of 1 y-bin case
331  	//
332  	// Revision 1.3  2000/08/25 22:03:39  genevb
333  	// Fixed entries problem
334  	//
335  	// Revision 1.2  2000/08/25 15:46:42  genevb
336  	// Added stats box, legend names
337  	//
338  	// Revision 1.1  2000/07/26 22:00:27  lansdell
339  	// new multi-hist class for superimposing the x-projections of y-bins (of a TH2F histogram) into one TH1F histogram
340  	//
341  	
342