Source code for MPF.errorBands

import ROOT

from . import pyrootHelpers as PH
from .arrow import Arrow
from .commonHelpers.logger import logger
logger = logger.getChild(__name__)

[docs]class AE(ROOT.TGraphAsymmErrors): def __init__(self, histo=None, relErr=False, customDrawString=None): if relErr and histo is not None: super(AE, self).__init__(PH.getRelErrHist(histo)) elif histo is not None: super(AE, self).__init__(histo) else: super(AE, self).__init__() self.customDrawString = customDrawString self.zIndex = 5 self.data = False self.arrows = [] self.xTitle = None # def firstDraw(self): # self.draw(drawstring='a')
[docs] def draw(self, drawString='', **kwargs): if self.customDrawString is not None: self.Draw(self.customDrawString) elif self.data: self.SetMarkerStyle(20) self.Draw(drawString + "PE0") else: self.Draw(drawString + "2") if self.arrows: for arrow in self.arrows: arrow.draw()
[docs] def truncateErrors(self): for i in range(1, self.GetN()): self.SetPointError(i, 0, 0, 0, 0)
[docs] def addRatioArrows(self, up, low): """Add a list of arrows to a ratio graph. The ratio thresholds for which an arrow is drawn are given by up, low""" self.arrows = [] x = ROOT.Double() y = ROOT.Double() for i in range(1, self.GetN()): self.GetPoint(i, x, y) if y > up: logger.debug("Point number {} at {} with ratio {} will get an up arrow".format(i, x, y)) self.arrows.append(self.makeArrow(x, up, low, True)) if y < low: logger.debug("Point number {} at {} with ratio {} will get a down arrow".format(i, x, y)) self.arrows.append(self.makeArrow(x, up, low, False))
[docs] @staticmethod def makeArrow(bincenter, up, low, pointUp=True): length = 0.2*(up-low) size = 0.015 if pointUp: arrow = Arrow(bincenter, up - length, bincenter, up - 0.2*length, 0.01, "|>") else: arrow = Arrow(bincenter, low + length, bincenter, low + 0.2*length, 0.01, "|>") arrow.SetLineWidth(2) arrow.SetLineColor(ROOT.kRed) arrow.SetFillColor(ROOT.kRed) return arrow
[docs]def getPoissonRatio(num, den, ignoreDenErrors=True, ignoreNumErrors=False): """Returns a ratio graph of 2 independend histograms. For the error calculation the Yield per bin is assumed to be the mean of a poisson distribution (histogram error is ignored). Optional keyword arguments: ignoreDenErrors: Ignore the denominator for error calculation (default True) ignoreNumErrors: Ignore the numerator for error calculation (default False) """ if ignoreNumErrors: raise NotImplementedError("ignoring the numerator for errors is not implemented yet") if not ignoreDenErrors: raise NotImplementedError("Considering the denominator for errros is not implemented yet") ae = AE() ae.SetName(next(PH.tempNames)) for i in range(1, num.GetNbinsX()+1): center = num.GetBinCenter(i) width = num.GetBinWidth(i)/2.0 yNum = num.GetBinContent(i) yDen = den.GetBinContent(i) if yNum <= 0.: logger.debug("Numerator number {} is 0 or negative ({}) for bin at {} - ignoring this bin".format(i, yNum, center)) continue try: ratio = num.GetBinContent(i)/den.GetBinContent(i) eyHigh = (PH.calcPoissonCLUpper(0.68, yNum))/yDen-ratio eyLow = ratio - (PH.calcPoissonCLLower(0.68, yNum))/yDen pointIndex = ae.GetN() ae.SetPoint(pointIndex, center, ratio) ae.SetPointError(pointIndex, width, width, eyLow, eyHigh) except ZeroDivisionError: logger.debug("Denominator number {} is 0 for bin at {} - ignoring this bin (Numerator: {})".format(i, center, yNum)) pass logger.debug("Created ratio graph with {} points".format(ae.GetN())) return ae