def draw(pad, hists, label=('','')) : pad.Draw() pad.cd() h_data = hists[dataSample()] stack = r.THStack('stack_'+h_data.GetName(), '') leg = topRightLegend(pad, 0.275, 0.475, shift=-0.025) leg.SetBorderSize(0) leg.AddEntry(h_data, dataSample(), 'P') for s in mcSamples() : h = hists[s] h.SetMarkerSize(0) h.SetFillColor(colors[s]) h.SetLineColor(h.GetFillColor()) h.SetDrawOption('bar') stack.Add(h) for s in mcSamples()[::-1] : leg.AddEntry(hists[s], s, 'F') # stack goes b-t, legend goes t-b h_data.SetMarkerStyle(r.kFullDotLarge) stack.Draw('hist') h_data.Draw('p same') leg.Draw('same') tex = r.TLatex() tex.SetNDC(True) label = "#splitline{%s}{%s}"%(label[0], label[1]) if len(label)==2 else label tex.DrawLatex(0.25, 0.95, label) pad.Update() # force stack to create padMaster padMaster = stack.GetHistogram() pMin, pMax = getMinMax([padMaster, h_data]) stack.SetMaximum(pMax) pad._graphical_objects = [stack, h_data, leg, tex] + [h for h in stack.GetStack()] pad.Update()
def plotStackedHistos(histosFlavorSlice={}, canvasName='', outputDir='./', frameTitle='stack', colors={}) : "Plot the input histos used to compute the fractions" histos = histosFlavorSlice can = r.TCanvas(canvasName, canvasName, 800, 600) can.cd() stack = r.THStack('stack_'+canvasName, '') leg = topRightLegend(can, 0.275, 0.475, shift=-0.025) leg.SetBorderSize(0) colors = SampleUtils.colors if not colors else colors procs = sorted(histos.keys()) for p in procs: h = histos[p] h.SetFillColor(colors[p]) h.SetLineColor(h.GetFillColor()) h.SetDrawOption('bar') stack.Add(h) for s in procs[::-1] : leg.AddEntry(histos[s], s, 'F') # stack goes b-t, legend goes t-b stack.Draw('hist e') leg.Draw('same') tex = r.TLatex() tex.SetNDC(True) tex.SetTextFont(first(histos).GetTitleFont()) tex.SetTextSize(first(histos).GetTitleSize()) tex.DrawLatex(0.1, 0.925, frameTitle.split(';')[0]) can.Update() # force stack to create canMaster canMaster = stack.GetHistogram() canMaster.SetTitle(frameTitle) canMaster.Draw('axis same') can._graphical_objects = [stack, canMaster, leg, tex] + [h for h in stack.GetStack()] can.Update() for ext in ['png','eps'] : outFilename = outputDir+'/'+canvasName+'.'+ext rmIfExists(outFilename) can.SaveAs(outFilename)
def plot_emu_mue_with_ratio(canvas=None, h_mue=None, h_emu=None, h_ratio=None, filename='', figformats=['png', 'eps'], label=''): c = canvas c.Clear() c._graphics = [] c.cd() botPad, topPad = buildBotTopPads(c, splitFraction=0.375) topPad.Draw() topPad.cd() h_mue.SetStats(0) h_emu.SetStats(0) h_emu.SetLineColor(r.kBlue) h_mue.SetLineColor(r.kRed) h_mue.Draw() h_emu.Draw('same') pm = h_mue yMin, yMax = getMinMax([h_mue, h_emu]) pm.SetMinimum(0.0) pm.SetMaximum(1.1 * yMax) xax = pm.GetXaxis() yax = pm.GetYaxis() xax.SetLabelSize(0) xax.SetTitleSize(0) leg = topRightLegend(c, 0.275, 0.275, shift=0.05) leg.SetBorderSize(0) leg.SetHeader(label) leg.AddEntry(h_mue, '#mue', 'L') leg.AddEntry(h_emu, 'e#mu', 'L') leg.Draw() c._graphics.append(leg) c.cd() botPad.Draw() botPad.cd() h_ratio.SetLineColor(r.kBlack) h_ratio.SetTitle('') xax = h_ratio.GetXaxis() yax = h_ratio.GetYaxis() yax.SetRangeUser(0.0, 2.0) yax.SetTitle('e#mu / #mue ratio') xA, yA = h_ratio.GetXaxis(), h_ratio.GetYaxis() textScaleUp = 1.0/botPad.GetHNDC() yA.SetNdivisions(-104) yA.CenterTitle() yA.SetTitleOffset(yA.GetTitleOffset()/textScaleUp) for a in [xA, yA] : a.SetLabelSize(a.GetLabelSize()*textScaleUp) a.SetTitleSize(a.GetTitleSize()*textScaleUp) h_ratio.Draw() refline = referenceLine(xA.GetXmin(), xA.GetXmax()) refline.Draw() c._graphics.append(refline) c.Update() for ext in figformats: c.SaveAs("{0}.{1}".format(filename, ext)) print "{0}.{1}".format(filename, ext)
def plotFractionsStacked(histos={}, canvasName='', canvasTitle='', outputDir='./', frameTitle='title;p_{T} [GeV]; efficiency', histos2={}, h1Label='', h2Label='') : "plot stack of histos; optional histos2 are also stacked with the same colors, but with different fill style" can = r.TCanvas(canvasName, '', 800, 600) can.cd() stack = r.THStack('stack_'+canvasName, '') leg = topRightLegend(can, 0.275, 0.475, shift=+0.010) leg.SetBorderSize(0) leg.SetX1NDC(0.9) leg.SetX2NDC(1.0) colors = SampleUtils.colors procs = sorted(histos.keys()) def setHistoAtts(histo, process, colors=colors, fillStyle=None) : h, p = histo, process h.SetMarkerSize(0) h.SetFillColor(colors[p]) h.SetLineColor(h.GetFillColor()) h.SetDrawOption('bar') paleColors = {'ttbar':r.kRed-9, 'zjets' : r.kOrange-4, 'wjets' : r.kBlue-8, 'diboson' : r.kSpring+1, 'singletop' : r.kAzure+6, 'multijet' : r.kGray, 'heavyflavor' : r.kViolet-9} if fillStyle : h.SetFillColor(paleColors[p]) h.SetLineColor(h.GetFillColor()) for p in procs: h = histos[p] setHistoAtts(h, p) stack.Add(h) for s in procs[::-1] : leg.AddEntry(histos[s], ('bb/cc' if s=='heavyflavor' else s), 'F') # stack goes b-t, legend goes t-b for p in filter(lambda p: p in histos2, procs) : setHistoAtts(histos2[p], p, fillStyle=3001) stack.Add(histos2[p]) stack.Draw('hist') if h1Label or h2Label: leg.SetHeader(', '.join(["%s : %s"%(f,l) if l else '' for f,l in [('darker',h1Label), ('lighter',h2Label)]])) leg.Draw('same') tex = r.TLatex() tex.SetNDC(True) tex.DrawLatex(0.1, 0.9, 'fractions: '+frameTitle[:frameTitle.find(';')-1]) can.Update() # force stack to create canMaster canMaster = stack.GetHistogram() canMaster.SetTitle(frameTitle) canMaster.Draw('axis same') can._graphical_objects = [stack, canMaster, leg, tex] + [h for h in stack.GetStack()] can.Update() for ext in ['png','eps'] : outFilename = outputDir+'/'+canvasName+'.'+ext rmIfExists(outFilename) can.SaveAs(outFilename)
def drawTop(pad, hists, err_band, label=('','')) : pad.Draw() pad.cd() h_data = hists[dataSample()] h_bkg = hists['sm'] stack = r.THStack('stack_'+h_data.GetName(), '') leg = topRightLegend(pad, 0.275, 0.475, shift=-0.025) leg.SetBorderSize(0) leg.AddEntry(h_data, dataSample(), 'P') leg.AddEntry(h_bkg, 'sm', 'L') counters = dict() if 'nbjets' in h_data.GetName() : counters['data'] = integralAndError(h_data) counters['sm'] = integralAndError(h_bkg) for s in bkSamples() : h = hists[s] h.SetMarkerSize(0) h.SetFillColor(colors[s]) h.SetLineColor(h.GetFillColor()) h.SetDrawOption('bar') if 'nbjets' in h.GetName() : counters[s] = integralAndError(h) stack.Add(h) for s in bkSamples()[::-1] : leg.AddEntry(hists[s], s, 'F') # stack goes b-t, legend goes t-b h_data.SetMarkerStyle(r.kFullDotLarge) stack.Draw('hist') h_bkg.Draw('hist same') err_band.Draw('E2 same') h_data.Draw('p same') leg.AddEntry(err_band, 'Uncertainty', 'F') leg.Draw('same') tex = r.TLatex() tex.SetNDC(True) label = "#splitline{%s}{%s}"%(label[0], label[1]) if len(label)==2 else label tex.DrawLatex(0.50, 0.85, label) pad.Update() # force stack to create padMaster padMaster = stack.GetHistogram() pMin, pMax = getMinMax([h_bkg, h_data, err_band]) stack.SetMaximum(pMax) xAx, yAx = padMaster.GetXaxis(), padMaster.GetYaxis() xAx.SetTitle('') xAx.SetLabelSize(0) textScaleUp = 1.0/pad.GetHNDC() yAx.SetLabelSize(textScaleUp*yAx.GetLabelSize()) pad._graphical_objects = [stack, h_data, h_bkg, err_band, leg, tex] + [h for h in stack.GetStack()] pad.Update() if 'nbjets' in h_data.GetName() : print h_data.GetName() print " | ".join(["%12s"%k for k,v in sorted(counters.items())]) print " | ".join(["%12s"%("%.1f +/- %.1f"%v) for k,v in sorted(counters.items())])
def plotHisto(inputFiles={}, histoname='', canvasname='', outdir='./') : can = r.TCanvas(canvasname, histoname, 800, 600) can.cd() backds = [b for b in backgrounds if b in inputFiles] stackBkgds = filter(lambda x : x in backds, stackedBackgrounds) h_bkgs = dict((b, inputFiles[b].Get(histoname)) for b in backds) h_btot = inputFiles['allBkg'].Get(histoname) if 'allBkg' in inputFiles else None h_bnoHf = inputFiles['allBkgButHf'].Get(histoname) if 'allBkgButHf' in inputFiles else None h_data = inputFiles['data'].Get(histoname) if 'data' in inputFiles else None stack = r.THStack('stack_'+histoname, '') leg = topRightLegend(can, 0.275, 0.475, shift=-0.025) if h_data : leg.AddEntry(h_data, "data: %.1f"%h_data.Integral(), 'P') if h_btot : leg.AddEntry(h_btot, "tot bkg %.1f"%h_btot.Integral(), 'l') if h_bnoHf : leg.AddEntry(h_bnoHf, "bkgNoHf: %.1f"%h_bnoHf.Integral(), 'l') for b in stackBkgds : h = h_bkgs[b] if not h : print 'missing h for ',b continue h.SetMarkerSize(0) h.SetFillColor(colors[b]) h.SetLineColor(h.GetFillColor()) h.SetDrawOption('bar') stack.Add(h) for s in stackBkgds[::-1] : leg.AddEntry(h_bkgs[s], "%s: %.1f"%(s, h_bkgs[s].Integral()), 'F') # stack goes b-t, legend goes t-b stack.Draw('hist') if h_btot : h_btot.SetLineWidth(2*h_btot.GetLineWidth()) h_btot.Draw('hist same') if h_bnoHf : h_bnoHf.SetLineWidth(2*h_bnoHf.GetLineWidth()) h_bnoHf.SetLineStyle(2) h_bnoHf.Draw('hist same') if h_data : h_data.SetMarkerStyle(r.kFullDotLarge) h_data.Draw('p same') leg.Draw('same') yMin, yMax = getMinMax([h for h in [stack.GetHistogram(), h_btot, h_bnoHf, h_data] if h is not None]) stack.SetMaximum(1.1*yMax) tex = r.TLatex() tex.SetNDC(True) tex.DrawLatex(0.15, 0.95, histoname) can.Update() for ext in ['png'] : can.SaveAs(outdir+'/'+canvasname+'.'+ext)
def plot_m_emu_mue(h_tauel, h_taumu, header='leg header', normalize=True): can = r.TCanvas('m_coll_'+header,'') can.cd() if normalize: for h in [h_tauel, h_taumu]: if h.Integral(): h.Scale(1.0/h.Integral()) padMaster = h_tauel padMaster.SetMinimum(0.0) padMaster.SetMaximum(1.1*max([h.GetMaximum() for h in [h_tauel, h_taumu]])) for h, c in [(h_tauel, r.kRed), (h_taumu, r.kBlue)]: h.SetLineColor(c) h.SetMarkerColor(c) padMaster.Draw('axis') leg = topRightLegend(can, 0.25, 0.35) leg.SetHeader(header) for l, h in [('h#rightarrow#taue, sr_emu', h_tauel), ('h#rightarrow#tau#mu, sr_mue', h_taumu)]: h.SetStats(0) h.Draw('l same') leg.AddEntry(h, l, 'lp') leg.Draw() can.Update() can.SaveAs('m_coll_'+header+'.png')
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='./', 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 main(): parser = argparse.ArgumentParser( description=description, epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter) add_arg = parser.add_argument add_arg('-o', '--output-dir', default="./") add_arg('-p', '--process', help='one physics process, eg. ttw') add_arg('-s', '--systematic', help='one of the systematic variations') add_arg('-v', '--verbose', action='store_true') add_arg('-d', '--debug', action='store_true') args = parser.parse_args() set_log(args.verbose, args.debug) outdir = args.output_dir process = args.process systematic = args.systematic available_processes = get_input_samples().keys() if process not in available_processes: raise StandardError("invalid process %s, should be one of %s" % (process, str(available_processes))) available_systematics = get_input_samples()[process].keys() if systematic not in available_systematics: raise StandardError("invalid systematic %s, should be one of %s" % (systematic, str(available_systematics))) file_label = process + '_sys_' + systematic plot_label = process + ' sys. ' + systematic normalize_to_unity = False # True luminosity = 1.0 combiner = HistogramCombiner() combiner.build_samples(process=process, systematic=systematic) histogram_names = [ 'h_meff', 'h_jetN', # 'h_electronPt', 'h_muonPt', # 'h_bjetEmulN', 'h_bjetN', # 'h_bjetEmulN_sr3b', 'h_bjetN_sr3b', # 'h_bjetEmulN_sr1b', 'h_bjetN_sr1b', # 'h_bjetEmulN_cr2bttV', 'h_bjetN_cr2bttV', # 'h_meff_sr3b', 'h_jetN_sr3b', 'h_met_sr3b', # 'h_meff_sr1b', 'h_jetN_sr1b', 'h_met_sr1b', # 'h_meff_sr0b5j', 'h_jetN_sr0b5j', 'h_met_sr0b5j', # 'h_meff_sr0b4j', 'h_jetN_sr0b4j', 'h_met_sr0b4j', # 'h_meff_sr0b3j', 'h_jetN_sr0b3j', 'h_met_sr0b3j', # 'h_meff_cr2bttV', 'h_jetN_cr2bttV', 'h_met_cr2bttV' ] combiner.compute_normalization_factors() output_pdf_name = outdir + '/' + file_label + '.pdf' c_summary = R.TCanvas('c_summary', 'plotExplicitSamples sampes summary ') combiner.print_sample_summary_to_pdf( c_summary, label="%s: nominal vs. %s systematic" % (process, systematic)) c_summary.SaveAs(output_pdf_name + '(') for histogram_name in histogram_names: rebin = 'meff' in histogram_name # and '_sr' in histogram_name # non-inclusive histos: low stats rebin_factor = (2 if 'meff' in histogram_name else 2 if 'jetN' in histogram_name else 1) if rebin else 1 histograms = combiner.get_histograms(histogram_name=histogram_name) h_nom = histograms['nominal'] h_up = histograms['up'] h_dn = histograms['down'] if 'h_jetFlavorMultiplicity' in histogram_name: h_nom = emulate_btag_multiplicity_from_truth_flavor(h_nom, 'nom') h_up = emulate_btag_multiplicity_from_truth_flavor(h_up, 'up') h_dn = emulate_btag_multiplicity_from_truth_flavor(h_dn, 'dn') histos = [h_nom, h_up, h_dn] for h in set(histos): # set: avoid rebinning twice when up==down h.Rebin(rebin_factor) h_nom.SetLineWidth(2 * h_nom.GetLineWidth()) h_nom.SetLineColor(R.kBlack) h_up.SetLineColor(R.kBlue) h_dn.SetLineColor(R.kRed) pad_master = h_nom pad_master.SetMaximum(1.1 * max([h.GetMaximum() for h in histos])) pad_master.SetMinimum(1.0 * min([0.0] + [h.GetMinimum() for h in histos])) pad_master.GetYaxis().SetTitle('Arbitrary Units') pad_master.SetStats(0) can = R.TCanvas('c_ttV_syst_' + histogram_name, 'ttV explicit variations ' + pad_master.GetTitle(), 700, 700) botPad, topPad = ru.buildBotTopPads(can, squeezeMargins=False) # top can.cd() topPad.Draw() topPad.cd() topPad._po = [pad_master] # persistent objects pad_master.GetXaxis().SetTitleSize(0) pad_master.GetXaxis().SetLabelSize(0) pad_master.Draw('axis') # ru.topRightLabel(topPad, pad_master.GetTitle(), xpos=0.5) ru.topRightLabel(topPad, "#bf{#it{ATLAS}} Simulation Preliminary", xpos=0.85, ypos=0.9) ru.topRightLabel(topPad, "#sqrt{s} = 13 TeV", xpos=0.85, ypos=0.8) leg = ru.topRightLegend(can, legWidth=0.225, legHeight=0.300, hShift=-0.10, vShift=-0.25) leg.SetBorderSize(0) # leg.SetHeader(plot_label+ ("(norm=1)" if normalize_to_unity else "(lumi %.1f)"%luminosity)) topPad._po.append(leg) def format_legend_label(h, l): return "{0}: {1:.2E} ({2:.0f})".format(l, h.Integral(), h.GetEntries()) def pretty_scale_legend_label(h, l): return ("nominal" if l is 'nom' else "#mu = 2.0 #mu_{0}" if l is 'up' else "#mu = 0.5 #mu_{0}" if l is 'dn' else 'unknown') for h, l in [(h_nom, 'nom'), (h_up, 'up'), (h_dn, 'dn')]: h.Draw('hist same') leg.AddEntry(h, pretty_scale_legend_label(h, l), 'l') topPad._po.append(h) leg.Draw('same') def integral_and_error(h): error = R.Double(0.0) integral = h.IntegralAndError(1, h.GetNbinsX() + 1, error) return integral, error def ratio_and_error(ave=(1.0, 0.01), bve=(2.0, 0.001)): a, sa = ave b, sb = bve if a and b: r = a / b e = r * sqrt((sa / a) * (sa / a) + (sb / b) * (sb / b)) return r, e else: return 0.0, 0.0 print_normalization_summary = histogram_name.startswith('h_meff') if print_normalization_summary: nom_int = h_nom.Integral() up_int = h_up.Integral() dn_int = h_dn.Integral() nom_int, nom_err = integral_and_error(h_nom) up_int, up_err = integral_and_error(h_up) dn_int, dn_err = integral_and_error(h_dn) rup, rupe = ratio_and_error((up_int, up_err), (nom_int, nom_err)) rdn, rdne = ratio_and_error((dn_int, dn_err), (nom_int, nom_err)) # print ("normalization change: " # +"{} up {:.1%} down {:.1%} (nom {:.1f}, up {:.1f}, do {:.1f})".format(h_nom.GetName(), # 1.0-up_int/nom_int if nom_int else 1.0, # 1.0-dn_int/nom_int if nom_int else 1.0, # nom_int, # up_int, # dn_int)) print( "normalization change: " + "{} up {:.1%} +/- {:.1%} down {:.1%} +/- {:.1%} ".format( h_nom.GetName(), 1.0 - rup, rupe, 1.0 - rdn, rdne) + "(integral: " + "nom {:.2E} +/- {:.2E}, up {:.2E} +/- {:.2E}, do {:.2E} +/- {:.2E})" .format(nom_int, nom_err, up_int, up_err, dn_int, dn_err) + " (entries nom {:.2E} up {:.2E} do {:.2E}".format( h_nom.GetEntries(), h_up.GetEntries(), h_dn.GetEntries())) print( "tex normalization change: " + "{} up ${:.1%} \pm {:.1%}$ down ${:.1%} \pm {:.1%}$ ".format( h_nom.GetName(), 1.0 - rup, rupe, 1.0 - rdn, rdne)) def bc(h): return [ h.GetBinContent(i) for i in range(1, 1 + h.GetNbinsX()) ] def max_frac_variation(h1, h2): "maximum bin-by-bin fractional variation; h1 is denominator, empty bins skipped" bc1 = bc(h1) bc2 = bc(h2) return max( [abs(b2 / b1) for b1, b2 in zip(bc1, bc2) if b1 and b2]) def max_frac_variation_within10(h1, h2): """maximum bin-by-bin fractional variation; h1 is denominator. Bins with <0.1*peak are skipped""" bc1 = bc(h1) bc2 = bc(h2) m1 = max(bc1) m2 = max(bc2) return max([ abs(b2 / b1) for b1, b2 in zip(bc1, bc2) if b1 > 0.1 * m1 and b2 > 0.1 * m2 ]) # print ("shape change: " # +"{} up {:.1%} down {:.1%} ".format(h_nom.GetName(), # 1.0-max_frac_variation_within10(h_up, h_nom), # 1.0-max_frac_variation_within10(h_dn, h_nom))) topPad.Update() # bottom can.cd() botPad.SetTopMargin(1.25 * botPad.GetTopMargin()) botPad.Draw() botPad.cd() ratio_up = ru.buildRatioHistogram(h_up, h_nom) ratio_dn = ru.buildRatioHistogram(h_dn, h_nom) yMin, yMax = 0.5, 1.5 ratioPadMaster = pad_master.Clone(pad_master.GetName() + '_ratio') ratioPadMaster.SetMinimum(yMin) ratioPadMaster.SetMaximum(yMax) ratioPadMaster.SetStats(0) ratioPadMaster.Draw('axis') x_lo, x_hi = ru.getXrange(ratioPadMaster) refLines = [ ru.referenceLine(x_lo, x_hi, y, y) for y in [0.5, 1.0, 1.5] if y > yMin and y < yMax ] for l in refLines: l.Draw() ratio_up.Draw('same') ratio_dn.Draw('same') xA, yA = ratioPadMaster.GetXaxis(), ratioPadMaster.GetYaxis() textScaleUp = 0.75 * 1.0 / botPad.GetHNDC() yA.SetNdivisions(-102) yA.SetTitle('Ratio') yA.CenterTitle() yA.SetTitleOffset(yA.GetTitleOffset() / textScaleUp) xA.SetTitleSize( yA.GetTitleSize()) # x- was set to 0 for padmaster, restore it xA.SetLabelSize(yA.GetLabelSize()) xA.SetTitle(prettify_title(xA.GetTitle())) for a in [xA, yA]: a.SetLabelSize(a.GetLabelSize() * textScaleUp) a.SetTitleSize(a.GetTitleSize() * textScaleUp) botPad._graphical_objects = [ratio_up, ratio_dn, ratioPadMaster ] + refLines # avoid garbage collection botPad.Update() can.Update() first_histo = histogram_name is histogram_names[0] last_histo = histogram_name is histogram_names[-1] can.SaveAs(outdir + '/' + can.GetName() + '.png') can.SaveAs(outdir + '/' + can.GetName() + '.eps') can.SaveAs(output_pdf_name + (')' if last_histo else ''))
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)
def main() : parser = argparse.ArgumentParser(description=description, epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter) add_arg = parser.add_argument add_arg('-o', '--output-dir', default="./") add_arg('-p', '--process', help='one physics process, eg. ttw') add_arg('-s', '--systematic', help='one of the systematic variations') add_arg('-v', '--verbose', action='store_true') add_arg('-d', '--debug', action='store_true') args = parser.parse_args() set_log(args.verbose, args.debug) outdir = args.output_dir process = args.process systematic = args.systematic available_processes = get_input_samples().keys() if process not in available_processes: raise StandardError("invalid process %s, should be one of %s"%(process, str(available_processes))) available_systematics = get_input_samples()[process].keys() if systematic not in available_systematics: raise StandardError("invalid systematic %s, should be one of %s"%(systematic, str(available_systematics))) file_label = process+'_sys_'+systematic plot_label = process+' sys. '+systematic normalize_to_unity = False # True luminosity = 1.0 combiner = HistogramCombiner() combiner.build_samples(process=process, systematic=systematic) histogram_names = ['h_meff', 'h_jetN', # 'h_electronPt', 'h_muonPt', # 'h_bjetEmulN', 'h_bjetN', # 'h_bjetEmulN_sr3b', 'h_bjetN_sr3b', # 'h_bjetEmulN_sr1b', 'h_bjetN_sr1b', # 'h_bjetEmulN_cr2bttV', 'h_bjetN_cr2bttV', # 'h_meff_sr3b', 'h_jetN_sr3b', 'h_met_sr3b', # 'h_meff_sr1b', 'h_jetN_sr1b', 'h_met_sr1b', # 'h_meff_sr0b5j', 'h_jetN_sr0b5j', 'h_met_sr0b5j', # 'h_meff_sr0b4j', 'h_jetN_sr0b4j', 'h_met_sr0b4j', # 'h_meff_sr0b3j', 'h_jetN_sr0b3j', 'h_met_sr0b3j', # 'h_meff_cr2bttV', 'h_jetN_cr2bttV', 'h_met_cr2bttV' ] combiner.compute_normalization_factors() output_pdf_name = outdir+'/'+file_label+'.pdf' c_summary = R.TCanvas('c_summary', 'plotExplicitSamples sampes summary ') combiner.print_sample_summary_to_pdf(c_summary, label="%s: nominal vs. %s systematic"%(process, systematic)) c_summary.SaveAs(output_pdf_name+'(') for histogram_name in histogram_names: rebin = 'meff' in histogram_name # and '_sr' in histogram_name # non-inclusive histos: low stats rebin_factor = (2 if 'meff' in histogram_name else 2 if 'jetN' in histogram_name else 1) if rebin else 1 histograms = combiner.get_histograms(histogram_name=histogram_name) h_nom = histograms['nominal'] h_up = histograms['up'] h_dn = histograms['down'] if 'h_jetFlavorMultiplicity' in histogram_name: h_nom = emulate_btag_multiplicity_from_truth_flavor(h_nom, 'nom') h_up = emulate_btag_multiplicity_from_truth_flavor(h_up, 'up') h_dn = emulate_btag_multiplicity_from_truth_flavor(h_dn, 'dn') histos = [h_nom, h_up, h_dn] for h in set(histos): # set: avoid rebinning twice when up==down h.Rebin(rebin_factor) h_nom.SetLineWidth(2*h_nom.GetLineWidth()) h_nom.SetLineColor(R.kBlack) h_up.SetLineColor(R.kBlue) h_dn.SetLineColor(R.kRed) pad_master = h_nom pad_master.SetMaximum(1.1*max([h.GetMaximum() for h in histos])) pad_master.SetMinimum(1.0*min([0.0]+[h.GetMinimum() for h in histos])) pad_master.GetYaxis().SetTitle('Arbitrary Units') pad_master.SetStats(0) can = R.TCanvas('c_ttV_syst_'+histogram_name, 'ttV explicit variations '+pad_master.GetTitle(), 700, 700) botPad, topPad = ru.buildBotTopPads(can, squeezeMargins=False) # top can.cd() topPad.Draw() topPad.cd() topPad._po = [pad_master] # persistent objects pad_master.GetXaxis().SetTitleSize(0) pad_master.GetXaxis().SetLabelSize(0) pad_master.Draw('axis') # ru.topRightLabel(topPad, pad_master.GetTitle(), xpos=0.5) ru.topRightLabel(topPad, "#bf{#it{ATLAS}} Simulation Preliminary", xpos=0.85, ypos=0.9) ru.topRightLabel(topPad, "#sqrt{s} = 13 TeV", xpos=0.85, ypos=0.8) leg = ru.topRightLegend(can, legWidth=0.225, legHeight=0.300, hShift=-0.10, vShift=-0.25) leg.SetBorderSize(0) # leg.SetHeader(plot_label+ ("(norm=1)" if normalize_to_unity else "(lumi %.1f)"%luminosity)) topPad._po.append(leg) def format_legend_label(h, l): return "{0}: {1:.2E} ({2:.0f})".format(l, h.Integral(), h.GetEntries()) def pretty_scale_legend_label(h, l): return ("nominal" if l is 'nom' else "#mu = 2.0 #mu_{0}" if l is 'up' else "#mu = 0.5 #mu_{0}" if l is 'dn' else 'unknown') for h,l in [(h_nom, 'nom'), (h_up, 'up'), (h_dn, 'dn')]: h.Draw('hist same') leg.AddEntry(h, pretty_scale_legend_label(h, l), 'l') topPad._po.append(h) leg.Draw('same') def integral_and_error(h): error = R.Double(0.0) integral = h.IntegralAndError(1, h.GetNbinsX()+1, error) return integral, error def ratio_and_error(ave=(1.0, 0.01), bve=(2.0, 0.001)): a, sa = ave b, sb = bve if a and b: r = a/b e = r * sqrt((sa/a)*(sa/a)+(sb/b)*(sb/b)) return r, e else: return 0.0, 0.0 print_normalization_summary = histogram_name.startswith('h_meff') if print_normalization_summary: nom_int = h_nom.Integral() up_int = h_up.Integral() dn_int = h_dn.Integral() nom_int, nom_err = integral_and_error(h_nom) up_int, up_err = integral_and_error(h_up) dn_int, dn_err = integral_and_error(h_dn) rup, rupe = ratio_and_error((up_int, up_err), (nom_int, nom_err)) rdn, rdne = ratio_and_error((dn_int, dn_err), (nom_int, nom_err)) # print ("normalization change: " # +"{} up {:.1%} down {:.1%} (nom {:.1f}, up {:.1f}, do {:.1f})".format(h_nom.GetName(), # 1.0-up_int/nom_int if nom_int else 1.0, # 1.0-dn_int/nom_int if nom_int else 1.0, # nom_int, # up_int, # dn_int)) print ("normalization change: " +"{} up {:.1%} +/- {:.1%} down {:.1%} +/- {:.1%} ".format(h_nom.GetName(), 1.0-rup, rupe, 1.0-rdn, rdne) +"(integral: " +"nom {:.2E} +/- {:.2E}, up {:.2E} +/- {:.2E}, do {:.2E} +/- {:.2E})".format(nom_int, nom_err, up_int, up_err, dn_int, dn_err) +" (entries nom {:.2E} up {:.2E} do {:.2E}".format(h_nom.GetEntries(), h_up.GetEntries(), h_dn.GetEntries())) print ("tex normalization change: " +"{} up ${:.1%} \pm {:.1%}$ down ${:.1%} \pm {:.1%}$ ".format(h_nom.GetName(), 1.0-rup, rupe, 1.0-rdn, rdne) ) def bc(h): return [h.GetBinContent(i) for i in range(1,1+h.GetNbinsX())] def max_frac_variation(h1, h2): "maximum bin-by-bin fractional variation; h1 is denominator, empty bins skipped" bc1 = bc(h1) bc2 = bc(h2) return max([abs(b2/b1) for b1, b2 in zip(bc1, bc2) if b1 and b2]) def max_frac_variation_within10(h1, h2): """maximum bin-by-bin fractional variation; h1 is denominator. Bins with <0.1*peak are skipped""" bc1 = bc(h1) bc2 = bc(h2) m1 = max(bc1) m2 = max(bc2) return max([abs(b2/b1) for b1, b2 in zip(bc1, bc2) if b1>0.1*m1 and b2>0.1*m2]) # print ("shape change: " # +"{} up {:.1%} down {:.1%} ".format(h_nom.GetName(), # 1.0-max_frac_variation_within10(h_up, h_nom), # 1.0-max_frac_variation_within10(h_dn, h_nom))) topPad.Update() # bottom can.cd() botPad.SetTopMargin(1.25*botPad.GetTopMargin()) botPad.Draw() botPad.cd() ratio_up = ru.buildRatioHistogram(h_up, h_nom) ratio_dn = ru.buildRatioHistogram(h_dn, h_nom) yMin, yMax = 0.5, 1.5 ratioPadMaster = pad_master.Clone(pad_master.GetName()+'_ratio') ratioPadMaster.SetMinimum(yMin) ratioPadMaster.SetMaximum(yMax) ratioPadMaster.SetStats(0) ratioPadMaster.Draw('axis') x_lo, x_hi = ru.getXrange(ratioPadMaster) refLines = [ru.referenceLine(x_lo, x_hi, y, y) for y in [0.5, 1.0, 1.5] if y>yMin and y<yMax] for l in refLines : l.Draw() ratio_up.Draw('same') ratio_dn.Draw('same') xA, yA = ratioPadMaster.GetXaxis(), ratioPadMaster.GetYaxis() textScaleUp = 0.75*1.0/botPad.GetHNDC() yA.SetNdivisions(-102) yA.SetTitle('Ratio') yA.CenterTitle() yA.SetTitleOffset(yA.GetTitleOffset()/textScaleUp) xA.SetTitleSize(yA.GetTitleSize()) # x- was set to 0 for padmaster, restore it xA.SetLabelSize(yA.GetLabelSize()) xA.SetTitle(prettify_title(xA.GetTitle())) for a in [xA, yA] : a.SetLabelSize(a.GetLabelSize()*textScaleUp) a.SetTitleSize(a.GetTitleSize()*textScaleUp) botPad._graphical_objects = [ratio_up, ratio_dn, ratioPadMaster] + refLines # avoid garbage collection botPad.Update() can.Update() first_histo = histogram_name is histogram_names[0] last_histo = histogram_name is histogram_names[-1] can.SaveAs(outdir+'/'+can.GetName()+'.png') can.SaveAs(outdir+'/'+can.GetName()+'.eps') can.SaveAs(output_pdf_name+ (')' if last_histo else ''))