Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooHist.cxx
Go to the documentation of this file.
1 /*****************************************************************************
2  * Project: RooFit *
3  * Package: RooFitCore *
4  * @(#)root/roofitcore:$Id$
5  * Authors: *
6  * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7  * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8  * *
9  * Copyright (c) 2000-2005, Regents of the University of California *
10  * and Stanford University. All rights reserved. *
11  * *
12  * Redistribution and use in source and binary forms, *
13  * with or without modification, are permitted according to the terms *
14  * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15  *****************************************************************************/
16 
17 /**
18 \file RooHist.cxx
19 \class RooHist
20 \ingroup Roofitcore
21 
22 A RooHist is a graphical representation of binned data based on the
23 TGraphAsymmErrors class. Error bars are calculated using either Poisson
24 or Binomial statistics. A RooHist is used to represent histograms in
25 a RooPlot.
26 **/
27 
28 #include "RooFit.h"
29 
30 #include "RooHist.h"
31 #include "RooHist.h"
32 #include "RooHistError.h"
33 #include "RooCurve.h"
34 #include "RooScaledFunc.h"
35 #include "RooMsgService.h"
36 
37 #include "TH1.h"
38 #include "TClass.h"
39 #include "Riostream.h"
40 #include <iomanip>
41 
42 using namespace std;
43 
44 ClassImp(RooHist);
45  ;
46 
47 
48 ////////////////////////////////////////////////////////////////////////////////
49 /// Default constructor
50 
51 RooHist::RooHist() :
52  _nominalBinWidth(1),
53  _nSigma(1),
54  _entries(0),
55  _rawEntries(0)
56 {
57 }
58 
59 
60 
61 ////////////////////////////////////////////////////////////////////////////////
62 /// Create an empty histogram that can be filled with the addBin()
63 /// and addAsymmetryBin() methods. Use the optional parameter to
64 /// specify the confidence level in units of sigma to use for
65 /// calculating error bars. The nominal bin width specifies the
66 /// default used by addBin(), and is used to set the relative
67 /// normalization of bins with different widths.
68 
69  RooHist::RooHist(Double_t nominalBinWidth, Double_t nSigma, Double_t /*xErrorFrac*/, Double_t /*scaleFactor*/) :
70  TGraphAsymmErrors(), _nominalBinWidth(nominalBinWidth), _nSigma(nSigma), _rawEntries(-1)
71 {
72  initialize();
73 }
74 
75 
76 ////////////////////////////////////////////////////////////////////////////////
77 /// Create a histogram from the contents of the specified TH1 object
78 /// which may have fixed or variable bin widths. Error bars are
79 /// calculated using Poisson statistics. Prints a warning and rounds
80 /// any bins with non-integer contents. Use the optional parameter to
81 /// specify the confidence level in units of sigma to use for
82 /// calculating error bars. The nominal bin width specifies the
83 /// default used by addBin(), and is used to set the relative
84 /// normalization of bins with different widths. If not set, the
85 /// nominal bin width is calculated as range/nbins.
86 
87 RooHist::RooHist(const TH1 &data, Double_t nominalBinWidth, Double_t nSigma, RooAbsData::ErrorType etype, Double_t xErrorFrac,
88  Bool_t correctForBinWidth, Double_t scaleFactor) :
89  TGraphAsymmErrors(), _nominalBinWidth(nominalBinWidth), _nSigma(nSigma), _rawEntries(-1)
90 {
91  initialize();
92  // copy the input histogram's name and title
93  SetName(data.GetName());
94  SetTitle(data.GetTitle());
95  // calculate our nominal bin width if necessary
96  if(_nominalBinWidth == 0) {
97  const TAxis *axis= ((TH1&)data).GetXaxis();
98  if(axis->GetNbins() > 0) _nominalBinWidth= (axis->GetXmax() - axis->GetXmin())/axis->GetNbins();
99  }
100  setYAxisLabel(data.GetYaxis()->GetTitle());
101 
102  // initialize our contents from the input histogram's contents
103  Int_t nbin= data.GetNbinsX();
104  for(Int_t bin= 1; bin <= nbin; bin++) {
105  Axis_t x= data.GetBinCenter(bin);
106  Stat_t y= data.GetBinContent(bin);
107  Stat_t dy = data.GetBinError(bin) ;
108  if (etype==RooAbsData::Poisson) {
109  addBin(x,y,data.GetBinWidth(bin),xErrorFrac,scaleFactor);
110  } else if (etype==RooAbsData::SumW2) {
111  addBinWithError(x,y,dy,dy,data.GetBinWidth(bin),xErrorFrac,correctForBinWidth,scaleFactor);
112  } else {
113  addBinWithError(x,y,0,0,data.GetBinWidth(bin),xErrorFrac,correctForBinWidth,scaleFactor);
114  }
115  }
116  // add over/underflow bins to our event count
117  _entries+= data.GetBinContent(0) + data.GetBinContent(nbin+1);
118 }
119 
120 
121 
122 ////////////////////////////////////////////////////////////////////////////////
123 /// Create a histogram from the asymmetry between the specified TH1 objects
124 /// which may have fixed or variable bin widths, but which must both have
125 /// the same binning. The asymmetry is calculated as (1-2)/(1+2). Error bars are
126 /// calculated using Binomial statistics. Prints a warning and rounds
127 /// any bins with non-integer contents. Use the optional parameter to
128 /// specify the confidence level in units of sigma to use for
129 /// calculating error bars. The nominal bin width specifies the
130 /// default used by addAsymmetryBin(), and is used to set the relative
131 /// normalization of bins with different widths. If not set, the
132 /// nominal bin width is calculated as range/nbins.
133 
134 RooHist::RooHist(const TH1 &data1, const TH1 &data2, Double_t nominalBinWidth, Double_t nSigma,
135  RooAbsData::ErrorType etype, Double_t xErrorFrac, Bool_t efficiency, Double_t scaleFactor) :
136  TGraphAsymmErrors(), _nominalBinWidth(nominalBinWidth), _nSigma(nSigma), _rawEntries(-1)
137 {
138  initialize();
139  // copy the first input histogram's name and title
140  SetName(data1.GetName());
141  SetTitle(data1.GetTitle());
142  // calculate our nominal bin width if necessary
143  if(_nominalBinWidth == 0) {
144  const TAxis *axis= ((TH1&)data1).GetXaxis();
145  if(axis->GetNbins() > 0) _nominalBinWidth= (axis->GetXmax() - axis->GetXmin())/axis->GetNbins();
146  }
147 
148  if (!efficiency) {
149  setYAxisLabel(Form("Asymmetry (%s - %s)/(%s + %s)",
150  data1.GetName(),data2.GetName(),data1.GetName(),data2.GetName()));
151  } else {
152  setYAxisLabel(Form("Efficiency (%s)/(%s + %s)",
153  data1.GetName(),data1.GetName(),data2.GetName()));
154  }
155  // initialize our contents from the input histogram contents
156  Int_t nbin= data1.GetNbinsX();
157  if(data2.GetNbinsX() != nbin) {
158  coutE(InputArguments) << "RooHist::RooHist: histograms have different number of bins" << endl;
159  return;
160  }
161  for(Int_t bin= 1; bin <= nbin; bin++) {
162  Axis_t x= data1.GetBinCenter(bin);
163  if(fabs(data2.GetBinCenter(bin)-x)>1e-10) {
164  coutW(InputArguments) << "RooHist::RooHist: histograms have different centers for bin " << bin << endl;
165  }
166  Stat_t y1= data1.GetBinContent(bin);
167  Stat_t y2= data2.GetBinContent(bin);
168  if (!efficiency) {
169 
170  if (etype==RooAbsData::Poisson) {
171  addAsymmetryBin(x,roundBin(y1),roundBin(y2),data1.GetBinWidth(bin),xErrorFrac,scaleFactor);
172  } else if (etype==RooAbsData::SumW2) {
173  Stat_t dy1= data1.GetBinError(bin);
174  Stat_t dy2= data2.GetBinError(bin);
175  addAsymmetryBinWithError(x,y1,y2,dy1,dy2,data1.GetBinWidth(bin),xErrorFrac,scaleFactor);
176  } else {
177  addAsymmetryBinWithError(x,y1,y2,0,0,data1.GetBinWidth(bin),xErrorFrac,scaleFactor);
178  }
179 
180  } else {
181 
182  if (etype==RooAbsData::Poisson) {
183  addEfficiencyBin(x,roundBin(y1),roundBin(y2),data1.GetBinWidth(bin),xErrorFrac,scaleFactor);
184  } else if (etype==RooAbsData::SumW2) {
185  Stat_t dy1= data1.GetBinError(bin);
186  Stat_t dy2= data2.GetBinError(bin);
187  addEfficiencyBinWithError(x,y1,y2,dy1,dy2,data1.GetBinWidth(bin),xErrorFrac,scaleFactor);
188  } else {
189  addEfficiencyBinWithError(x,y1,y2,0,0,data1.GetBinWidth(bin),xErrorFrac,scaleFactor);
190  }
191 
192  }
193 
194  }
195  // we do not have a meaningful number of entries
196  _entries= -1;
197 }
198 
199 
200 
201 ////////////////////////////////////////////////////////////////////////////////
202 /// Create histogram as sum of two existing histograms. If Poisson errors are selected the histograms are
203 /// added and Poisson confidence intervals are calculated for the summed content. If wgt1 and wgt2 are not
204 /// 1 in this mode, a warning message is printed. If SumW2 errors are selected the histograms are added
205 /// and the histograms errors are added in quadrature, taking the weights into account.
206 
207 RooHist::RooHist(const RooHist& hist1, const RooHist& hist2, Double_t wgt1, Double_t wgt2,
208  RooAbsData::ErrorType etype, Double_t xErrorFrac) : _rawEntries(-1)
209 {
210  // Initialize the histogram
211  initialize() ;
212 
213  // Copy all non-content properties from hist1
214  SetName(hist1.GetName()) ;
215  SetTitle(hist1.GetTitle()) ;
216  _nominalBinWidth=hist1._nominalBinWidth ;
217  _nSigma=hist1._nSigma ;
218  setYAxisLabel(hist1.getYAxisLabel()) ;
219 
220  if (!hist1.hasIdenticalBinning(hist2)) {
221  coutE(InputArguments) << "RooHist::RooHist input histograms have incompatible binning, combined histogram will remain empty" << endl ;
222  return ;
223  }
224 
225  if (etype==RooAbsData::Poisson) {
226  // Add histograms with Poisson errors
227 
228  // Issue warning if weights are not 1
229  if (wgt1!=1.0 || wgt2 != 1.0) {
230  coutW(InputArguments) << "RooHist::RooHist: WARNING: Poisson errors of weighted sum of two histograms is not well defined! " << endl
231  << " Summed histogram bins will rounded to nearest integer for Poisson confidence interval calculation" << endl ;
232  }
233 
234  // Add histograms, calculate Poisson confidence interval on sum value
235  Int_t i,n=hist1.GetN() ;
236  for(i=0 ; i<n ; i++) {
237  Double_t x1,y1,x2,y2,dx1 ;
238  hist1.GetPoint(i,x1,y1) ;
239  dx1 = hist1.GetErrorX(i) ;
240  hist2.GetPoint(i,x2,y2) ;
241  addBin(x1,roundBin(wgt1*y1+wgt2*y2),2*dx1/xErrorFrac,xErrorFrac) ;
242  }
243 
244  } else {
245  // Add histograms with SumW2 errors
246 
247  // Add histograms, calculate combined sum-of-weights error
248  Int_t i,n=hist1.GetN() ;
249  for(i=0 ; i<n ; i++) {
250  Double_t x1,y1,x2,y2,dx1,dy1,dy2 ;
251  hist1.GetPoint(i,x1,y1) ;
252  dx1 = hist1.GetErrorX(i) ;
253  dy1 = hist1.GetErrorY(i) ;
254  dy2 = hist2.GetErrorY(i) ;
255  hist2.GetPoint(i,x2,y2) ;
256  Double_t dy = sqrt(wgt1*wgt1*dy1*dy1+wgt2*wgt2*dy2*dy2) ;
257  addBinWithError(x1,wgt1*y1+wgt2*y2,dy,dy,2*dx1/xErrorFrac,xErrorFrac) ;
258  }
259  }
260 
261 }
262 
263 
264 ////////////////////////////////////////////////////////////////////////////////
265 /// Create histogram from a pdf or function. Errors are computed based on the fit result provided.
266 ///
267 /// This signature is intended for unfolding/deconvolution scenarios,
268 /// where a pdf is constructed as "data minus background" and is thus
269 /// intended to be displayed as "data" (or at least data-like).
270 /// Usage of this signature is triggered by the draw style "P" in RooAbsReal::plotOn.
271 ///
272 /// More details.
273 /// \param[in] f The function to be plotted.
274 /// \param[in] x The variable on the x-axis
275 /// \param[in] xErrorFrac Size of the errror in x as a fraction of the bin width
276 /// \param[in] scaleFactor arbitrary scaling of the y-values
277 /// \param[in] normVars variables over which to normalize
278 RooHist::RooHist(const RooAbsReal &f, RooAbsRealLValue &x, Double_t xErrorFrac, Double_t scaleFactor, const RooArgSet *normVars, const RooFitResult* fr) :
279  TGraphAsymmErrors(), _nSigma(1), _rawEntries(-1)
280 {
281  // grab the function's name and title
282  TString name(f.GetName());
283  SetName(name.Data());
284  TString title(f.GetTitle());
285  SetTitle(title.Data());
286  // append " ( [<funit> ][/ <xunit> ])" to our y-axis label if necessary
287  if(0 != strlen(f.getUnit()) || 0 != strlen(x.getUnit())) {
288  title.Append(" ( ");
289  if(0 != strlen(f.getUnit())) {
290  title.Append(f.getUnit());
291  title.Append(" ");
292  }
293  if(0 != strlen(x.getUnit())) {
294  title.Append("/ ");
295  title.Append(x.getUnit());
296  title.Append(" ");
297  }
298  title.Append(")");
299  }
300  setYAxisLabel(title.Data());
301 
302  RooAbsFunc *funcPtr = nullptr;
303  RooAbsFunc *rawPtr = nullptr;
304  funcPtr= f.bindVars(x,normVars,kTRUE);
305 
306  // apply a scale factor if necessary
307  if(scaleFactor != 1) {
308  rawPtr= funcPtr;
309  funcPtr= new RooScaledFunc(*rawPtr,scaleFactor);
310  }
311 
312  // apply a scale factor if necessary
313  assert(funcPtr);
314 
315  // calculate the points to add to our curve
316  int xbins = x.numBins();
317  RooArgSet nset;
318  if(normVars) nset.add(*normVars);
319  for(int i=0; i<xbins; ++i){
320  double xval = x.getBinning().binCenter(i);
321  double xwidth = x.getBinning().binWidth(i);
322  Axis_t xval_ax = xval;
323  double yval = (*funcPtr)(&xval);
324  double yerr = sqrt(yval);
325  if(fr) yerr = f.getPropagatedError(*fr,nset);
326  addBinWithError(xval_ax,yval,yerr,yerr,xwidth,xErrorFrac,false,scaleFactor) ;
327  _entries += yval;
328  }
329  _nominalBinWidth = 1.;
330 
331  // cleanup
332  delete funcPtr;
333  if(rawPtr) delete rawPtr;
334 }
335 
336 
337 ////////////////////////////////////////////////////////////////////////////////
338 /// Perform common initialization for all constructors.
339 
340 void RooHist::initialize()
341 {
342  SetMarkerStyle(8);
343  _entries= 0;
344 }
345 
346 
347 ////////////////////////////////////////////////////////////////////////////////
348 /// Return the number of events of the dataset associated with this RooHist.
349 /// This is the number of events in the RooHist itself, unless a different
350 /// value was specified through setRawEntries()
351 
352 Double_t RooHist::getFitRangeNEvt() const
353 {
354  return (_rawEntries==-1 ? _entries : _rawEntries) ;
355 }
356 
357 
358 ////////////////////////////////////////////////////////////////////////////////
359 /// Calculate integral of histogram in given range
360 
361 Double_t RooHist::getFitRangeNEvt(Double_t xlo, Double_t xhi) const
362 {
363  Double_t sum(0) ;
364  for (int i=0 ; i<GetN() ; i++) {
365  Double_t x,y ;
366 
367  GetPoint(i,x,y) ;
368 
369  if (x>=xlo && x<=xhi) {
370  sum += y ;
371  }
372  }
373 
374  if (_rawEntries!=-1) {
375  coutW(Plotting) << "RooHist::getFitRangeNEvt() WARNING: The number of normalisation events associated to histogram " << GetName() << " is not equal to number of events in this histogram."
376  << "\n\t\t This is due a cut being applied while plotting the data. Automatic normalisation over a sub-range of a plot variable assumes"
377  << "\n\t\t that the effect of that cut is uniform across the plot, which may be an incorrect assumption. To obtain a correct normalisation, it needs to be passed explicitly:"
378  << "\n\t\t\t data->plotOn(frame01,CutRange(\"SB1\"));"
379  << "\n\t\t\t const double nData = data->sumEntries(\"\", \"SB1\"); //or the cut string such as sumEntries(\"x > 0.\");"
380  << "\n\t\t\t model.plotOn(frame01, RooFit::Normalization(nData, RooAbsReal::NumEvent), ProjectionRange(\"SB1\"));" << endl ;
381  sum *= _rawEntries / _entries ;
382  }
383 
384  return sum ;
385 }
386 
387 
388 
389 ////////////////////////////////////////////////////////////////////////////////
390 /// Return (average) bin width of this RooHist
391 
392 Double_t RooHist::getFitRangeBinW() const
393 {
394  return _nominalBinWidth ;
395 }
396 
397 
398 
399 ////////////////////////////////////////////////////////////////////////////////
400 /// Return the nearest positive integer to the input value
401 /// and print a warning if an adjustment is required.
402 
403 Int_t RooHist::roundBin(Double_t y)
404 {
405  if(y < 0) {
406  coutW(Plotting) << fName << "::roundBin: rounding negative bin contents to zero: " << y << endl;
407  return 0;
408  }
409  Int_t n= (Int_t)(y+0.5);
410  if(fabs(y-n)>1e-6) {
411  coutW(Plotting) << fName << "::roundBin: rounding non-integer bin contents: " << y << endl;
412  }
413  return n;
414 }
415 
416 
417 
418 ////////////////////////////////////////////////////////////////////////////////
419 /// Add a bin to this histogram with the specified integer bin contents
420 /// and using an error bar calculated with Poisson statistics. The bin width
421 /// is used to set the relative scale of bins with different widths.
422 
423 void RooHist::addBin(Axis_t binCenter, Double_t n, Double_t binWidth, Double_t xErrorFrac, Double_t scaleFactor)
424 {
425  if (n<0) {
426  coutW(Plotting) << "RooHist::addBin(" << GetName() << ") WARNING: negative entry set to zero when Poisson error bars are requested" << endl ;
427  }
428 
429  Double_t scale= 1;
430  if(binWidth > 0) {
431  scale= _nominalBinWidth/binWidth;
432  }
433  _entries+= n;
434  Int_t index= GetN();
435 
436  // calculate Poisson errors for this bin
437  Double_t ym,yp,dx(0.5*binWidth);
438 
439  if (fabs((double)((n-Int_t(n))>1e-5))) {
440  // need interpolation
441  Double_t ym1(0),yp1(0),ym2(0),yp2(0) ;
442  Int_t n1 = Int_t(n) ;
443  Int_t n2 = n1+1 ;
444  if(!RooHistError::instance().getPoissonInterval(n1,ym1,yp1,_nSigma) ||
445  !RooHistError::instance().getPoissonInterval(n2,ym2,yp2,_nSigma)) {
446  coutE(Plotting) << "RooHist::addBin: unable to add bin with " << n << " events" << endl;
447  }
448  ym = ym1 + (n-n1)*(ym2-ym1) ;
449  yp = yp1 + (n-n1)*(yp2-yp1) ;
450  coutW(Plotting) << "RooHist::addBin(" << GetName()
451  << ") WARNING: non-integer bin entry " << n << " with Poisson errors, interpolating between Poisson errors of adjacent integer" << endl ;
452  } else {
453  // integer case
454  if(!RooHistError::instance().getPoissonInterval(Int_t(n),ym,yp,_nSigma)) {
455  coutE(Plotting) << "RooHist::addBin: unable to add bin with " << n << " events" << endl;
456  return;
457  }
458  }
459 
460  SetPoint(index,binCenter,n*scale*scaleFactor);
461  SetPointError(index,dx*xErrorFrac,dx*xErrorFrac,scale*(n-ym)*scaleFactor,scale*(yp-n)*scaleFactor);
462  updateYAxisLimits(scale*yp);
463  updateYAxisLimits(scale*ym);
464 }
465 
466 
467 
468 ////////////////////////////////////////////////////////////////////////////////
469 /// Add a bin to this histogram with the specified bin contents
470 /// and error. The bin width is used to set the relative scale of
471 /// bins with different widths.
472 
473 void RooHist::addBinWithError(Axis_t binCenter, Double_t n, Double_t elow, Double_t ehigh, Double_t binWidth,
474  Double_t xErrorFrac, Bool_t correctForBinWidth, Double_t scaleFactor)
475 {
476  Double_t scale= 1;
477  if(binWidth > 0 && correctForBinWidth) {
478  scale= _nominalBinWidth/binWidth;
479  }
480  _entries+= n;
481  Int_t index= GetN();
482 
483  Double_t dx(0.5*binWidth) ;
484  SetPoint(index,binCenter,n*scale*scaleFactor);
485  SetPointError(index,dx*xErrorFrac,dx*xErrorFrac,elow*scale*scaleFactor,ehigh*scale*scaleFactor);
486  updateYAxisLimits(scale*(n-elow));
487  updateYAxisLimits(scale*(n+ehigh));
488 }
489 
490 
491 
492 
493 ////////////////////////////////////////////////////////////////////////////////
494 /// Add a bin to this histogram with the specified bin contents
495 /// and error. The bin width is used to set the relative scale of
496 /// bins with different widths.
497 
498 void RooHist::addBinWithXYError(Axis_t binCenter, Double_t n, Double_t exlow, Double_t exhigh, Double_t eylow, Double_t eyhigh,
499  Double_t scaleFactor)
500 {
501  _entries+= n;
502  Int_t index= GetN();
503 
504  SetPoint(index,binCenter,n*scaleFactor);
505  SetPointError(index,exlow,exhigh,eylow*scaleFactor,eyhigh*scaleFactor);
506  updateYAxisLimits(scaleFactor*(n-eylow));
507  updateYAxisLimits(scaleFactor*(n+eyhigh));
508 }
509 
510 
511 
512 
513 
514 ////////////////////////////////////////////////////////////////////////////////
515 /// Add a bin to this histogram with the value (n1-n2)/(n1+n2)
516 /// using an error bar calculated with Binomial statistics.
517 
518 void RooHist::addAsymmetryBin(Axis_t binCenter, Int_t n1, Int_t n2, Double_t binWidth, Double_t xErrorFrac, Double_t scaleFactor)
519 {
520  Double_t scale= 1;
521  if(binWidth > 0) scale= _nominalBinWidth/binWidth;
522  Int_t index= GetN();
523 
524  // calculate Binomial errors for this bin
525  Double_t ym,yp,dx(0.5*binWidth);
526  if(!RooHistError::instance().getBinomialIntervalAsym(n1,n2,ym,yp,_nSigma)) {
527  coutE(Plotting) << "RooHist::addAsymmetryBin: unable to calculate binomial error for bin with " << n1 << "," << n2 << " events" << endl;
528  return;
529  }
530 
531  Double_t a= (Double_t)(n1-n2)/(n1+n2);
532  SetPoint(index,binCenter,a*scaleFactor);
533  SetPointError(index,dx*xErrorFrac,dx*xErrorFrac,(a-ym)*scaleFactor,(yp-a)*scaleFactor);
534  updateYAxisLimits(scale*yp);
535  updateYAxisLimits(scale*ym);
536 }
537 
538 
539 
540 ////////////////////////////////////////////////////////////////////////////////
541 /// Add a bin to this histogram with the value (n1-n2)/(n1+n2)
542 /// using an error bar calculated with Binomial statistics.
543 
544 void RooHist::addAsymmetryBinWithError(Axis_t binCenter, Double_t n1, Double_t n2, Double_t en1, Double_t en2, Double_t binWidth, Double_t xErrorFrac, Double_t scaleFactor)
545 {
546  Double_t scale= 1;
547  if(binWidth > 0) scale= _nominalBinWidth/binWidth;
548  Int_t index= GetN();
549 
550  // calculate Binomial errors for this bin
551  Double_t ym,yp,dx(0.5*binWidth);
552  Double_t a= (Double_t)(n1-n2)/(n1+n2);
553 
554  Double_t error = 2*sqrt( pow(en1,2)*pow(n2,2) + pow(en2,2)*pow(n1,2) ) / pow(n1+n2,2) ;
555  ym=a-error ;
556  yp=a+error ;
557 
558  SetPoint(index,binCenter,a*scaleFactor);
559  SetPointError(index,dx*xErrorFrac,dx*xErrorFrac,(a-ym)*scaleFactor,(yp-a)*scaleFactor);
560  updateYAxisLimits(scale*yp);
561  updateYAxisLimits(scale*ym);
562 }
563 
564 
565 
566 ////////////////////////////////////////////////////////////////////////////////
567 /// Add a bin to this histogram with the value n1/(n1+n2)
568 /// using an error bar calculated with Binomial statistics.
569 
570 void RooHist::addEfficiencyBin(Axis_t binCenter, Int_t n1, Int_t n2, Double_t binWidth, Double_t xErrorFrac, Double_t scaleFactor)
571 {
572  Double_t scale= 1;
573  if(binWidth > 0) scale= _nominalBinWidth/binWidth;
574  Int_t index= GetN();
575 
576  Double_t a= (Double_t)(n1)/(n1+n2);
577 
578  // calculate Binomial errors for this bin
579  Double_t ym,yp,dx(0.5*binWidth);
580  if(!RooHistError::instance().getBinomialIntervalEff(n1,n2,ym,yp,_nSigma)) {
581  coutE(Plotting) << "RooHist::addEfficiencyBin: unable to calculate binomial error for bin with " << n1 << "," << n2 << " events" << endl;
582  return;
583  }
584 
585  SetPoint(index,binCenter,a*scaleFactor);
586  SetPointError(index,dx*xErrorFrac,dx*xErrorFrac,(a-ym)*scaleFactor,(yp-a)*scaleFactor);
587  updateYAxisLimits(scale*yp);
588  updateYAxisLimits(scale*ym);
589 }
590 
591 
592 
593 ////////////////////////////////////////////////////////////////////////////////
594 /// Add a bin to this histogram with the value n1/(n1+n2)
595 /// using an error bar calculated with Binomial statistics.
596 
597 void RooHist::addEfficiencyBinWithError(Axis_t binCenter, Double_t n1, Double_t n2, Double_t en1, Double_t en2, Double_t binWidth, Double_t xErrorFrac, Double_t scaleFactor)
598 {
599  Double_t scale= 1;
600  if(binWidth > 0) scale= _nominalBinWidth/binWidth;
601  Int_t index= GetN();
602 
603  Double_t a= (Double_t)(n1)/(n1+n2);
604 
605  Double_t error = sqrt( pow(en1,2)*pow(n2,2) + pow(en2,2)*pow(n1,2) ) / pow(n1+n2,2) ;
606 
607  // calculate Binomial errors for this bin
608  Double_t ym,yp,dx(0.5*binWidth);
609  ym=a-error ;
610  yp=a+error ;
611 
612 
613  SetPoint(index,binCenter,a*scaleFactor);
614  SetPointError(index,dx*xErrorFrac,dx*xErrorFrac,(a-ym)*scaleFactor,(yp-a)*scaleFactor);
615  updateYAxisLimits(scale*yp);
616  updateYAxisLimits(scale*ym);
617 }
618 
619 
620 
621 ////////////////////////////////////////////////////////////////////////////////
622 /// Destructor
623 
624 RooHist::~RooHist()
625 {
626 }
627 
628 
629 
630 ////////////////////////////////////////////////////////////////////////////////
631 /// Return kTRUE if binning of this RooHist is identical to that of 'other'
632 
633 Bool_t RooHist::hasIdenticalBinning(const RooHist& other) const
634 {
635  // First check if number of bins is the same
636  if (GetN() != other.GetN()) {
637  return kFALSE ;
638  }
639 
640  // Next require that all bin centers are the same
641  Int_t i ;
642  for (i=0 ; i<GetN() ; i++) {
643  Double_t x1,x2,y1,y2 ;
644 
645  GetPoint(i,x1,y1) ;
646  other.GetPoint(i,x2,y2) ;
647 
648  if (fabs(x1-x2)>1e-10) {
649  return kFALSE ;
650  }
651 
652  }
653 
654  return kTRUE ;
655 }
656 
657 
658 
659 ////////////////////////////////////////////////////////////////////////////////
660 /// Return kTRUE if contents of this RooHist is identical within given
661 /// relative tolerance to that of 'other'
662 
663 Bool_t RooHist::isIdentical(const RooHist& other, Double_t tol) const
664 {
665  // Make temporary TH1s output of RooHists to perform Kolmogorov test
666  TH1::AddDirectory(kFALSE) ;
667  TH1F h_self("h_self","h_self",GetN(),0,1) ;
668  TH1F h_other("h_other","h_other",GetN(),0,1) ;
669  TH1::AddDirectory(kTRUE) ;
670 
671  for (Int_t i=0 ; i<GetN() ; i++) {
672  h_self.SetBinContent(i+1,GetY()[i]) ;
673  h_other.SetBinContent(i+1,other.GetY()[i]) ;
674  }
675 
676  Double_t M = h_self.KolmogorovTest(&h_other,"M") ;
677  if (M>tol) {
678  Double_t kprob = h_self.KolmogorovTest(&h_other) ;
679  cout << "RooHist::isIdentical() tolerance exceeded M=" << M << " (tol=" << tol << "), corresponding prob = " << kprob << endl ;
680  return kFALSE ;
681  }
682 
683  return kTRUE ;
684 }
685 
686 
687 
688 ////////////////////////////////////////////////////////////////////////////////
689 /// Print info about this histogram to the specified output stream.
690 ///
691 /// Standard: number of entries
692 /// Shape: error CL and maximum value
693 /// Verbose: print our bin contents and errors
694 
695 void RooHist::printMultiline(ostream& os, Int_t contents, Bool_t verbose, TString indent) const
696 {
697  RooPlotable::printMultiline(os,contents,verbose,indent);
698  os << indent << "--- RooHist ---" << endl;
699  Int_t n= GetN();
700  os << indent << " Contains " << n << " bins" << endl;
701  if(verbose) {
702  os << indent << " Errors calculated at" << _nSigma << "-sigma CL" << endl;
703  os << indent << " Bin Contents:" << endl;
704  for(Int_t i= 0; i < n; i++) {
705  os << indent << setw(3) << i << ") x= " << fX[i];
706  if(fEXhigh[i] > 0 || fEXlow[i] > 0) {
707  os << " +" << fEXhigh[i] << " -" << fEXlow[i];
708  }
709  os << " , y = " << fY[i] << " +" << fEYhigh[i] << " -" << fEYlow[i] << endl;
710  }
711  }
712 }
713 
714 
715 
716 ////////////////////////////////////////////////////////////////////////////////
717 /// Print name of RooHist
718 
719 void RooHist::printName(ostream& os) const
720 {
721  os << GetName() ;
722 }
723 
724 
725 
726 ////////////////////////////////////////////////////////////////////////////////
727 /// Print title of RooHist
728 
729 void RooHist::printTitle(ostream& os) const
730 {
731  os << GetTitle() ;
732 }
733 
734 
735 
736 ////////////////////////////////////////////////////////////////////////////////
737 /// Print class name of RooHist
738 
739 void RooHist::printClassName(ostream& os) const
740 {
741  os << IsA()->GetName() ;
742 }
743 
744 
745 
746 ////////////////////////////////////////////////////////////////////////////////
747 /// Create and return RooHist containing residuals w.r.t to given curve.
748 /// If normalize is true, the residuals are normalized by the histogram
749 /// errors creating a RooHist with pull values
750 
751 RooHist* RooHist::makeResidHist(const RooCurve& curve, bool normalize, bool useAverage) const
752 {
753 
754  // Copy all non-content properties from hist1
755  RooHist* hist = new RooHist(_nominalBinWidth) ;
756  if (normalize) {
757  hist->SetName(Form("pull_%s_%s",GetName(),curve.GetName())) ;
758  hist->SetTitle(Form("Pull of %s and %s",GetTitle(),curve.GetTitle())) ;
759  } else {
760  hist->SetName(Form("resid_%s_%s",GetName(),curve.GetName())) ;
761  hist->SetTitle(Form("Residual of %s and %s",GetTitle(),curve.GetTitle())) ;
762  }
763 
764  // Determine range of curve
765  Double_t xstart,xstop,y ;
766  curve.GetPoint(0,xstart,y) ;
767  curve.GetPoint(curve.GetN()-1,xstop,y) ;
768 
769  // Add histograms, calculate Poisson confidence interval on sum value
770  for(Int_t i=0 ; i<GetN() ; i++) {
771  Double_t x,point;
772  GetPoint(i,x,point) ;
773 
774  // Only calculate pull for bins inside curve range
775  if (x<xstart || x>xstop) continue ;
776 
777  Double_t yy ;
778  if (useAverage) {
779  Double_t exl = GetErrorXlow(i);
780  Double_t exh = GetErrorXhigh(i) ;
781  if (exl<=0 ) exl = GetErrorX(i);
782  if (exh<=0 ) exh = GetErrorX(i);
783  if (exl<=0 ) exl = 0.5*getNominalBinWidth();
784  if (exh<=0 ) exh = 0.5*getNominalBinWidth();
785  yy = point - curve.average(x-exl,x+exh) ;
786  } else {
787  yy = point - curve.interpolate(x) ;
788  }
789 
790  Double_t dyl = GetErrorYlow(i) ;
791  Double_t dyh = GetErrorYhigh(i) ;
792  if (normalize) {
793  Double_t norm = (yy>0?dyl:dyh);
794  if (norm==0.) {
795  coutW(Plotting) << "RooHist::makeResisHist(" << GetName() << ") WARNING: point " << i << " has zero error, setting residual to zero" << endl ;
796  yy=0 ;
797  dyh=0 ;
798  dyl=0 ;
799  } else {
800  yy /= norm;
801  dyh /= norm;
802  dyl /= norm;
803  }
804  }
805  hist->addBinWithError(x,yy,dyl,dyh);
806  }
807  return hist ;
808 }