def cache_values(self):
     input_file = r.TFile.Open(self.filename)
     histogram = input_file.Get(self.histoname)
     integral, error = None, None
     ptmin, ptmax = self.ptmin, self.ptmax
     one_dim = histogram.Class().GetName().startswith('TH1')
     if one_dim:
         integral, error = ru.integralAndError(histogram)
     else:
         pt_axis = histogram.GetXaxis()
         if not any(s in pt_axis.GetTitle() for s in ['pt', 'p_T', 'p_{T']):
             raise RuntimeError("expecting pt axis, but got '%s' from %s" %
                                (pt_axis.GetTitle(), histogram.GetName()))
         first_pt_bin = pt_axis.FindFixBin(ptmin) if ptmin else 0
         last_pt_bin = pt_axis.FindFixBin(ptmax) if ptmax else -1
         first_m_bin = 0
         last_m_bin = -1
         error = r.Double(0.0)
         integral = histogram.IntegralAndError(first_pt_bin, last_pt_bin,
                                               first_m_bin, last_m_bin,
                                               error)
         error = float(error)
     self.yields[self.keycache] = integral
     self.errors[self.keycache] = error
     input_file.Close()
Example #2
0
def buildTotBackgroundHisto(histoFakeBkg=None, histosSimBkgs={}) :
    hTemplate = histoFakeBkg
    if not hTemplate :
        hTemplate = first(histosSimBkgs)
        print "warning, cannot use fake as template; histo name will be wrong, based on %s"%hTemplate.GetName()
    totBkg = hTemplate.Clone(hTemplate.GetName().replace('_fake','_totbkg'))
    totBkg.Reset()
    if not totBkg.GetSumw2N() : totBkg.Sumw2()
    allBackgrounds = dict((group, histo) for group, histo in [('fake',histoFakeBkg)]+[(g,h) for g,h in histosSimBkgs.iteritems()])
    for group, histo in allBackgrounds.iteritems() :
        if histo :
            totBkg.Add(histo)
            integral, error = integralAndError(histo)
            print "adding %.3f +/- %.3f  : %s (%s)" % (integral, error, group, histo.GetName())
        else : print "buildStatisticalErrorBand: missing %s"%group
    integral, error = integralAndError(totBkg)
    print "totBkg %.3f +/- %.3f  : %s" % (integral, error, totBkg.GetName())
    return totBkg
Example #3
0
def buildTotBackgroundHisto(histoFakeBkg=None, histosSimBkgs={}):
    hTemplate = histoFakeBkg
    if not hTemplate:
        hTemplate = first(histosSimBkgs)
        print "warning, cannot use fake as template; histo name will be wrong, based on %s" % hTemplate.GetName(
        )
    totBkg = hTemplate.Clone(hTemplate.GetName().replace('_fake', '_totbkg'))
    totBkg.Reset()
    if not totBkg.GetSumw2N(): totBkg.Sumw2()
    allBackgrounds = dict((group, histo)
                          for group, histo in [('fake', histoFakeBkg)] +
                          [(g, h) for g, h in histosSimBkgs.iteritems()])
    for group, histo in allBackgrounds.iteritems():
        if histo:
            totBkg.Add(histo)
            integral, error = integralAndError(histo)
            print "adding %.3f +/- %.3f  : %s (%s)" % (integral, error, group,
                                                       histo.GetName())
        else:
            print "buildStatisticalErrorBand: missing %s" % group
    integral, error = integralAndError(totBkg)
    print "totBkg %.3f +/- %.3f  : %s" % (integral, error, totBkg.GetName())
    return totBkg
 def cache_values(self):
     input_file = r.TFile.Open(self.filename)
     histogram = input_file.Get(self.histoname)
     integral, error = None, None
     ptmin, ptmax = self.ptmin, self.ptmax
     one_dim = histogram.Class().GetName().startswith('TH1')
     if one_dim:
         integral, error = ru.integralAndError(histogram)
     else:
         pt_axis = histogram.GetXaxis()
         if not any(s in pt_axis.GetTitle() for s in ['pt', 'p_T', 'p_{T']):
             raise RuntimeError("expecting pt axis, but got '%s' from %s"%(pt_axis.GetTitle(), histogram.GetName()))
         first_pt_bin = pt_axis.FindFixBin(ptmin) if ptmin else 0
         last_pt_bin = pt_axis.FindFixBin(ptmax) if ptmax else -1
         first_m_bin = 0
         last_m_bin = -1
         error = r.Double(0.0)
         integral = histogram.IntegralAndError(first_pt_bin, last_pt_bin, first_m_bin, last_m_bin, error)
         error = float(error)
     self.yields[self.keycache] = integral
     self.errors[self.keycache] = error
     input_file.Close()
