1    	//////////////////////////////////////////////////////////////////////////
2    	//                                                                      //
3    	//  StMultiH2F allows multiple similar TH2F 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 "StMultiH2F.h"
14   	#include "TString.h"
15   	#include "TLegend.h"
16   	#include "TPad.h"
17   	#include "TDirectory.h"
18   	
19   	ClassImp(StMultiH2F)
20   	
21   	StMultiH2F::StMultiH2F() : subHists(0) {}
22   	
23   	StMultiH2F::StMultiH2F(const char *name,const char *title,Int_t nbinsx,
24   			       Axis_t xlow,Axis_t xup,Int_t nbinsy,Axis_t ylow,
25   	                       Axis_t yup,Int_t nbinsz) :
26   	  TH3F(name,title,nbinsx,xlow,xup,nbinsy,ylow,yup,nbinsz,-0.5,-0.5+nbinsz),
27   	  subHists(0) {}
28   	
29   	StMultiH2F::~StMultiH2F() {
30   	  if (subHists) {
31   	    int zbins = TMath::Min(GetNbinsZ(),StMultiH2FMaxBins);
32   	    for (int zbin=0; zbin<zbins; zbin++) delete subHists[zbin];
33   	  }
34   	}
35   	
36   	void StMultiH2F::Draw(Option_t *option) {
37   	  // Probably only the "box" and "cont" options are reasonable here
38   	
39   	  int x0 = fXaxis.GetFirst();
40   	  int x1 = fXaxis.GetLast();
41   	  int y0 = fYaxis.GetFirst();
42   	  int y1 = fYaxis.GetLast();
43   	  fXaxis.SetRange();
44   	  fYaxis.SetRange();
45   	  int zbins = TMath::Min(GetNbinsZ(),StMultiH2FMaxBins);
46   	
47   	  // dummy histogram pointer(s)
48   	  if (!subHists) { subHists = new TH2D*[zbins]; memset(subHists,0,zbins*sizeof(TH2D*)); }
49   	
50   	  if (zbins == 1) {
51   	    delete subHists[0];
52   	    subHists[0] = XYProjection(GetName());
53   	    subHists[0]->SetStats((!TestBit(kNoStats)));
54   	    TAxis* taxisX = subHists[0]->GetXaxis();
55   	    TAxis* taxisY = subHists[0]->GetYaxis();
56   	    fXaxis.Copy(*taxisX);
57   	    fYaxis.Copy(*taxisY);
58   	    taxisX->SetRange(x0,x1);
59   	    taxisY->SetRange(y0,y1);
60   	    fXaxis.SetRange(x0,x1);
61   	    fYaxis.SetRange(y0,y1);
62   	    subHists[0]->Draw(option);
63   	    return;
64   	  }
65   	
66   	  // overlay the z bins of the 3d histogram into a 2d histogram
67   	  // using different box colors
68   	
69   	  // make a legend
70   	  TLegend *legend = new TLegend(0.80,0.84,0.98,0.98,"Legend","NDC");
71   	  legend->SetFillColor(0);
72   	  legend->SetFillStyle(0);
73   	  legend->SetMargin(0.25);
74   	
75   	  int zbin;
76   	  double maxval = -999999.;
77   	  int maxbin = -1;
78   	
79   	  TString n0;
80   	  for (zbin=0; zbin<zbins; zbin++) {
81   	    if ((zbin >= 10) || (names[zbin].IsNull())) n0 = GetName();
82   	    else n0 = names[zbin];
83   	    int slice = zbin+1;
84   	    delete subHists[zbin];
85   	    subHists[zbin] = XYProjection(n0.Data(),slice);
86   	    subHists[zbin]->SetLineColor(60+40*(zbin/(zbins-1)));
87   	    subHists[zbin]->SetStats(kFALSE);
88   	    TAxis* taxisX = subHists[zbin]->GetXaxis();
89   	    TAxis* taxisY = subHists[zbin]->GetYaxis();
90   	    fXaxis.Copy(*taxisX);
91   	    fYaxis.Copy(*taxisY);
92   	    taxisX->SetRange(x0,x1);
93   	    taxisY->SetRange(y0,y1);
94   	  
95   	    double binmax = subHists[zbin]->GetMaximum();
96   	    if (binmax > maxval) {
97   	      maxval = binmax;
98   	      maxbin = zbin;
99   	    }
100  	    legend->AddEntry(subHists[zbin],n0.Data(),"l");
101  	  }
102  	
103  	  subHists[maxbin]->SetTitle(GetTitle());
104  	  subHists[maxbin]->Draw(option);
105  	  TString sameoption = option; sameoption += "same";
106  	  for (zbin=0; zbin<zbins; zbin++) {
107  	    if (zbin != maxbin) subHists[zbin]->Draw(sameoption.Data());
108  	  }
109  	
110  	  // Draw statistics for full set if stats are turned on
111  	  if (!TestBit(kNoStats)) {
112  	    delete subHists[0];
113  	    subHists[0] = XYProjection(GetName());
114  	    subHists[0]->Reset();
115  	    subHists[0]->SetEntries(GetEntries());
116  	    subHists[0]->SetStats(kTRUE);
117  	    subHists[0]->Draw(sameoption.Data());
118  	    legend->SetX1(0.59);
119  	    legend->SetX2(0.77);
120  	  }
121  	
122  	  legend->Draw();
123  	
124  	  fXaxis.SetRange(x0,x1);
125  	  fYaxis.SetRange(y0,y1);
126  	}
127  	
128  	TH2D* StMultiH2F::XYProjection(const char* name, Int_t zbin) {
129  	  static char buf[256];
130  	  if (zbin<0) sprintf(buf,"%s.",name);
131  	  else sprintf(buf,"%s_%d_%s",GetName(),zbin,name);
132  	
133  	  TList* tgList = gDirectory->GetList();
134  	  TH2D* temp = (TH2D*) tgList->FindObject(buf);
135  	  if (temp) tgList->Remove(temp);
136  	
137  	  if (zbin<0) fZaxis.SetRange();
138  	  else fZaxis.SetRange(zbin,zbin);
139  	  temp = (TH2D*) Project3D("yx");
140  	  temp->SetName(buf);
141  	  TAttLine::Copy(*temp);
142  	  TAttFill::Copy(*temp);
143  	  TAttMarker::Copy(*temp);
144  	  temp->GetXaxis()->SetRange(fXaxis.GetFirst(),fXaxis.GetLast());
145  	  temp->GetYaxis()->SetRange(fYaxis.GetFirst(),fYaxis.GetLast());
146  	  return temp; // up to the user of this function delete
147  	}
148  	
149  	void StMultiH2F::SavePrimitive(ostream& out, Option_t* option) {
150  	  // Save primitive as a C++ statement(s) on output stream out
151  	
152  	  bool nonEqiX = kFALSE;
153  	  bool nonEqiY = kFALSE;
154  	  int i;
155  	
156  	  // Check if the histogram has equidistant X bins or not.  If not, we
157  	  // create an array holding the bins.
158  	  if (GetXaxis()->GetXbins()->fN && GetXaxis()->GetXbins()->fArray) {
159  	    nonEqiX = kTRUE;
160  	    out << "   Double_t xAxis[" << GetXaxis()->GetXbins()->fN
161  	        << "] = {";
162  	    for (i = 0; i < GetXaxis()->GetXbins()->fN; i++) {
163  	      if (i != 0) out << ", ";
164  	      out << GetXaxis()->GetXbins()->fArray[i];
165  	    }
166  	    out << "}; " << endl;
167  	  }
168  	
169  	  // Check if the histogram has equidistant Y bins or not.  If not, we
170  	  // create an array holding the bins.
171  	  if (GetYaxis()->GetXbins()->fN && GetYaxis()->GetXbins()->fArray) {
172  	    nonEqiY = kTRUE;
173  	    out << "   Double_t yAxis[" << GetYaxis()->GetXbins()->fN
174  	        << "] = {";
175  	    for (i = 0; i < GetYaxis()->GetXbins()->fN; i++) {
176  	      if (i != 0) out << ", ";
177  	      out << GetYaxis()->GetXbins()->fArray[i];
178  	    }
179  	    out << "}; " << endl;
180  	  }
181  	
182  	  char quote = '"';
183  	  out <<"   "<<endl;
184  	  out <<"   TH1 *" << GetName() << " = new " << ClassName() << "("
185  	      << quote << GetName() << quote << "," << quote << GetTitle() << quote
186  	      << "," << GetXaxis()->GetNbins();
187  	  if (nonEqiX)
188  	    out << ", xAxis";
189  	  else
190  	    out << "," << GetXaxis()->GetXmin()
191  	        << "," << GetXaxis()->GetXmax();
192  	  if (nonEqiY)
193  	    out << ", yAxis";
194  	  else
195  	    out << "," << GetYaxis()->GetXmin()
196  	        << "," << GetYaxis()->GetXmax();
197  	  out << "," << GetZaxis()->GetNbins() << ");" << endl;
198  	
199  	  // save bin contents
200  	  int bin;
201  	  for (bin=0;bin<fNcells;bin++) {
202  	    double bc = GetBinContent(bin);
203  	    if (bc) {
204  	      out<<"   "<<GetName()<<"->SetBinContent("<<bin<<","<<bc<<");"<<endl;
205  	    }
206  	  }
207  	
208  	  // save bin errors
209  	  if (fSumw2.fN) {
210  	    for (bin=0;bin<fNcells;bin++) {
211  	      double be = GetBinError(bin);
212  	      if (be) {
213  	        out <<"   "<<GetName()<<"->SetBinError("<<bin<<","<<be<<");"<<endl;
214  	      }
215  	    }
216  	  }
217  	
218  	  for (bin=0;bin<GetZaxis()->GetNbins();bin++) {
219  	    if (!(names[bin].IsNull()))
220  	      out <<"   "<<GetName()<< "->Rebin(" << bin << ","
221  	          << quote << names[bin] << quote << ");" << endl;
222  	  }
223  	
224  	  TH1::SavePrimitiveHelp(out, option);
225  	}
226  	
227  	// $Id: StMultiH2F.cxx,v 1.8 2016/05/27 18:02:41 genevb Exp $
228  	// $Log: StMultiH2F.cxx,v $
229  	// Revision 1.8  2016/05/27 18:02:41  genevb
230  	// Garbage collection (Coverity), remove unnecessary ROOT types
231  	//
232  	// Revision 1.7  2015/07/20 18:27:47  genevb
233  	// fix minor bug with SavePrimitive
234  	//
235  	// Revision 1.6  2013/11/21 22:22:48  genevb
236  	// Protect against array out-of-bounds, use inherited axis handles
237  	//
238  	// Revision 1.5  2008/07/10 21:26:59  genevb
239  	// Allow SavePrimitive of fully drawn TPad to work properly
240  	//
241  	// Revision 1.4  2008/07/09 20:52:38  genevb
242  	// Implement SavePrimitive functions
243  	//
244  	// Revision 1.3  2007/04/24 17:45:33  genevb
245  	// Patched for problems with limited axis ranges
246  	//
247  	// Revision 1.2  2007/04/12 22:39:13  genevb
248  	// Remove drawing of underflows
249  	//
250  	// Revision 1.1  2007/03/13 16:22:31  genevb
251  	// Introduce StMultiH2F class
252  	//
253  	//
254