def MakeMacroRegionPlot(macro_reg, datacard_dir, datacard_name, outdir, userMax=None): # based on MakePlot, but here we want to sum over several cards topo_regs = utils.GetMacroregions(macro_reg) #arbitrary set #list of lists, one per maco region, of low edges of MT2 bins mt2bins = [] for topo_reg in topo_regs: bins = utils.GetMT2binsFull(topo_reg) mt2bins.append(bins) bkg_processes = ["zinv", "llep", "qcd"] nBkgs = len(bkg_processes) # MT2 binning we want to use: let's take the region with the highest number of bins xbins = mt2bins[0] #start with the first region for tempmt2bins in mt2bins: if (len(xbins) < len(tempmt2bins)): xbins = tempmt2bins xbinsA = array('d', xbins) xbinsA[len(xbinsA) - 1] = 1800 # set last bin nBinsTotal = len(xbinsA) - 1 ## setup histograms h_data = ROOT.TH1D("h_data", "", len(xbinsA) - 1, xbinsA) h_bkg_tot = ROOT.TH1D("h_tot", "", len(xbinsA) - 1, xbinsA) h_bkg_vec = [] for i, proc in enumerate(bkg_processes): h_bkg_vec.append(ROOT.TH1D("h_" + proc, "", len(xbinsA) - 1, xbinsA)) h_unc = ROOT.TH1D("h_unc", "", len(xbinsA) - 1, xbinsA) # store prediction uncertainties h_unc_ratio = ROOT.TH1D("h_unc_ratio", "", len(xbinsA) - 1, xbinsA) # store prediction uncertainties ## fill histograms ibin = 0 binLabels = [] # for ijbj, jbj_reg in enumerate(jbj_regs): datacard_list = [] for imt2 in range(len(xbinsA) - 1): datacard_list.append([]) for itopo, topo_reg in enumerate(topo_regs): ibin = 0 for imt2 in range(len(mt2bins[itopo]) - 1): ibin += 1 mt2left = mt2bins[itopo][imt2] mt2right = mt2bins[itopo][imt2 + 1] if mt2right == 1800: mt2right = "Inf" mt2name = utils.GetMT2name(mt2left, mt2right) datacard_name_fmt = datacard_name.format(topo_reg, mt2name) datacard_list[imt2].append( os.path.join(datacard_dir, datacard_name_fmt)) # get yields. first entry is data, rest are background predictions #print datacard_name_fmt yields = utils.GetYieldsFromDatacard( os.path.join(datacard_dir, datacard_name_fmt), bkg_processes) #print yields[0] h_data.SetBinContent(ibin, h_data.GetBinContent(ibin) + yields[0]) for j in range(1, nBkgs + 1): h_bkg_vec[j - 1].SetBinContent( ibin, h_bkg_vec[j - 1].GetBinContent(ibin) + yields[j]) tot_pred = sum(yields[1:]) h_bkg_tot.SetBinContent(ibin, h_bkg_tot.GetBinContent(ibin) + tot_pred) # get uncertainties pred_unc = utils.GetUncertaintiesFromDatacard( os.path.join(datacard_dir, datacard_name_fmt), bkg_processes) tot_unc_up = ROOT.TMath.Sqrt( sum([(pred_unc[i][0] * yields[i + 1])**2 for i in range(nBkgs)])) tot_unc_down = ROOT.TMath.Sqrt( sum([(pred_unc[i][1] * yields[i + 1])**2 for i in range(nBkgs)])) tot_unc_sym = max(tot_unc_up, tot_unc_down) # h_unc.SetBinContent(ibin, h_unc.GetBinContent(ibin) + tot_unc_sym) # treat as fully correlated for now h_unc.SetBinContent(ibin, h_unc.GetBinContent(ibin) + tot_unc_sym * tot_unc_sym) # sum in quadrature #print tot_pred, tot_unc_up, tot_unc_down h_bkg_vec[0].SetFillColor(418) h_bkg_vec[1].SetFillColor(ROOT.kAzure + 4) h_bkg_vec[2].SetFillColor(401) # Outdated: simple sum in quadrature #for imt2 in range(len(xbinsA)-1): # h_unc_ratio.SetBinContent(imt2+1, h_data.GetBinContent(imt2+1)/h_bkg_tot.GetBinContent(imt2+1)) # h_unc_ratio.SetBinError(imt2+1, ROOT.TMath.Sqrt(h_unc.GetBinContent(imt2+1))/h_bkg_tot.GetBinContent(imt2+1)) # h_unc.SetBinError(imt2+1, ROOT.TMath.Sqrt(h_unc.GetBinContent(imt2+1))) # h_unc.SetBinContent(imt2+1, h_bkg_tot.GetBinContent(imt2+1)) for imt2 in range(len(xbinsA) - 1): unc = utils.getMacroRegionUncertainties("test" + str(imt2), datacard_list[imt2]) h_unc_ratio.SetBinContent( imt2 + 1, h_data.GetBinContent(imt2 + 1) / h_bkg_tot.GetBinContent(imt2 + 1)) h_unc_ratio.SetBinError(imt2 + 1, unc / h_bkg_tot.GetBinContent(imt2 + 1)) h_unc.SetBinError(imt2 + 1, unc) h_unc.SetBinContent(imt2 + 1, h_bkg_tot.GetBinContent(imt2 + 1)) stack = ROOT.THStack("bkg_stack", "") for j in range(nBkgs): h_bkg_vec[nBkgs - 1 - j].SetLineWidth(1) h_bkg_vec[nBkgs - 1 - j].SetLineColor(ROOT.kBlack) stack.Add(h_bkg_vec[nBkgs - 1 - j]) # h_bkg_tot.Print("all") # h_unc.Print("all") # h_unc_ratio.Print("all") h_data.Print("all") h_data.SetMarkerStyle(20) h_data.SetMarkerSize(1.3) h_data.SetMarkerColor(ROOT.kBlack) h_data.SetLineColor(ROOT.kBlack) ROOT.gStyle.SetOptStat(0) ROOT.gStyle.SetLineWidth(1) c = ROOT.TCanvas("c", "c", 600, 600) pads = [] pads.append(ROOT.TPad("1", "1", 0.0, 0.18, 1.0, 1.0)) pads.append(ROOT.TPad("2", "2", 0.0, 0.0, 1.0, 0.19)) pads[0].SetTopMargin(0.08) pads[0].SetBottomMargin(0.13) pads[0].SetRightMargin(0.05) pads[0].SetLeftMargin(0.10) pads[1].SetRightMargin(0.05) pads[1].SetLeftMargin(0.10) pads[0].Draw() pads[1].Draw() pads[0].cd() pads[0].SetLogy(1) # pads[0].SetTickx(1) pads[1].SetTickx(1) pads[0].SetTicky(1) pads[1].SetTicky(1) yMin = 1e-1 if userMax != None: yMax = userMax else: yMax = h_data.GetMaximum()**(2.0) h_data.GetYaxis().SetRangeUser(yMin, yMax) h_data.GetYaxis().SetTitle("Events / Bin") h_data.GetYaxis().SetTitleOffset(1.2) h_data.GetYaxis().SetTickLength(0.02) #h_data.GetXaxis().SetLabelSize(0) h_data.GetXaxis().SetTickLength(0.015) h_data.GetXaxis().SetTitle("MT2 [GeV]") h_data.GetXaxis().SetTitleSize(0.04) h_data.GetXaxis().SetLabelSize(0.036) h_data.GetXaxis().SetTitleOffset(1.2) # just draw dots to get axes. Will draw TGraphAsymmErrors on top later h_data.SetMarkerStyle(1) h_data.Draw("P") # draw the backgrounds stack.Draw("SAME HIST") # draw the prediction uncertainties h_unc.SetFillStyle(3244) h_unc.SetFillColor(ROOT.kGray + 3) h_unc.Draw("SAME E2") # get a graph using proper asymmetric poissonian errors g_data = ROOT.TGraphAsymmErrors() ppmUtils.ConvertToPoissonGraph(h_data, g_data, drawZeros=True) # g_data.SetPointError(g_data.GetN()-1, 0, 0, 0, 0) g_data.SetMarkerStyle(20) g_data.SetMarkerSize(1.2) g_data.SetLineWidth(1) # draw the graph and then axes again on top g_data.Draw("SAME P") h_data.Draw("SAME AXIS") # save for later left = pads[0].GetLeftMargin() right = pads[0].GetRightMargin() top = pads[0].GetTopMargin() bot = pads[0].GetBottomMargin() text = ROOT.TLatex() text.SetNDC(1) # draw the "Pre-fit background" text text.SetTextAlign(13) text.SetTextFont(42) text.SetTextAngle(0) text.SetTextSize(0.05) text.DrawLatex(left + 0.04, 1 - top - 0.01, "Pre-fit background") # draw the HT bin in upper middle text.SetTextAlign(21) text.SetTextFont(62) text.SetTextAngle(0) text.SetTextSize(0.035) # text.DrawLatex(left+(1-right-left)*0.5, 1-top-0.01-0.04, utils.GetHTtitle(ht_reg)) text.DrawLatex(left + (1 - right - left) * 0.3, 1 - top - 0.01 - 0.09, utils.GetMacroregionTitle(macro_reg)) # Draw the CMS and luminosity text ppmUtils.DrawCmsText(pads[0], text="CMS Preliminary", textSize=0.038) ppmUtils.DrawLumiText(pads[0], lumi=utils.lumi, textSize=0.038) # legend leg = ROOT.TLegend(1 - right - 0.175, 1 - top - 0.23, 1 - right - 0.02, 1 - top - 0.01) leg.SetBorderSize(1) leg.SetCornerRadius(0.3) leg.AddEntry(g_data, "Data", "lp") for i in range(nBkgs): leg.AddEntry(h_bkg_vec[i], utils.GetLegendName(bkg_processes[i]), 'f') leg.Draw() #################### #### RATIO PLOT #### #################### pads[1].cd() h_ratio = h_bkg_vec[0].Clone( "h_ratio") #h_ratio is just a dummy histogram to draw axes correctly h_ratio.Reset() g_ratio = ROOT.TGraphAsymmErrors() h_pred = h_bkg_tot.Clone("h_pred") ppmUtils.GetPoissonRatioGraph(h_pred, h_data, g_ratio, drawZeros=True, useMCErr=False) h_ratio.GetYaxis().SetRangeUser(0, 2) h_ratio.GetYaxis().SetNdivisions(505) h_ratio.GetYaxis().SetTitle("Data/Pred.") h_ratio.GetYaxis().SetTitleSize(0.16) h_ratio.GetYaxis().SetTitleOffset(0.25) h_ratio.GetYaxis().SetLabelSize(0.13) h_ratio.GetYaxis().CenterTitle() h_ratio.GetYaxis().SetTickLength(0.02) h_ratio.GetXaxis().SetLabelSize(0) h_ratio.GetXaxis().SetTitle("") #h_ratio.GetXaxis().SetNdivisions(nBinsTotal,0,0) h_ratio.GetXaxis().SetTickSize(0.06) g_ratio.SetMarkerStyle(20) g_ratio.SetMarkerSize(1.0) g_ratio.SetLineWidth(1) h_unc_ratio.SetFillStyle(1001) h_unc_ratio.SetFillColor(ROOT.kGray) h_ratio.Draw() h_unc_ratio.Draw("SAME E2") # draw line at 1 line = ROOT.TLine() line.SetLineStyle(1) line.SetLineWidth(1) line.SetLineColor(ROOT.kGray + 2) line.DrawLine(xbinsA[0], 1, xbinsA[len(xbinsA) - 1], 1) h_ratio.Draw("SAME AXIS") g_ratio.Draw("SAME P0") name = "MacroRegion_{0}".format(macro_reg) try: os.makedirs(outdir) except: pass c.SaveAs(os.path.join(outdir, name + ".pdf")) c.SaveAs(os.path.join(outdir, name + ".png")) h_data.Delete() g_data.Delete() h_ratio.Delete() g_ratio.Delete() for h in h_bkg_vec: h.Delete()
def plotDataMC(h_bkg_vec_, bkg_names, h_data=None, title=None, subtitles=None, ratioTitle=None, doRatio=False, yRangeUserRatio=None, scaleMCtoData=False, saveAs=None, isLog=True, dataTitle="Data", xRangeUser=None, doPause=False, lumi=1.0, lumiUnit="fb", noLumi=False, energy=13, xAxisTitle="H_{T}", xAxisUnit="GeV", userMax=None, userMin=None, doSort=False, doMT2Colors=False, markerSize=0.9, doOverflow=True, titleSize=0.04, subtitleSize=0.03, subLegText=None, subLegTextSize=0.03, cmsText="CMS Preliminary", cmsTextSize=0.035, doBkgError=False, functions=[], legCoords=None, doPull=False, convertToPoisson=False, drawZeros=True, drawSystematicBand=False, systematics=None, h_sig_vec=[], sig_names=[], customColors=None, verticalLines=[], ratioType=0): if h_data == None: doRatio = False scaleMCtoData = False if customColors!=None and len(customColors) < len(h_bkg_vec_): raise RuntimeError("Not enough colors for all backgrounds! {0} colors, {1} backgrounds.".format(len(customColors),len(h_bkg_vec_))) if drawSystematicBand and systematics==None: raise RuntimeError("Must supply a list of systematics to draw uncertainty band!") if systematics != None and len(systematics) != h_bkg_vec_[0].GetNbinsX(): raise RuntimeError("length of systematics list does not equal the number of bins!") # make shallow copies of hists so we don't overwrite the originals h_bkg_vec = [ROOT.TH1D() for h in h_bkg_vec_] for i in range(len(h_bkg_vec_)): h_bkg_vec_[i].Copy(h_bkg_vec[i]) if h_data != None: if type(h_data) != type(list()): h_data = [h_data] if len(h_data) > 4: print h_data raise RuntimeError("currently only supports up to 4 data histograms!") h_data_ = [ROOT.TH1D() for h in h_data] for i in range(len(h_data)): h_data[i].Copy(h_data_[i]) h_data[i] = h_data_[i] #so the arg name doesn't have underscore ROOT.gStyle.SetOptStat(0) #### setup canvas and pads #### c = ROOT.TCanvas() if doRatio: c.SetCanvasSize(700,600) pads = [] pads.append(ROOT.TPad("1","1",0.0,0.16,1.0,1.0)) pads.append(ROOT.TPad("2","2",0.0,0.0,1.0,0.17)) pads[0].SetTopMargin(0.08) pads[0].SetLeftMargin(0.12) pads[0].SetBottomMargin(0.10) pads[1].SetLeftMargin(0.12) pads[0].Draw() pads[1].Draw() pads[0].cd() else: c.SetCanvasSize(700,504) pads = [c] pads[0].SetLeftMargin(0.12) pads[0].SetTopMargin(0.08) if isLog: pads[0].SetLogy() pads[0].SetTicky(1) pads[0].cd() ## MC int_errors = [ROOT.Double(0) for i in range(len(h_bkg_vec))] integrals = [h_bkg_vec[i].IntegralAndError(0,-1,int_errors[i]) for i in range(len(h_bkg_vec))] if doSort: zipped = zip(h_bkg_vec,bkg_names) sorted_bkg = [x for (y,x) in sorted(zip(integrals,zipped))] h_bkg_vec = [x for (x,y) in sorted_bkg] bkg_names = [y for (x,y) in sorted_bkg] else: h_bkg_vec = h_bkg_vec[::-1] bkg_names = bkg_names[::-1] scaleFactor = 1.0 scaleFactorError = 1.0 if(h_data!=None and scaleMCtoData): tot_MC_error = ROOT.TMath.Sqrt(sum([x**2 for x in int_errors])) tot_MC_integral = sum(integrals) data_error = ROOT.Double(0) data_integral = h_data[0].IntegralAndError(0,-1,data_error) scaleFactor = data_integral/tot_MC_integral if data_integral > 0: scaleFactorError = scaleFactor * (data_error/data_integral + tot_MC_error/tot_MC_integral) else: scaleFactorError = 0.0 for i in range(len(h_bkg_vec)): h_bkg_vec[i].Scale(scaleFactor) dataMax = 0 if h_data!=None: for ih in range(len(h_data)): for i in range(1,h_data[ih].GetNbinsX()+1): y = h_data[ih].GetBinContent(i)+h_data[ih].GetBinError(i) if y>dataMax: dataMax = y sigMax = 0 if h_sig_vec!=None: for ih in range(len(h_sig_vec)): for i in range(1,h_sig_vec[ih].GetNbinsX()+1): y = h_sig_vec[ih].GetBinContent(i)+h_sig_vec[ih].GetBinError(i) if y>sigMax: sigMax = y stack = ROOT.THStack("hs","") plotBackgrounds(h_bkg_vec, bkg_names, canvas=pads[0], stack=stack, xRangeUser=xRangeUser, isLog=isLog, xAxisTitle=xAxisTitle, xAxisUnit=xAxisUnit, dataMax=dataMax, shallowCopy=False, userMax=userMax, userMin=userMin, doMT2Colors=doMT2Colors, doOverflow=doOverflow, sigMax=sigMax, customColors=customColors) if doBkgError: h_err = ROOT.TH1D() h_bkg_vec[0].Copy(h_err) for i in range(1,len(h_bkg_vec)): h_err.Add(h_bkg_vec[i]) h_err.SetFillStyle(3244) h_err.SetFillColor(ROOT.kGray+3) h_err.Draw("E2SAME") ## data if h_data != None: styles = [20,24,21,25] colors = [ROOT.kBlack,ROOT.kBlack,ROOT.kRed,ROOT.kBlack] N_DATA_EVENTS = [int(h.Integral(0,-1)) for h in h_data] #curretly only support counting of events for first histogram for ih in range(len(h_data)): h_data[ih].SetMarkerStyle(styles[ih]) h_data[ih].SetMarkerSize(markerSize) h_data[ih].SetMarkerColor(colors[ih]) h_data[ih].SetLineColor(colors[ih]) if xRangeUser!=None: h_data[ih].GetXaxis().SetRangeUser(*xRangeUser) if doOverflow: utils.PutOverflowInLastBin(h_data[ih], None if xRangeUser==None else xRangeUser[1]) if convertToPoisson: h_data_poisson = [ROOT.TGraphAsymmErrors() for h in h_data] for ih in range(len(h_data)-1,-1,-1): utils.ConvertToPoissonGraph(h_data[ih], h_data_poisson[ih], drawZeros=drawZeros) h_data_poisson[ih].SetMarkerStyle(styles[ih]) h_data_poisson[ih].SetMarkerSize(markerSize) h_data_poisson[ih].SetMarkerColor(colors[ih]) h_data_poisson[ih].SetLineColor(colors[ih]) h_data_poisson[ih].Draw("SAME PZ") else: for ih in range(len(h_data)-1,-1,-1): h_data[ih].Draw("SAME E0") ## functions for function in functions: function.Draw("SAME") ## signals #sig_cols = [ROOT.kMagenta, ROOT.kCyan, ROOT.kOrange+7, ROOT.kGreen] sig_cols = [ROOT.kGreen, ROOT.kYellow, ROOT.kMagenta, ROOT.kCyan] for isig in range(len(h_sig_vec)): h_sig_vec[isig].SetLineColor(sig_cols[isig]) #h_sig_vec[isig].SetLineWidth(2) h_sig_vec[isig].SetLineWidth(3) h_sig_vec[isig].SetLineStyle(7)#new h_sig_vec[isig].Draw("SAME HIST") ## draw vertical lines line = ROOT.TLine() line.SetLineWidth(2) line.SetLineColor(ROOT.kRed) for linex in verticalLines: lm = pads[0].GetLeftMargin() rm = pads[0].GetRightMargin() tm = pads[0].GetTopMargin() bm = pads[0].GetBottomMargin() if xRangeUser!=None: xrange = xRangeUser else: xrange = (h_bkg_vec[0].GetXaxis().GetXmin(), h_bkg_vec[0].GetXaxis().GetXmax()) xndc = lm + float(linex-xrange[0])/(xrange[1]-xrange[0]) * (1-rm-lm) line.DrawLineNDC(xndc,bm,xndc,1-tm) ## legend if legCoords == None: legCoords = (0.65,0.72,0.87,0.89) leg = ROOT.TLegend(*legCoords) leg.SetNColumns(2) leg.SetTextSize(0.035) leg.SetBorderSize(0); if h_data != None: if type(dataTitle) != type(list()): dataTitle = [dataTitle] for ih in range(len(h_data)): leg.AddEntry(h_data[ih],dataTitle[ih]) for i in range(len(h_bkg_vec)): leg.AddEntry(h_bkg_vec[-i-1],bkg_names[-i-1],"f") for i in range(len(h_sig_vec)): leg.AddEntry(h_sig_vec[i], sig_names[i], "l") leg.Draw() # handle all of the text text = ROOT.TLatex() text.SetNDC(1) cursorX = 0.23 cursorY = 0.89 # title if title!=None and title!="": text.SetTextAlign(13) text.SetTextFont(42) text.SetTextSize(titleSize) text.DrawLatex(cursorX,cursorY,title) cursorY -= titleSize + 0.010 # subtitles if subtitles==None: subtitles=[] if type(subtitles)==type(""): subtitles = [subtitles] for s in subtitles: text.SetTextAlign(13) text.SetTextFont(42) text.SetTextSize(subtitleSize) text.DrawLatex(cursorX,cursorY,s) cursorY -= subtitleSize + 0.015 # lumi if not noLumi: utils.DrawLumiText(pads[0],lumi=lumi,lumiUnit=lumiUnit,energy=energy,textFont=42,textSize=cmsTextSize) # CMS text #utils.DrawCmsText(pads[0],text=cmsText,textFont=62,textSize=cmsTextSize) #new plot text.SetTextFont(62) # text.SetTextSize(0.05) # text.SetTextAlign(11) # text.DrawLatexNDC(0.17, 0.84, "CMS") # text.SetTextFont(52) # text.SetTextSize(0.04) # text.SetTextAlign(13) # text.DrawLatexNDC(0.17, 0.83, "Preliminary") text.SetTextSize(0.04) text.SetTextAlign(11) text.DrawLatexNDC(0.13, 0.93, "CMS") #new text.SetTextFont(52) text.SetTextSize(0.04) text.SetTextAlign(11) text.DrawLatexNDC(0.2, 0.93, "Preliminary") # Sub-legend text cursorX = legCoords[0] cursorY = legCoords[1]-0.01 if subLegText==None: subLegText=[] if type(subLegText)==type(""): subLegText = [subLegText] for s in subLegText: if h_data==None: N_DATA_EVENTS = [0] vals = {"ndata":N_DATA_EVENTS[0], "datamcsf":scaleFactor, "datamcsferr":scaleFactorError} for i in range(len(N_DATA_EVENTS)): vals["ndata{0}".format(i+1)] = N_DATA_EVENTS[i] s = s.replace("{datamcsf}","{datamcsf:.2f}") s = s.replace("{datamcsferr}","{datamcsferr:.2f}") text.SetTextFont(62) text.SetTextAlign(13) text.SetTextSize(subLegTextSize) text.DrawLatex(cursorX,cursorY,s.format(**vals)) cursorY -= 0.03+0.005 ######## ratio plot ############ if doRatio: pads[1].cd() h1 = ROOT.TH1D() h_bkg_vec[0].Copy(h1) for i in range(len(h_bkg_vec)-1): h1.Add(h_bkg_vec[i+1]) ratioHist = [ROOT.TH1D() for h in h_data] ratioGraph = [ROOT.TGraphAsymmErrors() for h in h_data] h_syst = ROOT.TH1D() for ih,hd in list(enumerate(h_data))[::-1]: if ih==len(h_data)-1: plotRatio(h1, hd, canvas=pads[1], ratioHist=ratioHist[ih], ratioTitle=ratioTitle, xRangeUser=xRangeUser, markerSize=markerSize, markerStyle=hd.GetMarkerStyle(), markerColor=hd.GetMarkerColor(), doPull=doPull, convertToPoisson=convertToPoisson, ratioGraph=ratioGraph[ih], drawZeros=drawZeros, drawSystematicBand=drawSystematicBand, systematics=systematics, h_syst=h_syst) else: if ratioType==0: hden = h1 hnum = hd else: hden = hd hnum = h_data[0] plotRatio(hden, hnum, canvas=pads[1], ratioHist=ratioHist[ih], xRangeUser=xRangeUser, markerSize=markerSize, markerStyle=hd.GetMarkerStyle(), markerColor=hd.GetMarkerColor(), doPull=doPull, convertToPoisson=convertToPoisson, ratioGraph=ratioGraph[ih], drawZeros=drawZeros, justDrawPoints=True) c.Update() c.SetWindowSize(c.GetWw()+4, c.GetWh()+50) if saveAs!=None: c.SaveAs(saveAs) if doPause: raw_input()
def MakePlot(ht_reg, datacard_dir, datacard_name, outdir, userMax=None): jbj_regs = utils.GetJBJregions(ht_reg) #list of lists, one per jbj region, of low edges of MT2 bins mt2bins = utils.GetMT2bins(ht_reg) # nBinsTotal = sum([len(bins)-1 for bins in mt2bins]) + 1 nBinsTotal = sum([len(bins) - 1 for bins in mt2bins]) bkg_processes = ["zinv", "llep", "qcd"] nBkgs = len(bkg_processes) ## setup histograms h_data = ROOT.TH1D("h_data", "", nBinsTotal, 0, nBinsTotal) h_bkg_vec = [] for i, proc in enumerate(bkg_processes): h_bkg_vec.append(ROOT.TH1D("h_" + proc, "", nBinsTotal, 0, nBinsTotal)) g_unc = ROOT.TGraphAsymmErrors() # graph to store prediction uncertainties g_unc_ratio = ROOT.TGraphAsymmErrors( ) # graph to store prediction uncertainties ## fill histograms ibin = 0 binLabels = [] for ijbj, jbj_reg in enumerate(jbj_regs): for imt2 in range(len(mt2bins[ijbj]) - 1): ibin += 1 mt2left = mt2bins[ijbj][imt2] mt2right = mt2bins[ijbj][imt2 + 1] mt2name = utils.GetMT2name(mt2left, mt2right) if ht_reg != "monojet": datacard_name_fmt = datacard_name.format( ht_reg, jbj_reg, mt2name) else: ht_name = "HT{0}to{1}".format(mt2left, mt2right) ht_name = ht_name.replace("-1", "Inf") datacard_name_fmt = datacard_name.format( ht_name, jbj_reg, "m0toInf") # get yields. first entry is data, rest are background predictions yields = utils.GetYieldsFromDatacard( os.path.join(datacard_dir, datacard_name_fmt), bkg_processes) h_data.SetBinContent(ibin, yields[0]) for j in range(1, nBkgs + 1): h_bkg_vec[j - 1].SetBinContent(ibin, yields[j]) tot_pred = sum(yields[1:]) # get uncertainties pred_unc = utils.GetUncertaintiesFromDatacard( os.path.join(datacard_dir, datacard_name_fmt), bkg_processes) tot_unc_up = ROOT.TMath.Sqrt( sum([(pred_unc[i][0] * yields[i + 1])**2 for i in range(nBkgs)])) tot_unc_down = ROOT.TMath.Sqrt( sum([(pred_unc[i][1] * yields[i + 1])**2 for i in range(nBkgs)])) thisPoint = g_unc.GetN() g_unc.SetPoint(thisPoint, ibin - 0.5, tot_pred) g_unc.SetPointError(thisPoint, 0.5, 0.5, tot_unc_down, tot_unc_up) g_unc_ratio.SetPoint(thisPoint, ibin - 0.5, 1) g_unc_ratio.SetPointError(thisPoint, 0.5, 0.5, tot_unc_down / tot_pred, tot_unc_up / tot_pred) binLabels.append(utils.GetMT2label(mt2left, mt2right)) h_bkg_vec[0].SetFillColor(418) h_bkg_vec[1].SetFillColor(ROOT.kAzure + 4) h_bkg_vec[2].SetFillColor(401) stack = ROOT.THStack("bkg_stack", "") for j in range(nBkgs): h_bkg_vec[nBkgs - 1 - j].SetLineWidth(1) h_bkg_vec[nBkgs - 1 - j].SetLineColor(ROOT.kBlack) stack.Add(h_bkg_vec[nBkgs - 1 - j]) h_data.SetMarkerStyle(20) h_data.SetMarkerSize(1.3) h_data.SetMarkerColor(ROOT.kBlack) h_data.SetLineColor(ROOT.kBlack) ROOT.gStyle.SetOptStat(0) ROOT.gStyle.SetLineWidth(1) c = ROOT.TCanvas("c", "c", 900, 600) pads = [] pads.append(ROOT.TPad("1", "1", 0.0, 0.18, 1.0, 1.0)) pads.append(ROOT.TPad("2", "2", 0.0, 0.0, 1.0, 0.19)) pads[0].SetTopMargin(0.08) pads[0].SetBottomMargin(0.13) pads[0].SetRightMargin(0.05) pads[0].SetLeftMargin(0.10) pads[1].SetRightMargin(0.05) pads[1].SetLeftMargin(0.10) pads[0].Draw() pads[1].Draw() pads[0].cd() pads[0].SetLogy(1) # pads[0].SetTickx(1) pads[1].SetTickx(1) pads[0].SetTicky(1) pads[1].SetTicky(1) yMin = 1e-3 if userMax != None: yMax = userMax else: yMax = h_data.GetMaximum()**(2.0) h_data.GetYaxis().SetRangeUser(yMin, yMax) h_data.GetYaxis().SetTitle("Events / Bin") h_data.GetYaxis().SetTitleOffset(1.2) h_data.GetYaxis().SetTickLength(0.02) h_data.GetXaxis().SetRangeUser(0, nBinsTotal) h_data.GetXaxis().SetNdivisions(nBinsTotal, 0, 0) h_data.GetXaxis().SetLabelSize(0) h_data.GetXaxis().SetTickLength(0.015) # just draw dots to get axes. Will draw TGraphAsymmErrors on top later h_data.SetMarkerStyle(1) h_data.Draw("P") # draw the backgrounds stack.Draw("SAME HIST") # draw the prediction uncertainties g_unc.SetFillStyle(3244) g_unc.SetFillColor(ROOT.kGray + 3) g_unc.Draw("SAME 2") # get a graph using proper asymmetric poissonian errors g_data = ROOT.TGraphAsymmErrors() ppmUtils.ConvertToPoissonGraph(h_data, g_data, drawZeros=True) g_data.SetPointError(g_data.GetN() - 1, 0, 0, 0, 0) g_data.SetMarkerStyle(20) g_data.SetMarkerSize(1.2) g_data.SetLineWidth(1) # draw the graph and then axes again on top g_data.Draw("SAME P") h_data.Draw("SAME AXIS") # save for later left = pads[0].GetLeftMargin() right = pads[0].GetRightMargin() top = pads[0].GetTopMargin() bot = pads[0].GetBottomMargin() #draw the x-axis labels binWidth = (1.0 - right - left) / nBinsTotal text = ROOT.TLatex() text.SetNDC(1) text.SetTextAlign(32) text.SetTextAngle(90) text.SetTextSize(min(binWidth * 1.2, 0.026)) text.SetTextFont(62) for ibin in range(nBinsTotal - 1): x = left + (ibin + 0.5) * binWidth y = pads[0].GetBottomMargin() - 0.009 text.DrawLatex(x, y, binLabels[ibin]) # draw the "Pre-fit background" text text.SetTextAlign(13) text.SetTextFont(42) text.SetTextAngle(0) text.SetTextSize(0.05) text.DrawLatex(left + 0.04, 1 - top - 0.01, "Pre-fit background") # draw the HT bin in upper middle text.SetTextAlign(21) text.SetTextFont(62) text.SetTextAngle(0) text.SetTextSize(0.035) text.DrawLatex(left + (1 - right - left) * 0.5, 1 - top - 0.01 - 0.04, utils.GetHTtitle(ht_reg)) # Draw the CMS and luminosity text ppmUtils.DrawCmsText(pads[0], text="CMS Preliminary", textSize=0.038) ppmUtils.DrawLumiText(pads[0], lumi=utils.lumi, textSize=0.038) # draw the j/bj region labels ibin = 0 for ijbj, jbj_reg in enumerate(jbj_regs): xcenter = left + binWidth * (ibin + (len(mt2bins[ijbj]) - 1) * 0.5) lines = utils.GetJBJtitle(jbj_reg) text.SetTextAlign(23) text.SetTextFont(62) text.SetTextSize(0.030) # in the last region, move the text left a bit to avoid overlap with tick marks if ijbj == len(jbj_regs) - 1: text.SetTextAlign(13) xcenter = left + binWidth * ibin + 0.007 xcenter = max(xcenter, 1 - right - 0.25) y = bot + (1 - top - bot) * 0.85 if xcenter > 1 - right - 0.19: y = 0.67 text.DrawLatex(xcenter, y, lines[0]) text.DrawLatex(xcenter, y - text.GetTextSize() - 0.001, lines[1]) ibin += len(mt2bins[ijbj]) - 1 #draw the lines separating j-bj region line = ROOT.TLine() line.SetNDC(1) line.SetLineStyle(2) line.SetLineWidth(1) line.SetLineColor(ROOT.kBlack) ibin = 0 for i in range(len(jbj_regs) - 1): ibin += len(mt2bins[i]) - 1 x = left + binWidth * ibin line.DrawLineNDC(x, bot, x, bot + (1 - top - bot) * 0.85) # legend leg = ROOT.TLegend(1 - right - 0.175, 1 - top - 0.23, 1 - right - 0.02, 1 - top - 0.01) leg.SetBorderSize(1) leg.SetCornerRadius(0.3) leg.AddEntry(g_data, "Data", "lp") for i in range(nBkgs): leg.AddEntry(h_bkg_vec[i], utils.GetLegendName(bkg_processes[i]), 'f') leg.Draw() #################### #### RATIO PLOT #### #################### pads[1].cd() h_ratio = h_bkg_vec[0].Clone( "h_ratio") #h_ratio is just a dummy histogram to draw axes correctly h_ratio.Reset() g_ratio = ROOT.TGraphAsymmErrors() h_pred = h_bkg_vec[0].Clone("h_pred") for i in range(1, nBkgs): h_pred.Add(h_bkg_vec[i]) ppmUtils.GetPoissonRatioGraph(h_pred, h_data, g_ratio, drawZeros=True, useMCErr=False) h_ratio.GetYaxis().SetRangeUser(0, 2) h_ratio.GetYaxis().SetNdivisions(505) h_ratio.GetYaxis().SetTitle("Data/Pred.") h_ratio.GetYaxis().SetTitleSize(0.16) h_ratio.GetYaxis().SetTitleOffset(0.18) h_ratio.GetYaxis().SetLabelSize(0.13) h_ratio.GetYaxis().CenterTitle() h_ratio.GetYaxis().SetTickLength(0.02) h_ratio.GetXaxis().SetLabelSize(0) h_ratio.GetXaxis().SetTitle("") h_ratio.GetXaxis().SetNdivisions(nBinsTotal, 0, 0) h_ratio.GetXaxis().SetTickSize(0.06) g_ratio.SetMarkerStyle(20) g_ratio.SetMarkerSize(1.0) g_ratio.SetLineWidth(1) g_unc_ratio.SetFillStyle(1001) g_unc_ratio.SetFillColor(ROOT.kGray) h_ratio.Draw() g_unc_ratio.Draw("SAME 2") # draw line at 1 line = ROOT.TLine() line.SetLineStyle(1) line.SetLineWidth(1) line.SetLineColor(ROOT.kGray + 2) line.DrawLine(0, 1, nBinsTotal, 1) #draw the lines separating j-bj region line.SetNDC(1) line.SetLineStyle(2) line.SetLineWidth(1) line.SetLineColor(ROOT.kBlack) ibin = 0 for i in range(len(jbj_regs) - 1): ibin += len(mt2bins[i]) - 1 line.DrawLine(ibin, 0, ibin, 2) h_ratio.Draw("SAME AXIS") g_ratio.Draw("SAME P0") name = "prefit_{0}".format(ht_reg) try: os.makedirs(outdir) except: pass c.SaveAs(os.path.join(outdir, name + ".pdf")) c.SaveAs(os.path.join(outdir, name + ".png")) h_data.Delete() g_data.Delete() h_ratio.Delete() g_ratio.Delete() for h in h_bkg_vec: h.Delete()