Example #5
0
def plotHistos(histoData=None, histoSignal=None, histoTotBkg=None, histosBkg={},
               statErrBand=None, systErrBand=None, # these are TGraphAsymmErrors
               canvasName='canvas', outdir='./', options=None,
               stack_order=[],
               topLabel='',
               drawStatErr=False, drawSystErr=False,
               drawYieldAndError=False, printYieldSummary=False) :
    "Note: blinding can be required for only a subrange of the histo, so it is taken care of when filling"
    verbose = options.verbose
    formatAuxMaterial = options.format_aux
    setAtlasStyle()
    padMaster = histoData
    if verbose : print "plotting ",padMaster.GetName(),' (',padMaster.GetEntries(),' entries)'
    can = r.TCanvas(canvasName, padMaster.GetTitle(), 800, 800)
    botPad, topPad = buildBotTopPads(can, squeezeMargins=False)
    can.cd()
    topPad.Draw()
    # draw top
    topPad.cd()
    topPad._hists = [padMaster]
    if formatAuxMaterial:
        for ax in [padMaster.GetXaxis(), padMaster.GetYaxis()]:
            ax.SetTitle(prettify(ax.GetTitle()))
    padMaster.Draw('axis')
    topPad.Update() # necessary to fool root's dumb object ownership of the stack
    stack = r.THStack('stack_'+padMaster.GetName(), '')
    r.SetOwnership(stack, False)
    topPad._hists.append(stack)
    leg = topRightLegend(can,
                         0.300 if formatAuxMaterial else 0.225,
                         0.400 if formatAuxMaterial else 0.325,
                         shiftX=-0.1 if formatAuxMaterial else 0.0,
                         shiftY=-0.1 if formatAuxMaterial else 0.0)
    topPad._leg = leg
    leg.SetBorderSize(0)
    leg.SetTextFont(padMaster.GetTitleFont())
    leg._reversedEntries = []
    def integralWou(h):
        "Integral with underflow and overflow"
        return h.Integral(0, h.GetNbinsX()+1)
    for group, histo in sortedAs(histosBkg, stack_order) :
        histo.SetFillColor(getGroupColor(group))
        histo.SetLineWidth(2)
        histo.SetLineColor(r.kBlack)
        stack.Add(histo)
        topPad._hists.append(histo)
        leg._reversedEntries.append((histo,
                                     prettify(group) if formatAuxMaterial else
                                     "{0}: {1:.2f}".format(group, integralWou(histo)), 'F'))
    if not formatAuxMaterial:
        leg._reversedEntries.append((dummyHisto(),
                                     "{0}, {1:.2f}".format('bkg', sum([integralWou(h) for h in stack.GetHists()])), 'l'))
    if statErrBand and drawStatErr :
        statErrBand.SetFillStyle(3006)
        leg._reversedEntries.append((statErrBand, 'stat', 'f'))
    if systErrBand and drawSystErr :
        systErrBand.SetFillStyle(3007)
        leg._reversedEntries.append((systErrBand, 'syst', 'f'))
    leg._reversedEntries.append((histoData,
                                 "Data {0}".format(prettify(topLabel)) if formatAuxMaterial else
                                 "{0}, {1:.2f}".format('data', integralWou(histoData)), 'p'))
    for h, g, o in leg._reversedEntries[::-1] : leg.AddEntry(h, g, o) # stack goes b-t, legend goes t-b
    stack.Draw('hist same')
    histoData.SetMarkerStyle(r.kFullCircle)
    histoData.SetLineWidth(2)
    dataGraph = graphWithPoissonError(histoData)
    dataGraph.Draw('same p')
    isRightSignal = False
    if histoSignal:
        histoSignal.SetFillStyle(0)
        histoSignal.SetFillColor(0)
        histoSignal.SetLineColor(getGroupColor('signal'))
        histoSignal.SetLineWidth(3)
        isRightSignal = (all(s in histoSignal.GetName() for s in ['signaltaumu', 'sr_mue']) or
                         all(s in histoSignal.GetName() for s in ['signaltaue', 'sr_emu']))
        if isRightSignal: histoSignal.Draw('histo same')
    if statErrBand and drawStatErr :
        statErrBand.SetFillStyle(3006)
        statErrBand.Draw('E2 same')
        leg.AddEntry(statErrBand, 'stat', 'f')
    if systErrBand and drawSystErr :
        systErrBand.SetFillStyle(3007)
        systErrBand.Draw('E2 same')
        leg.AddEntry(systErrBand, 'syst', 'f')
    totErrBand = systUtils.addErrorBandsInQuadrature(statErrBand, systErrBand)
    if totErrBand :
        totErrBand.Draw('E2 same')
        totErrBand.SetFillStyle(3005)
        leg.AddEntry(totErrBand, 'stat+syst', 'f')
        if printYieldSummary:
            print_total_error = False
            print ("{}:".format(topLabel if topLabel else dataGraph.GetName())+

                   (" expected {:.2f}^{{+{:.2f}}}_{{{:.2f}}}".format(totErrBand.GetY()[0],
                                                                    totErrBand.GetErrorYhigh(0),
                                                                    totErrBand.GetErrorYlow(0))
                    if print_total_error else
                    " expected {:.2f}^{{+{:.2f}}}_{{{:.2f}}} (stat) ^{{+{:.2f}}}_{{{:.2f}}} (syst)"
                    .format(totErrBand.GetY()[0],
                            statErrBand.GetErrorYhigh(0) if statErrBand else 0.0,
                            statErrBand.GetErrorYlow(0) if statErrBand else 0.0,
                            systErrBand.GetErrorYhigh(0) if systErrBand else 0.0,
                            systErrBand.GetErrorYlow(0) if systErrBand else 0.0)
                    )+
                   " obs {:.2f}".format(dataGraph.GetY()[0]))
    if histoSignal and isRightSignal:
        hname = histoSignal.GetName()
        label = ('H#rightarrow#mu#tau' if 'signaltaumu' in hname else
                 'H#rightarrowe#tau'   if 'signaltaue' in hname else
                 'signal')
        label = ("{}, BR=1%".format(label) if formatAuxMaterial else
                 "{}, BR=1%, {:.2f}".format(label, integralWou(histoSignal)))
        leg.AddEntry(histoSignal, label, 'l')
    leg.Draw('same')
    topPad.Update()
    tex = r.TLatex()
    tex.SetTextSize(0.5 * tex.GetTextSize())
    tex.SetNDC(True)
    label  = "%s tot bkg : "%(can.GetName())
    label += "%.3f #pm %.3f (stat)"%(integralAndError(histoTotBkg))
    if systErrBand :
        sysUp, sysDo = systUtils.totalUpDownVariation(systErrBand)
        label += "#pm #splitline{%.3f}{%.3f} (syst)"%(sysUp, sysDo)
    if drawYieldAndError :
        tex.DrawLatex(0.10, 0.95, label)
        topPad.SetTopMargin(2.0*topPad.GetTopMargin())
    atlasLabel = drawAtlasLabel(can, align=13, scale=0.75,
                                xpos=0.175 if formatAuxMaterial else 0.125,
                                ypos=0.945 if formatAuxMaterial else None,
                                public=True)
    if topLabel and not formatAuxMaterial : topRightLabel(can, topLabel, ypos=1.0)
    yMin, yMax = getMinMax([histoData, dataGraph, histoTotBkg, histoSignal, totErrBand])
    padMaster.SetMinimum(0.0)
    padMaster.SetMaximum(1.1 * yMax)
    padMaster.GetXaxis().SetLabelSize(0)
    padMaster.GetXaxis().SetTitleSize(0)
    increaseAxisFont(padMaster.GetXaxis())
    increaseAxisFont(padMaster.GetYaxis())
    topPad.RedrawAxis()
    topPad.Update() # force stack to create padMaster
    # draw bot (ratio)
    can.cd()
    botPad.Draw()
    botPad.cd()
    ratio = systUtils.buildAsymmRatioGraph(dataGraph, totErrBand)
    ratioPadMaster = padMaster.Clone(padMaster.GetName()+'_ratio')
    ratioPadMaster.SetDirectory(0)
    ratioPadMaster.Clear()
    yMin, yMax = 0.0, 2.0
    ratioPadMaster.SetMinimum(yMin)
    ratioPadMaster.SetMaximum(yMax)
    ratioPadMaster.SetStats(0)
    ratioPadMaster.Draw('axis')
    x_lo, x_hi = getXrange(ratioPadMaster)
    refLines = [referenceLine(x_lo, x_hi, y, y) for y in [0.5, 1.0, 1.5]]
    for l in refLines : l.Draw()
    err_band_r = systUtils.buildErrBandRatioGraph(totErrBand)
    err_band_r.Draw('E2 same')
    ratio.Draw('ep')
    xA, yA = ratioPadMaster.GetXaxis(), ratioPadMaster.GetYaxis()
    textScaleUp = 0.75*1.0/botPad.GetHNDC()
    # if xaxis_title : xA.SetTitle(xaxis_title)
    yA.SetNdivisions(-104)
    yA.SetTitle('Data/Bkg')
    yA.CenterTitle()
    yA.SetTitleOffset(yA.GetTitleOffset()/textScaleUp)
    xA.SetTitleSize(yA.GetTitleSize()) # was set to 0 for padmaster, restore it
    xA.SetLabelSize(yA.GetLabelSize())
    for a in [xA, yA] :
        a.SetLabelSize(a.GetLabelSize()*textScaleUp)
        a.SetTitleSize(a.GetTitleSize()*textScaleUp)
    botPad._graphical_objects = [ratio, ratioPadMaster, err_band_r] + refLines # avoid garbage collection
    botPad.Update()
    can.Update()
    for ext in ['png','eps'] : can.SaveAs(outdir+'/'+can.GetName()+'.'+ext)
