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