69 RooHist::RooHist(Double_t nominalBinWidth, Double_t nSigma, Double_t , Double_t ) :
70 TGraphAsymmErrors(), _nominalBinWidth(nominalBinWidth), _nSigma(nSigma), _rawEntries(-1)
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)
93 SetName(data.GetName());
94 SetTitle(data.GetTitle());
96 if(_nominalBinWidth == 0) {
97 const TAxis *axis= ((TH1&)data).GetXaxis();
98 if(axis->GetNbins() > 0) _nominalBinWidth= (axis->GetXmax() - axis->GetXmin())/axis->GetNbins();
100 setYAxisLabel(data.GetYaxis()->GetTitle());
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);
113 addBinWithError(x,y,0,0,data.GetBinWidth(bin),xErrorFrac,correctForBinWidth,scaleFactor);
117 _entries+= data.GetBinContent(0) + data.GetBinContent(nbin+1);
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)
140 SetName(data1.GetName());
141 SetTitle(data1.GetTitle());
143 if(_nominalBinWidth == 0) {
144 const TAxis *axis= ((TH1&)data1).GetXaxis();
145 if(axis->GetNbins() > 0) _nominalBinWidth= (axis->GetXmax() - axis->GetXmin())/axis->GetNbins();
149 setYAxisLabel(Form(
"Asymmetry (%s - %s)/(%s + %s)",
150 data1.GetName(),data2.GetName(),data1.GetName(),data2.GetName()));
152 setYAxisLabel(Form(
"Efficiency (%s)/(%s + %s)",
153 data1.GetName(),data1.GetName(),data2.GetName()));
156 Int_t nbin= data1.GetNbinsX();
157 if(data2.GetNbinsX() != nbin) {
158 coutE(InputArguments) <<
"RooHist::RooHist: histograms have different number of bins" << endl;
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;
166 Stat_t y1= data1.GetBinContent(bin);
167 Stat_t y2= data2.GetBinContent(bin);
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);
177 addAsymmetryBinWithError(x,y1,y2,0,0,data1.GetBinWidth(bin),xErrorFrac,scaleFactor);
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);
189 addEfficiencyBinWithError(x,y1,y2,0,0,data1.GetBinWidth(bin),xErrorFrac,scaleFactor);
207 RooHist::RooHist(
const RooHist& hist1,
const RooHist& hist2, Double_t wgt1, Double_t wgt2,
208 RooAbsData::ErrorType etype, Double_t xErrorFrac) : _rawEntries(-1)
214 SetName(hist1.GetName()) ;
215 SetTitle(hist1.GetTitle()) ;
216 _nominalBinWidth=hist1._nominalBinWidth ;
217 _nSigma=hist1._nSigma ;
218 setYAxisLabel(hist1.getYAxisLabel()) ;
220 if (!hist1.hasIdenticalBinning(hist2)) {
221 coutE(InputArguments) <<
"RooHist::RooHist input histograms have incompatible binning, combined histogram will remain empty" << endl ;
225 if (etype==RooAbsData::Poisson) {
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 ;
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) ;
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) ;
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)
282 TString name(f.GetName());
283 SetName(name.Data());
284 TString title(f.GetTitle());
285 SetTitle(title.Data());
287 if(0 != strlen(f.getUnit()) || 0 != strlen(x.getUnit())) {
289 if(0 != strlen(f.getUnit())) {
290 title.Append(f.getUnit());
293 if(0 != strlen(x.getUnit())) {
295 title.Append(x.getUnit());
300 setYAxisLabel(title.Data());
302 RooAbsFunc *funcPtr =
nullptr;
303 RooAbsFunc *rawPtr =
nullptr;
304 funcPtr= f.bindVars(x,normVars,kTRUE);
307 if(scaleFactor != 1) {
309 funcPtr=
new RooScaledFunc(*rawPtr,scaleFactor);
316 int xbins = x.numBins();
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) ;
329 _nominalBinWidth = 1.;
333 if(rawPtr)
delete rawPtr;
340 void RooHist::initialize()
352 Double_t RooHist::getFitRangeNEvt()
const
354 return (_rawEntries==-1 ? _entries : _rawEntries) ;
361 Double_t RooHist::getFitRangeNEvt(Double_t xlo, Double_t xhi)
const
364 for (
int i=0 ; i<GetN() ; i++) {
369 if (x>=xlo && x<=xhi) {
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 ;
392 Double_t RooHist::getFitRangeBinW()
const
394 return _nominalBinWidth ;
403 Int_t RooHist::roundBin(Double_t y)
406 coutW(Plotting) << fName <<
"::roundBin: rounding negative bin contents to zero: " << y << endl;
409 Int_t n= (Int_t)(y+0.5);
411 coutW(Plotting) << fName <<
"::roundBin: rounding non-integer bin contents: " << y << endl;
423 void RooHist::addBin(Axis_t binCenter, Double_t n, Double_t binWidth, Double_t xErrorFrac, Double_t scaleFactor)
426 coutW(Plotting) <<
"RooHist::addBin(" << GetName() <<
") WARNING: negative entry set to zero when Poisson error bars are requested" << endl ;
431 scale= _nominalBinWidth/binWidth;
437 Double_t ym,yp,dx(0.5*binWidth);
439 if (fabs((
double)((n-Int_t(n))>1e-5))) {
441 Double_t ym1(0),yp1(0),ym2(0),yp2(0) ;
442 Int_t n1 = Int_t(n) ;
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;
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 ;
454 if(!RooHistError::instance().getPoissonInterval(Int_t(n),ym,yp,_nSigma)) {
455 coutE(Plotting) <<
"RooHist::addBin: unable to add bin with " << n <<
" events" << endl;
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);
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)
477 if(binWidth > 0 && correctForBinWidth) {
478 scale= _nominalBinWidth/binWidth;
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));
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)
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));
518 void RooHist::addAsymmetryBin(Axis_t binCenter, Int_t n1, Int_t n2, Double_t binWidth, Double_t xErrorFrac, Double_t scaleFactor)
521 if(binWidth > 0) scale= _nominalBinWidth/binWidth;
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;
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);
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)
547 if(binWidth > 0) scale= _nominalBinWidth/binWidth;
551 Double_t ym,yp,dx(0.5*binWidth);
552 Double_t a= (Double_t)(n1-n2)/(n1+n2);
554 Double_t error = 2*sqrt( pow(en1,2)*pow(n2,2) + pow(en2,2)*pow(n1,2) ) / pow(n1+n2,2) ;
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);
570 void RooHist::addEfficiencyBin(Axis_t binCenter, Int_t n1, Int_t n2, Double_t binWidth, Double_t xErrorFrac, Double_t scaleFactor)
573 if(binWidth > 0) scale= _nominalBinWidth/binWidth;
576 Double_t a= (Double_t)(n1)/(n1+n2);
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;
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);
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)
600 if(binWidth > 0) scale= _nominalBinWidth/binWidth;
603 Double_t a= (Double_t)(n1)/(n1+n2);
605 Double_t error = sqrt( pow(en1,2)*pow(n2,2) + pow(en2,2)*pow(n1,2) ) / pow(n1+n2,2) ;
608 Double_t ym,yp,dx(0.5*binWidth);
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);
633 Bool_t RooHist::hasIdenticalBinning(
const RooHist& other)
const
636 if (GetN() != other.GetN()) {
642 for (i=0 ; i<GetN() ; i++) {
643 Double_t x1,x2,y1,y2 ;
646 other.GetPoint(i,x2,y2) ;
648 if (fabs(x1-x2)>1e-10) {
663 Bool_t RooHist::isIdentical(
const RooHist& other, Double_t tol)
const
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) ;
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]) ;
676 Double_t M = h_self.KolmogorovTest(&h_other,
"M") ;
678 Double_t kprob = h_self.KolmogorovTest(&h_other) ;
679 cout <<
"RooHist::isIdentical() tolerance exceeded M=" << M <<
" (tol=" << tol <<
"), corresponding prob = " << kprob << endl ;
695 void RooHist::printMultiline(ostream& os, Int_t contents, Bool_t verbose, TString indent)
const
697 RooPlotable::printMultiline(os,contents,verbose,indent);
698 os << indent <<
"--- RooHist ---" << endl;
700 os << indent <<
" Contains " << n <<
" bins" << endl;
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];
709 os <<
" , y = " << fY[i] <<
" +" << fEYhigh[i] <<
" -" << fEYlow[i] << endl;
719 void RooHist::printName(ostream& os)
const
729 void RooHist::printTitle(ostream& os)
const
739 void RooHist::printClassName(ostream& os)
const
741 os << IsA()->GetName() ;
751 RooHist* RooHist::makeResidHist(
const RooCurve& curve,
bool normalize,
bool useAverage)
const
755 RooHist* hist =
new RooHist(_nominalBinWidth) ;
757 hist->SetName(Form(
"pull_%s_%s",GetName(),curve.GetName())) ;
758 hist->SetTitle(Form(
"Pull of %s and %s",GetTitle(),curve.GetTitle())) ;
760 hist->SetName(Form(
"resid_%s_%s",GetName(),curve.GetName())) ;
761 hist->SetTitle(Form(
"Residual of %s and %s",GetTitle(),curve.GetTitle())) ;
765 Double_t xstart,xstop,y ;
766 curve.GetPoint(0,xstart,y) ;
767 curve.GetPoint(curve.GetN()-1,xstop,y) ;
770 for(Int_t i=0 ; i<GetN() ; i++) {
772 GetPoint(i,x,point) ;
775 if (x<xstart || x>xstop) continue ;
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) ;
787 yy = point - curve.interpolate(x) ;
790 Double_t dyl = GetErrorYlow(i) ;
791 Double_t dyh = GetErrorYhigh(i) ;
793 Double_t norm = (yy>0?dyl:dyh);
795 coutW(Plotting) <<
"RooHist::makeResisHist(" << GetName() <<
") WARNING: point " << i <<
" has zero error, setting residual to zero" << endl ;
805 hist->addBinWithError(x,yy,dyl,dyh);