Example #6
0
def plotHistos(
        histoData=None,
        histoSignal=None,
        histoTotBkg=None,
        histosBkg={},
        statErrBand=None,
        systErrBand=None,  # these are TGraphAsymmErrors
        canvasName='canvas',
        outdir='./',
        options=None,
        stack_order=[],
        topLabel='',
        drawStatErr=False,
        drawSystErr=False,
        drawYieldAndError=False,
        printYieldSummary=False):
    "Note: blinding can be required for only a subrange of the histo, so it is taken care of when filling"
    verbose = options.verbose
    formatAuxMaterial = options.format_aux
    setAtlasStyle()
    padMaster = histoData
    if verbose:
        print "plotting ", padMaster.GetName(), ' (', padMaster.GetEntries(
        ), ' entries)'
    can = r.TCanvas(canvasName, padMaster.GetTitle(), 800, 800)
    botPad, topPad = buildBotTopPads(can, squeezeMargins=False)
    can.cd()
    topPad.Draw()
    # draw top
    topPad.cd()
    topPad._hists = [padMaster]
    if formatAuxMaterial:
        for ax in [padMaster.GetXaxis(), padMaster.GetYaxis()]:
            ax.SetTitle(prettify(ax.GetTitle()))
    padMaster.Draw('axis')
    topPad.Update(
    )  # necessary to fool root's dumb object ownership of the stack
    stack = r.THStack('stack_' + padMaster.GetName(), '')
    r.SetOwnership(stack, False)
    topPad._hists.append(stack)
    leg = topRightLegend(can,
                         0.300 if formatAuxMaterial else 0.225,
                         0.400 if formatAuxMaterial else 0.325,
                         shiftX=-0.1 if formatAuxMaterial else 0.0,
                         shiftY=-0.1 if formatAuxMaterial else 0.0)
    topPad._leg = leg
    leg.SetBorderSize(0)
    leg.SetTextFont(padMaster.GetTitleFont())
    leg._reversedEntries = []

    def integralWou(h):
        "Integral with underflow and overflow"
        return h.Integral(0, h.GetNbinsX() + 1)

    for group, histo in sortedAs(histosBkg, stack_order):
        histo.SetFillColor(getGroupColor(group))
        histo.SetLineWidth(2)
        histo.SetLineColor(r.kBlack)
        stack.Add(histo)
        topPad._hists.append(histo)
        leg._reversedEntries.append(
            (histo, prettify(group) if formatAuxMaterial else
             "{0}: {1:.2f}".format(group, integralWou(histo)), 'F'))
    if not formatAuxMaterial:
        leg._reversedEntries.append((dummyHisto(), "{0}, {1:.2f}".format(
            'bkg', sum([integralWou(h) for h in stack.GetHists()])), 'l'))
    if statErrBand and drawStatErr:
        statErrBand.SetFillStyle(3006)
        leg._reversedEntries.append((statErrBand, 'stat', 'f'))
    if systErrBand and drawSystErr:
        systErrBand.SetFillStyle(3007)
        leg._reversedEntries.append((systErrBand, 'syst', 'f'))
    leg._reversedEntries.append(
        (histoData, "Data {0}".format(prettify(topLabel)) if formatAuxMaterial
         else "{0}, {1:.2f}".format('data', integralWou(histoData)), 'p'))
    for h, g, o in leg._reversedEntries[::-1]:
        leg.AddEntry(h, g, o)  # stack goes b-t, legend goes t-b
    stack.Draw('hist same')
    histoData.SetMarkerStyle(r.kFullCircle)
    histoData.SetLineWidth(2)
    dataGraph = graphWithPoissonError(histoData)
    dataGraph.Draw('same p')
    isRightSignal = False
    if histoSignal:
        histoSignal.SetFillStyle(0)
        histoSignal.SetFillColor(0)
        histoSignal.SetLineColor(getGroupColor('signal'))
        histoSignal.SetLineWidth(3)
        isRightSignal = (all(s in histoSignal.GetName()
                             for s in ['signaltaumu', 'sr_mue'])
                         or all(s in histoSignal.GetName()
                                for s in ['signaltaue', 'sr_emu']))
        if isRightSignal: histoSignal.Draw('histo same')
    if statErrBand and drawStatErr:
        statErrBand.SetFillStyle(3006)
        statErrBand.Draw('E2 same')
        leg.AddEntry(statErrBand, 'stat', 'f')
    if systErrBand and drawSystErr:
        systErrBand.SetFillStyle(3007)
        systErrBand.Draw('E2 same')
        leg.AddEntry(systErrBand, 'syst', 'f')
    totErrBand = systUtils.addErrorBandsInQuadrature(statErrBand, systErrBand)
    if totErrBand:
        totErrBand.Draw('E2 same')
        totErrBand.SetFillStyle(3005)
        leg.AddEntry(totErrBand, 'stat+syst', 'f')
        if printYieldSummary:
            print_total_error = False
            print(
                "{}:".format(topLabel if topLabel else dataGraph.GetName()) +
                (" expected {:.2f}^{{+{:.2f}}}_{{{:.2f}}}".format(
                    totErrBand.GetY()[0], totErrBand.GetErrorYhigh(0),
                    totErrBand.GetErrorYlow(0)) if print_total_error else
                 " expected {:.2f}^{{+{:.2f}}}_{{{:.2f}}} (stat) ^{{+{:.2f}}}_{{{:.2f}}} (syst)"
                 .format(totErrBand.GetY()[0],
                         statErrBand.GetErrorYhigh(0) if statErrBand else 0.0,
                         statErrBand.GetErrorYlow(0) if statErrBand else 0.0,
                         systErrBand.GetErrorYhigh(0) if systErrBand else 0.0,
                         systErrBand.GetErrorYlow(0) if systErrBand else 0.0))
                + " obs {:.2f}".format(dataGraph.GetY()[0]))
    if histoSignal and isRightSignal:
        hname = histoSignal.GetName()
        label = ('H#rightarrow#mu#tau' if 'signaltaumu' in hname else
                 'H#rightarrowe#tau' if 'signaltaue' in hname else 'signal')
        label = ("{}, BR=1%".format(label) if formatAuxMaterial else
                 "{}, BR=1%, {:.2f}".format(label, integralWou(histoSignal)))
        leg.AddEntry(histoSignal, label, 'l')
    leg.Draw('same')
    topPad.Update()
    tex = r.TLatex()
    tex.SetTextSize(0.5 * tex.GetTextSize())
    tex.SetNDC(True)
    label = "%s tot bkg : " % (can.GetName())
    label += "%.3f #pm %.3f (stat)" % (integralAndError(histoTotBkg))
    if systErrBand:
        sysUp, sysDo = systUtils.totalUpDownVariation(systErrBand)
        label += "#pm #splitline{%.3f}{%.3f} (syst)" % (sysUp, sysDo)
    if drawYieldAndError:
        tex.DrawLatex(0.10, 0.95, label)
        topPad.SetTopMargin(2.0 * topPad.GetTopMargin())
    atlasLabel = drawAtlasLabel(can,
                                align=13,
                                scale=0.75,
                                xpos=0.175 if formatAuxMaterial else 0.125,
                                ypos=0.945 if formatAuxMaterial else None,
                                public=True)
    if topLabel and not formatAuxMaterial:
        topRightLabel(can, topLabel, ypos=1.0)
    yMin, yMax = getMinMax(
        [histoData, dataGraph, histoTotBkg, histoSignal, totErrBand])
    padMaster.SetMinimum(0.0)
    padMaster.SetMaximum(1.1 * yMax)
    padMaster.GetXaxis().SetLabelSize(0)
    padMaster.GetXaxis().SetTitleSize(0)
    increaseAxisFont(padMaster.GetXaxis())
    increaseAxisFont(padMaster.GetYaxis())
    topPad.RedrawAxis()
    topPad.Update()  # force stack to create padMaster
    # draw bot (ratio)
    can.cd()
    botPad.Draw()
    botPad.cd()
    ratio = systUtils.buildAsymmRatioGraph(dataGraph, totErrBand)
    ratioPadMaster = padMaster.Clone(padMaster.GetName() + '_ratio')
    ratioPadMaster.SetDirectory(0)
    ratioPadMaster.Clear()
    yMin, yMax = 0.0, 2.0
    ratioPadMaster.SetMinimum(yMin)
    ratioPadMaster.SetMaximum(yMax)
    ratioPadMaster.SetStats(0)
    ratioPadMaster.Draw('axis')
    x_lo, x_hi = getXrange(ratioPadMaster)
    refLines = [referenceLine(x_lo, x_hi, y, y) for y in [0.5, 1.0, 1.5]]
    for l in refLines:
        l.Draw()
    err_band_r = systUtils.buildErrBandRatioGraph(totErrBand)
    err_band_r.Draw('E2 same')
    ratio.Draw('ep')
    xA, yA = ratioPadMaster.GetXaxis(), ratioPadMaster.GetYaxis()
    textScaleUp = 0.75 * 1.0 / botPad.GetHNDC()
    # if xaxis_title : xA.SetTitle(xaxis_title)
    yA.SetNdivisions(-104)
    yA.SetTitle('Data/Bkg')
    yA.CenterTitle()
    yA.SetTitleOffset(yA.GetTitleOffset() / textScaleUp)
    xA.SetTitleSize(
        yA.GetTitleSize())  # was set to 0 for padmaster, restore it
    xA.SetLabelSize(yA.GetLabelSize())
    for a in [xA, yA]:
        a.SetLabelSize(a.GetLabelSize() * textScaleUp)
        a.SetTitleSize(a.GetTitleSize() * textScaleUp)
    botPad._graphical_objects = [ratio, ratioPadMaster, err_band_r
                                 ] + refLines  # avoid garbage collection
    botPad.Update()
    can.Update()
    for ext in ['png', 'eps']:
        can.SaveAs(outdir + '/' + can.GetName() + '.' + ext)
def plotHistos(histoData=None, histoSignal=None, histoTotBkg=None, histosBkg={},
               statErrBand=None, systErrBand=None, # these are TGraphAsymmErrors
               canvasName='canvas', outdir='./', verbose=False,
               drawStatErr=False, drawSystErr=False,
               drawYieldAndError=False) :
    "Note: blinding can be required for only a subrange of the histo, so it is taken care of when filling"
    #setWhPlotStyle()
    setAtlasStyle()
    padMaster = histoData
    if verbose : print "plotting ",padMaster.GetName()
    can = r.TCanvas(canvasName, padMaster.GetTitle(), 800, 600)
    can.cd()
    can._hists = [padMaster]
    padMaster.Draw('axis')
    can.Update() # necessary to fool root's dumb object ownership of the stack
    stack = r.THStack('stack_'+padMaster.GetName(), '')
    r.SetOwnership(stack, False)
    can._hists.append(stack)
    leg = topRightLegend(can, 0.225, 0.325)
    can._leg = leg
    leg.SetBorderSize(0)
    leg._reversedEntries = []
    for group, histo in sortedAs(histosBkg, stackedGroups()) :
        histo.SetFillColor(getGroupColor(group))
        histo.SetLineWidth(2)
        histo.SetLineColor(r.kBlack)
        stack.Add(histo)
        can._hists.append(histo)
        leg._reversedEntries.append((histo, group, 'F'))
    for h, g, o in leg._reversedEntries[::-1] : leg.AddEntry(h, g, o) # stack goes b-t, legend goes t-b
    stack.Draw('hist same')
    histoData.SetMarkerStyle(r.kFullCircle)
    histoData.SetLineWidth(2)
    dataGraph = graphWithPoissonError(histoData)
    dataGraph.Draw('same p')
    if histoSignal :
        histoSignal.SetLineColor(getGroupColor('signal'))
        histoSignal.SetLineWidth(2)
        histoSignal.Draw('histo same')
        leg.AddEntry(histoSignal, '(m_{C1},m_{N1})=(130, 0)GeV', 'l')
    if statErrBand and drawStatErr :
        statErrBand.SetFillStyle(3006)
        statErrBand.Draw('E2 same')
        leg.AddEntry(statErrBand, 'stat', 'f')
    if systErrBand and drawSystErr :
        systErrBand.SetFillStyle(3007)
        systErrBand.Draw('E2 same')
        leg.AddEntry(systErrBand, 'syst', 'f')
    totErrBand = systUtils.addErrorBandsInQuadrature(statErrBand, systErrBand)
    if totErrBand :
        totErrBand.Draw('E2 same')
        totErrBand.SetFillStyle(3005)
        leg.AddEntry(totErrBand, 'stat+syst', 'f')
    leg.Draw('same')
    can.Update()
    tex = r.TLatex()
    tex.SetTextSize(0.5 * tex.GetTextSize())
    tex.SetNDC(True)
    label  = "%s tot bkg : "%(can.GetName())
    label += "%.3f #pm %.3f (stat)"%(integralAndError(histoTotBkg))
    if systErrBand :
        sysUp, sysDo = systUtils.totalUpDownVariation(systErrBand)
        label += "#pm #splitline{%.3f}{%.3f} (syst)"%(sysUp, sysDo)
    if drawYieldAndError :
        tex.DrawLatex(0.10, 0.95, label)
        can.SetTopMargin(2.0*can.GetTopMargin())
    drawAtlasLabel(can, xpos=0.125, align=13)
    yMin, yMax = getMinMax([histoData, dataGraph, histoTotBkg, histoSignal, totErrBand])
    padMaster.SetMinimum(0.0)
    padMaster.SetMaximum(1.1 * yMax)
    increaseAxisFont(padMaster.GetXaxis())
    increaseAxisFont(padMaster.GetYaxis())
    can.RedrawAxis()
    can.Update() # force stack to create padMaster
    for ext in ['png','eps'] : can.SaveAs(outdir+'/'+can.GetName()+'.'+ext)