def make_plot_all_rods(error_dict, rod_dict, name): leg = TLegend(0,0,0,0) if 'lock' in name: leg = TLegend(0.18,0.85,0.50,0.55) else: leg = TLegend(0.18,0.85,0.40,0.55) leg.SetLineColor(0) leg.SetFillStyle(0) leg.SetShadowColor(0) leg.SetBorderSize(0) leg.SetNColumns(3) gStyle.SetLegendTextSize(0.045) v_hists = [] #for e,c in zip(error_bits, error_colors): for e in error_bits: h = TH1F('h'+e,'h'+e, len(rod_dict), 0, len(rod_dict)) h.SetFillStyle(1001) h.SetLineWidth(0) v_hists.append(h) v_hists[-1].SetDirectory(0) if bin(int('0x'+e, 16))[2:].zfill(4) == '0111': leg.AddEntry(v_hists[-1],'GOL 3',"f"); elif bin(int('0x'+e, 16))[2:].zfill(4) == '1011': leg.AddEntry(v_hists[-1],'GOL 2',"f"); elif bin(int('0x'+e, 16))[2:].zfill(4) == '1101': leg.AddEntry(v_hists[-1],'GOL 1',"f"); elif bin(int('0x'+e, 16))[2:].zfill(4) == '1110': leg.AddEntry(v_hists[-1],'GOL 0',"f"); else: leg.AddEntry(v_hists[-1],bin(int('0x'+e, 16))[2:].zfill(4),"f"); h = leg.GetY2()-leg.GetY1(); w = leg.GetX2()-leg.GetX1()*.6; leg.SetMargin(leg.GetNColumns()*h/(leg.GetNRows()*w)) for key,val in error_dict.items(): idx_rod = 0 for i, key2 in enumerate(rod_dict): if key2 == key[:8]: idx_rod = i v_hists[int(key[11:12], 16)].Fill(idx_rod, val) stack = THStack("stack","stack") for hist in v_hists: stack.Add(hist) if 'buff' in name: c1 = TCanvas( 'c1', 'c1', 2000, 500) else: c1 = TCanvas( 'c1', 'c1', 1000, 500) h1 = TH1F('h_1','h_1', len(rod_dict), 0, len(rod_dict)) for i, key in enumerate(rod_dict): h1.GetXaxis().SetBinLabel(i+1,key) h1.SetBinContent(i+1,rod_dict[key]) h1.GetXaxis().LabelsOption("v") h1.GetXaxis().SetTitle("ROD") h1.GetXaxis().SetTitleOffset(2.2) h1.GetYaxis().SetTitle("# of rocketio errors") h1.SetLineColor(kRed) h1.SetLineWidth(1) leg.AddEntry(h1,'total',"l"); c1.SetBottomMargin(0.23) h1.GetXaxis().SetTitle("ROD") h1.Draw("HIST") stack.Draw("PFC PLC SAME HIST") h1.Draw("SAMEHIST") AtlasStyle.ATLAS_LABEL(0.19,.88, 1, "Internal") leg.Draw() c1.Update() c1.Print("plots/"+name +".pdf") c1.Clear()
def MakeLegend(can, x1=.8, y1=.8, x2=.9, y2=.9, textsize=18, ncolumns=1, totalentries=0, option='f', skip=[]): from ROOT import TLegend, TH1, gStyle, TGraph if can.GetPrimitive('pad_top'): MakeLegend(can.GetPrimitive('pad_top'), x1, y1, x2, y2, textsize, ncolumns, totalentries, skip=skip) return if CanvasEmpty(can): print 'Error: trying to make legend from canvas with 0 plots. Will do nothing.' return # # if a previous version exists from this function, delete it # if can.GetPrimitive('legend'): can.GetPrimitive('legend').Delete() leg = TLegend(x1, y1, x2, y2) leg.SetName('legend') tobject_collector.append(leg) leg.SetTextFont(43) leg.SetTextSize(textsize) leg.SetTextFont(43) leg.SetBorderSize(0) leg.SetFillStyle(0) leg.SetNColumns(ncolumns) # # Add by TH1 GetTitle() # the_primitives = can.GetListOfPrimitives() if can.GetPrimitive('pad_top'): the_primitives = can.GetPrimitive('pad_top').GetListOfPrimitives() if can.GetPrimitive('stack'): the_stack = list(reversed(list(can.GetPrimitive('stack').GetHists()))) the_primitives = the_stack + list(the_primitives) if type(option) == type(''): option = [option] * 100 total = 0 for i in the_primitives: if i.GetName() == 'stack': continue drawopt = i.GetDrawOption() if issubclass(type(i), TH1) or issubclass(type(i), TGraph): if i.GetTitle() in skip: continue leg.AddEntry(i, i.GetTitle(), option[total]) # plef total += 1 # # Add empty entries to ensure a standard layout # for i in range(100): if totalentries == 0: break if total >= totalentries: break leg.AddEntry(None, '', '') total += 1 # recipe for making roughly square boxes h = leg.GetY2() - leg.GetY1() w = leg.GetX2() - leg.GetX1() leg.SetMargin(leg.GetNColumns() * h / float(leg.GetNRows() * w)) can.cd() if can.GetPrimitive('pad_top'): can.GetPrimitive('pad_top').cd() leg.Draw() can.Modified() can.Update() return
normCMS.SetMaximum(0.3) leg = TLegend(0.4, 1. - gPad.GetTopMargin() - 0.03 - 0.18, 1. - gPad.GetRightMargin() - 0.02, 1. - gPad.GetTopMargin() - 0.03, '', 'NDC') leg.SetMargin(0.15) #leg.Dump() leg.SetFillStyle(0) leg.SetBorderSize(0) leg.AddEntry(normCMS, 'CMS, |y|<2, #sqrt{s}=7 TeV', 'pe') if (D0): D0.Draw('pz') leg.AddEntry(D0, 'D#oslash, |y|<1.8, #sqrt{s}=1.96 TeV', 'pe') else: leg.SetY1(1. - gPad.GetTopMargin() - 0.03 - 0.12) if (CDF): CDF.Draw('pz') leg.AddEntry(CDF, 'CDF, |y|<0.4, #sqrt{s}=1.8 TeV', 'pe') #leg.Dump() leg.Draw('same') l.DrawLatex(1.0 - gPad.GetRightMargin() - 0.04, leg.GetY1() - 0.06, '#varUpsilon(%iS)' % resonance) gPad.SetLogy() gPad.Update() normCMS.GetXaxis().SetTitle('p_{T} (GeV/c)') normCMS.GetYaxis().SetTitle('(d#sigma/dp_{T})/#sigma_{TOT} (GeV/c)^{-1}') normCMS.GetXaxis().SetLimits(0., 30.) gPad.Modified() gPad.Print('TevatronCompare%iS.eps' % resonance) gPad.Print('TevatronCompare%iS.png' % resonance) gPad.Print('TevatronCompare%iS.pdf' % resonance)
def dijet(category): channel = 'bb' stype = channel isSB = True # relict from using Alberto's more complex script isData = not ISMC nTupleDir = NTUPLEDIR samples = data if isData else back pd = [] for sample_name in samples: if YEAR == 'run2': pd += sample[sample_name]['files'] else: pd += [x for x in sample[sample_name]['files'] if YEAR in x] print "datasets:", pd if not os.path.exists(PLOTDIR): os.makedirs(PLOTDIR) if BIAS: print "Running in BIAS mode" order = 0 RSS = {} X_mass = RooRealVar("jj_mass_widejet", "m_{jj}", X_min, X_max, "GeV") weight = RooRealVar("MANtag_weight", "", -1.e9, 1.e9) variables = RooArgSet(X_mass) variables.add(RooArgSet(weight)) if VARBINS: binsXmass = RooBinning(len(abins) - 1, abins) X_mass.setBinning(RooBinning(len(abins_narrow) - 1, abins_narrow)) plot_binning = RooBinning( int((X_mass.getMax() - X_mass.getMin()) / 100), X_mass.getMin(), X_mass.getMax()) else: X_mass.setBins(int((X_mass.getMax() - X_mass.getMin()) / 10)) binsXmass = RooBinning(int((X_mass.getMax() - X_mass.getMin()) / 100), X_mass.getMin(), X_mass.getMax()) plot_binning = binsXmass baseCut = "" print stype, "|", baseCut print " - Reading from Tree" treeBkg = TChain("tree") for ss in pd: if os.path.exists(nTupleDir + ss + "_" + BTAGGING + ".root"): treeBkg.Add(nTupleDir + ss + "_" + BTAGGING + ".root") else: print "found no file for sample:", ss setData = RooDataSet("setData", "Data (QCD+TTbar MC)", variables, RooFit.Cut(baseCut), RooFit.WeightVar(weight), RooFit.Import(treeBkg)) nevents = setData.sumEntries() dataMin, dataMax = array('d', [0.]), array('d', [0.]) setData.getRange(X_mass, dataMin, dataMax) xmin, xmax = dataMin[0], dataMax[0] lastBin = X_mass.getMax() if VARBINS: for b in narrow_bins: if b > xmax: lastBin = b break print "Imported", ( "data" if isData else "MC" ), "RooDataSet with", nevents, "events between [%.1f, %.1f]" % (xmin, xmax) #xmax = xmax+binsXmass.averageBinWidth() # start form next bin # 1 parameter print "fitting 1 parameter model" p1_1 = RooRealVar("CMS" + YEAR + "_" + category + "_p1_1", "p1", 7.0, 0., 2000.) modelBkg1 = RooGenericPdf("Bkg1", "Bkg. fit (2 par.)", "1./pow(@0/13000, @1)", RooArgList(X_mass, p1_1)) normzBkg1 = RooRealVar( modelBkg1.GetName() + "_norm", "Number of background events", nevents, 0., 5. * nevents) #range dependent of actual number of events! modelExt1 = RooExtendPdf(modelBkg1.GetName() + "_ext", modelBkg1.GetTitle(), modelBkg1, normzBkg1) fitRes1 = modelExt1.fitTo(setData, RooFit.Extended(True), RooFit.Save(1), RooFit.SumW2Error(not isData), RooFit.Strategy(2), RooFit.Minimizer("Minuit2"), RooFit.PrintLevel(1 if VERBOSE else -1)) fitRes1.Print() RSS[1] = drawFit("Bkg1", category, X_mass, modelBkg1, setData, binsXmass, [fitRes1], normzBkg1.getVal()) # 2 parameters print "fitting 2 parameter model" p2_1 = RooRealVar("CMS" + YEAR + "_" + category + "_p2_1", "p1", 0., -100., 1000.) p2_2 = RooRealVar("CMS" + YEAR + "_" + category + "_p2_2", "p2", p1_1.getVal(), -100., 600.) modelBkg2 = RooGenericPdf("Bkg2", "Bkg. fit (3 par.)", "pow(1-@0/13000, @1) / pow(@0/13000, @2)", RooArgList(X_mass, p2_1, p2_2)) normzBkg2 = RooRealVar(modelBkg2.GetName() + "_norm", "Number of background events", nevents, 0., 5. * nevents) modelExt2 = RooExtendPdf(modelBkg2.GetName() + "_ext", modelBkg2.GetTitle(), modelBkg2, normzBkg2) fitRes2 = modelExt2.fitTo(setData, RooFit.Extended(True), RooFit.Save(1), RooFit.SumW2Error(not isData), RooFit.Strategy(2), RooFit.Minimizer("Minuit2"), RooFit.PrintLevel(1 if VERBOSE else -1)) fitRes2.Print() RSS[2] = drawFit("Bkg2", category, X_mass, modelBkg2, setData, binsXmass, [fitRes2], normzBkg2.getVal()) # 3 parameters print "fitting 3 parameter model" p3_1 = RooRealVar("CMS" + YEAR + "_" + category + "_p3_1", "p1", p2_1.getVal(), -2000., 2000.) p3_2 = RooRealVar("CMS" + YEAR + "_" + category + "_p3_2", "p2", p2_2.getVal(), -400., 2000.) p3_3 = RooRealVar("CMS" + YEAR + "_" + category + "_p3_3", "p3", -2.5, -500., 500.) modelBkg3 = RooGenericPdf( "Bkg3", "Bkg. fit (4 par.)", "pow(1-@0/13000, @1) / pow(@0/13000, @2+@3*log(@0/13000))", RooArgList(X_mass, p3_1, p3_2, p3_3)) normzBkg3 = RooRealVar(modelBkg3.GetName() + "_norm", "Number of background events", nevents, 0., 5. * nevents) modelExt3 = RooExtendPdf(modelBkg3.GetName() + "_ext", modelBkg3.GetTitle(), modelBkg3, normzBkg3) fitRes3 = modelExt3.fitTo(setData, RooFit.Extended(True), RooFit.Save(1), RooFit.SumW2Error(not isData), RooFit.Strategy(2), RooFit.Minimizer("Minuit2"), RooFit.PrintLevel(1 if VERBOSE else -1)) fitRes3.Print() RSS[3] = drawFit("Bkg3", category, X_mass, modelBkg3, setData, binsXmass, [fitRes3], normzBkg3.getVal()) # 4 parameters print "fitting 4 parameter model" p4_1 = RooRealVar("CMS" + YEAR + "_" + category + "_p4_1", "p1", p3_1.getVal(), -2000., 2000.) p4_2 = RooRealVar("CMS" + YEAR + "_" + category + "_p4_2", "p2", p3_2.getVal(), -2000., 2000.) p4_3 = RooRealVar("CMS" + YEAR + "_" + category + "_p4_3", "p3", p3_3.getVal(), -50., 50.) p4_4 = RooRealVar("CMS" + YEAR + "_" + category + "_p4_4", "p4", 0.1, -50., 50.) modelBkg4 = RooGenericPdf( "Bkg4", "Bkg. fit (5 par.)", "pow(1 - @0/13000, @1) / pow(@0/13000, @2+@3*log(@0/13000)+@4*pow(log(@0/13000), 2))", RooArgList(X_mass, p4_1, p4_2, p4_3, p4_4)) normzBkg4 = RooRealVar(modelBkg4.GetName() + "_norm", "Number of background events", nevents, 0., 5. * nevents) modelExt4 = RooExtendPdf(modelBkg4.GetName() + "_ext", modelBkg4.GetTitle(), modelBkg4, normzBkg4) fitRes4 = modelExt4.fitTo(setData, RooFit.Extended(True), RooFit.Save(1), RooFit.SumW2Error(not isData), RooFit.Strategy(2), RooFit.Minimizer("Minuit2"), RooFit.PrintLevel(1 if VERBOSE else -1)) fitRes4.Print() RSS[4] = drawFit("Bkg4", category, X_mass, modelBkg4, setData, binsXmass, [fitRes4], normzBkg4.getVal()) # Normalization parameters are should be set constant, but shape ones should not # if BIAS: # p1_1.setConstant(True) # p2_1.setConstant(True) # p2_2.setConstant(True) # p3_1.setConstant(True) # p3_2.setConstant(True) # p3_3.setConstant(True) # p4_1.setConstant(True) # p4_2.setConstant(True) # p4_3.setConstant(True) # p4_4.setConstant(True) normzBkg1.setConstant(True) normzBkg2.setConstant(True) normzBkg3.setConstant(True) normzBkg4.setConstant(True) #*******************************************************# # # # Fisher # # # #*******************************************************# # Fisher test with open(PLOTDIR + "/Fisher_" + category + ".tex", 'w') as fout: fout.write(r"\begin{tabular}{c|c|c|c|c}") fout.write("\n") fout.write(r"function & $\chi^2$ & RSS & ndof & F-test \\") fout.write("\n") fout.write("\hline") fout.write("\n") CL_high = False for o1 in range(1, 5): o2 = min(o1 + 1, 5) fout.write("%d par & %.2f & %.2f & %d & " % (o1 + 1, RSS[o1]["chi2"], RSS[o1]["rss"], RSS[o1]["nbins"] - RSS[o1]["npar"])) if o2 > len(RSS): fout.write(r"\\") fout.write("\n") continue #order==0 and CL = fisherTest(RSS[o1]['rss'], RSS[o2]['rss'], o1 + 1., o2 + 1., RSS[o1]["nbins"]) fout.write("CL=%.3f " % (CL)) if CL > 0.10: # The function with less parameters is enough if not CL_high: order = o1 #fout.write( "%d par are sufficient " % (o1+1)) CL_high = True else: #fout.write( "%d par are needed " % (o2+1)) if not CL_high: order = o2 fout.write(r"\\") fout.write("\n") fout.write("\hline") fout.write("\n") fout.write(r"\end{tabular}") print "saved F-test table as", PLOTDIR + "/Fisher_" + category + ".tex" #print "-"*25 #print "function & $\\chi^2$ & RSS & ndof & F-test & result \\\\" #print "\\multicolumn{6}{c}{", "Zprime_to_bb", "} \\\\" #print "\\hline" #CL_high = False #for o1 in range(1, 5): # o2 = min(o1 + 1, 5) # print "%d par & %.2f & %.2f & %d & " % (o1+1, RSS[o1]["chi2"], RSS[o1]["rss"], RSS[o1]["nbins"]-RSS[o1]["npar"]), # if o2 > len(RSS): # print "\\\\" # continue #order==0 and # CL = fisherTest(RSS[o1]['rss'], RSS[o2]['rss'], o1+1., o2+1., RSS[o1]["nbins"]) # print "%d par vs %d par CL=%f & " % (o1+1, o2+1, CL), # if CL > 0.10: # The function with less parameters is enough # if not CL_high: # order = o1 # print "%d par are sufficient" % (o1+1), # CL_high=True # else: # print "%d par are needed" % (o2+1), # if not CL_high: # order = o2 # print "\\\\" #print "\\hline" #print "-"*25 #print "@ Order is", order, "("+category+")" #order = min(3, order) #order = 2 if order == 1: modelBkg = modelBkg1 #.Clone("Bkg") modelAlt = modelBkg2 #.Clone("BkgAlt") normzBkg = normzBkg1 #.Clone("Bkg_norm") fitRes = fitRes1 elif order == 2: modelBkg = modelBkg2 #.Clone("Bkg") modelAlt = modelBkg3 #.Clone("BkgAlt") normzBkg = normzBkg2 #.Clone("Bkg_norm") fitRes = fitRes2 elif order == 3: modelBkg = modelBkg3 #.Clone("Bkg") modelAlt = modelBkg4 #.Clone("BkgAlt") normzBkg = normzBkg3 #.Clone("Bkg_norm") fitRes = fitRes3 elif order == 4: modelBkg = modelBkg4 #.Clone("Bkg") modelAlt = modelBkg3 #.Clone("BkgAlt") normzBkg = normzBkg4 #.Clone("Bkg_norm") fitRes = fitRes4 else: print "Functions with", order + 1, "or more parameters are needed to fit the background" exit() modelBkg.SetName("Bkg_" + YEAR + "_" + category) modelAlt.SetName("Alt_" + YEAR + "_" + category) normzBkg.SetName("Bkg_" + YEAR + "_" + category + "_norm") print "-" * 25 # Generate pseudo data setToys = RooDataSet() setToys.SetName("data_toys") setToys.SetTitle("Data (toys)") if not isData: print " - Generating", nevents, "events for toy data" setToys = modelBkg.generate(RooArgSet(X_mass), nevents) #setToys = modelAlt.generate(RooArgSet(X_mass), nevents) print "toy data generated" if VERBOSE: raw_input("Press Enter to continue...") #*******************************************************# # # # Plot # # # #*******************************************************# print "starting to plot" c = TCanvas("c_" + category, category, 800, 800) c.Divide(1, 2) setTopPad(c.GetPad(1), RATIO) setBotPad(c.GetPad(2), RATIO) c.cd(1) frame = X_mass.frame() setPadStyle(frame, 1.25, True) if VARBINS: frame.GetXaxis().SetRangeUser(X_mass.getMin(), lastBin) signal = getSignal( category, stype, 2000) #replacing Alberto's getSignal by own dummy function graphData = setData.plotOn(frame, RooFit.Binning(plot_binning), RooFit.Scaling(False), RooFit.Invisible()) modelBkg.plotOn(frame, RooFit.VisualizeError(fitRes, 1, False), RooFit.LineColor(602), RooFit.FillColor(590), RooFit.FillStyle(1001), RooFit.DrawOption("FL"), RooFit.Name("1sigma")) modelBkg.plotOn(frame, RooFit.LineColor(602), RooFit.FillColor(590), RooFit.FillStyle(1001), RooFit.DrawOption("L"), RooFit.Name(modelBkg.GetName())) modelAlt.plotOn(frame, RooFit.LineStyle(7), RooFit.LineColor(613), RooFit.FillColor(609), RooFit.FillStyle(1001), RooFit.DrawOption("L"), RooFit.Name(modelAlt.GetName())) if not isSB and signal[0] is not None: # FIXME remove /(2./3.) signal[0].plotOn( frame, RooFit.Normalization(signal[1] * signal[2], RooAbsReal.NumEvent), RooFit.LineStyle(3), RooFit.LineWidth(6), RooFit.LineColor(629), RooFit.DrawOption("L"), RooFit.Name("Signal")) graphData = setData.plotOn( frame, RooFit.Binning(plot_binning), RooFit.Scaling(False), RooFit.XErrorSize(0 if not VARBINS else 1), RooFit.DataError(RooAbsData.Poisson if isData else RooAbsData.SumW2), RooFit.DrawOption("PE0"), RooFit.Name(setData.GetName())) fixData(graphData.getHist(), True, True, not isData) pulls = frame.pullHist(setData.GetName(), modelBkg.GetName(), True) chi = frame.chiSquare(setData.GetName(), modelBkg.GetName(), True) #setToys.plotOn(frame, RooFit.DataError(RooAbsData.Poisson), RooFit.DrawOption("PE0"), RooFit.MarkerColor(2)) frame.GetYaxis().SetTitle("Events / ( 100 GeV )") frame.GetYaxis().SetTitleOffset(1.05) frame.Draw() #print "frame drawn" # Get Chi2 # chi2[1] = frame.chiSquare(modelBkg1.GetName(), setData.GetName()) # chi2[2] = frame.chiSquare(modelBkg2.GetName(), setData.GetName()) # chi2[3] = frame.chiSquare(modelBkg3.GetName(), setData.GetName()) # chi2[4] = frame.chiSquare(modelBkg4.GetName(), setData.GetName()) frame.SetMaximum(frame.GetMaximum() * 10) frame.SetMinimum(max(frame.GetMinimum(), 1.e-1)) c.GetPad(1).SetLogy() drawAnalysis(category) drawRegion(category, True) #drawCMS(LUMI, "Simulation Preliminary") drawCMS(LUMI, "Work in Progress", suppressCMS=True) leg = TLegend(0.575, 0.6, 0.95, 0.9) leg.SetBorderSize(0) leg.SetFillStyle(0) #1001 leg.SetFillColor(0) leg.AddEntry(setData.GetName(), setData.GetTitle() + " (%d events)" % nevents, "PEL") leg.AddEntry(modelBkg.GetName(), modelBkg.GetTitle(), "FL") #.SetTextColor(629) leg.AddEntry(modelAlt.GetName(), modelAlt.GetTitle(), "L") if not isSB and signal[0] is not None: leg.AddEntry("Signal", signal[0].GetTitle(), "L") leg.SetY1(0.9 - leg.GetNRows() * 0.05) leg.Draw() latex = TLatex() latex.SetNDC() latex.SetTextSize(0.04) latex.SetTextFont(42) if not isSB: latex.DrawLatex(leg.GetX1() * 1.16, leg.GetY1() - 0.04, "HVT model B (g_{V}=3)") # latex.DrawLatex(0.67, leg.GetY1()-0.045, "#sigma_{X} = 1.0 pb") c.cd(2) frame_res = X_mass.frame() setPadStyle(frame_res, 1.25) frame_res.addPlotable(pulls, "P") setBotStyle(frame_res, RATIO, False) if VARBINS: frame_res.GetXaxis().SetRangeUser(X_mass.getMin(), lastBin) frame_res.GetYaxis().SetRangeUser(-5, 5) frame_res.GetYaxis().SetTitle("pulls(#sigma)") frame_res.GetYaxis().SetTitleOffset(0.3) frame_res.Draw() fixData(pulls, False, True, False) drawChi2(RSS[order]["chi2"], RSS[order]["nbins"] - (order + 1), True) line = drawLine(X_mass.getMin(), 0, lastBin, 0) if VARBINS: c.SaveAs(PLOTDIR + "/BkgSR_" + category + ".pdf") c.SaveAs(PLOTDIR + "/BkgSR_" + category + ".png") else: c.SaveAs(PLOTDIR + "/BkgSR_" + category + ".pdf") c.SaveAs(PLOTDIR + "/BkgSR_" + category + ".png") #*******************************************************# # # # Generate workspace # # # #*******************************************************# if BIAS: gSystem.Load("libHiggsAnalysisCombinedLimit.so") from ROOT import RooMultiPdf cat = RooCategory("pdf_index", "Index of Pdf which is active") pdfs = RooArgList(modelBkg, modelAlt) roomultipdf = RooMultiPdf("roomultipdf", "All Pdfs", cat, pdfs) normulti = RooRealVar("roomultipdf_norm", "Number of background events", nevents, 0., 1.e6) normzBkg.setConstant( False ) ## newly put here to ensure it's freely floating in the combine fit # create workspace w = RooWorkspace("Zprime_" + YEAR, "workspace") # Dataset if isData: getattr(w, "import")(setData, RooFit.Rename("data_obs")) else: getattr(w, "import")(setToys, RooFit.Rename("data_obs")) #getattr(w, "import")(setData, RooFit.Rename("data_obs")) if BIAS: getattr(w, "import")(cat, RooFit.Rename(cat.GetName())) getattr(w, "import")(normulti, RooFit.Rename(normulti.GetName())) getattr(w, "import")(roomultipdf, RooFit.Rename(roomultipdf.GetName())) getattr(w, "import")(modelBkg, RooFit.Rename(modelBkg.GetName())) getattr(w, "import")(modelAlt, RooFit.Rename(modelAlt.GetName())) getattr(w, "import")(normzBkg, RooFit.Rename(normzBkg.GetName())) w.writeToFile(WORKDIR + "%s_%s.root" % (DATA_TYPE + "_" + YEAR, category), True) print "Workspace", WORKDIR + "%s_%s.root" % ( DATA_TYPE + "_" + YEAR, category), "saved successfully" if VERBOSE: raw_input("Press Enter to continue...")
def checkDataPoissonErrors(): '''Check on behaviour of Poisson errors in histograms.''' N = 100 hist0 = TH1D("data0", "default", N, 0, N) hist1 = TH1D("data1", "TH1.kPoisson", N, 0, N) hist2 = TH1D("data2", "#chi^{2} quantile", N, 0, N) for i in xrange(0, N + 2): y = max(0, i - 1) hist0.SetBinContent(i, y) hist1.SetBinContent(i, y) hist2.SetBinContent(i, y) # GET data Possoin errors graph1 = getDataPoissonErrors(hist1, drawZeroBins=True, centerBin=False, kPoisson=True) graph2 = getDataPoissonErrors(hist2, drawZeroBins=True, centerBin=False, kPoisson=False) # FILL table table = [] table.append( "%22s %14s %14s %14s" % (" ", "default".center(14), "kPoisson".center(14), "chi^2".center(14))) table.append("%4s %7s %7s %6s %6s %6s %6s %6s %6s" % ("bin", "content", "sqrt(N)", "errLow", "errUp", "errLow", "errUp", "errLow", "errUp")) for i in xrange(1, N + 1): y = hist0.GetBinContent(i) table.append( "%4d %5d %7.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f" % (i, y, sqrt(y), hist0.GetBinErrorLow(i), hist0.GetBinErrorUp(i), graph1.GetErrorYlow(i - 1), graph1.GetErrorYhigh(i - 1), graph2.GetErrorYlow(i - 1), graph2.GetErrorYhigh(i - 1))) # PRINT table for line in table: print ">>> " + line print ">>> " # GRAPHS function = TF1("function1", "sqrt(x)", 0, N) function.SetTitle("#sqrt{N}") graphElow1, graphEup1 = makeErrorGraph(graph1) graphElow2, graphEup2 = makeErrorGraph(graph2) graphElow1.SetTitle("TH1.kPoisson low") graphEup1.SetTitle("TH1.kPoisson high") graphElow2.SetTitle("N-F^{-1}_{#chi^{2}}(1-#alpha,2N)/2") graphEup2.SetTitle("F^{-1}_{#chi^{2}}(#alpha,2(N-1))/2-N") graphs = [function, graphElow1, graphEup1, graphElow2, graphEup2] # DRAW settings W, H = 800, 800 T, B = 0.04 * H, 0.14 * H L, R = 0.12 * W, 0.04 * W xmin, xmax = -N * 0.01, N * 1.01 ymax = function.GetMaximum() * 1.16 width = 0.25 legendTextSize = 0.045 height = 0.062 * (1 + len(graphs)) x2 = 0.86 x1 = x2 - width y1 = 0.20 y2 = y1 + height # CANVAS canvas = TCanvas("canvas", "canvas", 100, 100, W, H) canvas.Divide(2) canvas.cd(1) gPad.SetPad("pad1", "pad1", 0, 0.37, 1, 1, 0, -1, 0) gPad.SetTopMargin(T / H) gPad.SetBottomMargin(0.01) gPad.SetLeftMargin(L / W) gPad.SetRightMargin(R / W) gPad.SetTickx(0) gPad.SetTicky(0) gPad.SetGrid() # FRAME frame = gPad.DrawFrame(xmin, 0, xmax, ymax) frame.GetYaxis().SetTitleSize(0.055) frame.GetXaxis().SetTitleSize(0.058) frame.GetXaxis().SetLabelSize(0.050 * 0) frame.GetYaxis().SetLabelSize(0.053) frame.GetXaxis().SetLabelOffset(0.012) frame.GetXaxis().SetTitleOffset(1.02) frame.GetYaxis().SetTitleOffset(1.08) frame.GetXaxis().SetNdivisions(505) frame.GetXaxis().SetTitle("number of events") frame.GetYaxis().SetTitle("error on number of events") legend = TLegend(x1, y1, x2, y2) # DRAW colors = [kRed, kBlue, kViolet, kYellow, kGreen] for i, graph in enumerate(graphs): style = kSolid width = 2 if i < 3: width = 3 if i > 2: style = kDashed graph.SetLineColor(colors[i % len(colors)]) graph.SetLineStyle(style) graph.SetLineWidth(width) graph.Draw('L SAME') legend.AddEntry(graph, graph.GetTitle(), 'L') #CMS_lumi.CMS_lumi(gPad,13,0) gPad.SetTicks(1, 1) gPad.Modified() frame.Draw('SAME AXIS') # LEGEND legend.SetFillStyle(0) legend.SetBorderSize(0) legend.SetTextSize(legendTextSize) legend.SetTextFont(62) legend.SetHeader("method") legend.SetTextFont(42) legend.Draw() # CHI2 TEXT text1 = "#splitline{#alpha = (1-0.6827)/2}{upper #chi^{2} CDF F_{#chi^{2}}}" text = TLatex() text.SetNDC() text.SetTextFont(42) text.SetTextSize(legendTextSize) text.SetTextAlign(13) # centered: 22 xoffset = (legend.GetX2() - legend.GetX1()) * legend.GetMargin() * 1.04 text.DrawLatexNDC(legend.GetX1() + xoffset, legend.GetY1() - 0.012, text1) # RATIO plot canvas.cd(2) gPad.SetPad("pad2", "pad2", 0, 0, 1, 0.36, 0, -1, 0) gPad.SetTopMargin(0.05) gPad.SetBottomMargin(0.24) gPad.SetLeftMargin(L / W) gPad.SetRightMargin(R / W) # FRAME ratio frame_ratio = gPad.DrawFrame(xmin, 0.50, xmax, 1.50) frame_ratio.GetYaxis().CenterTitle() frame_ratio.GetYaxis().SetTitleSize(0.055 * 1.79) frame_ratio.GetXaxis().SetTitleSize(0.058 * 1.79) frame_ratio.GetXaxis().SetLabelSize(0.052 * 1.79) frame_ratio.GetYaxis().SetLabelSize(0.050 * 1.79) frame_ratio.GetXaxis().SetLabelOffset(0.012) frame_ratio.GetXaxis().SetTitleOffset(1.00) frame_ratio.GetYaxis().SetTitleOffset(0.63) frame_ratio.GetXaxis().SetNdivisions(508) frame_ratio.GetYaxis().CenterTitle(True) frame_ratio.GetYaxis().SetTitle("ratio") frame_ratio.GetXaxis().SetTitle("number of events N") frame_ratio.GetYaxis().SetNdivisions(5) # DRAW ratio ratios = [] graphf = makeGraphFromTF1(function, N) for i, graph in enumerate(graphs): if isinstance(graph, TF1): graph = makeGraphFromTF1(graph, N) ratio = makeRatioTGraphs(graph, graphf) ratio.SetLineColor(graph.GetLineColor()) ratio.SetLineStyle(graph.GetLineStyle()) ratio.SetLineWidth(graph.GetLineWidth()) ratio.Draw('L SAME') ratios.append(ratio) gPad.SetTicks(1, 1) gPad.Modified() frame_ratio.Draw('sameaxis') # SAVE canvas.SaveAs("PoissonError.png") canvas.Close()
class ROOTPlot(PlotSpec): # pylint: disable=too-many-instance-attributes """ROOT specific implementation of PlotSpec """ def __init__(self, **kwargs): super().__init__() # copy member variables from orig PlotSpec self.copy(kwargs.pop("orig", None)) # It's a ROOT object and we control its name self.name = None # frame constructed to provide axes self.frame = None # ROOT objects self.objects = None # Styles to be used for the styles self.styles = None # text to be added self.pave_boxes = None # legend self.root_legend = None # labels of objects added to this ROOTPlot self.labels = None # lines added self._root_lines = [] # TPad used for the plot self.pad = None # TODO: use PlotSpec's relative coordinates self.size = (300, 300) def __draw_objects(self): """Draw all objects """ for obj, sty in zip(self.objects, self.styles): # adjust draw_option to always contain "same" in addition to # user specified options draw_option = "same" if not sty else f"same {sty.draw_options}" obj.Draw(draw_option) def __draw_lines(self): """Draw all lines """ for l in self._lines: x_low = l.x_low x_up = l.x_up if l.x_orientation == "relative": x_range = self._axes[0].limits[1] - self._axes[0].limits[0] x_low = self._axes[0].limits[0] + l.x_low * x_range x_up = self._axes[0].limits[0] + l.x_up * x_range y_low = l.y_low y_up = l.y_up if l.y_orientation == "relative": y_range = self._axes[1].limits[1] - self._axes[1].limits[0] y_low = self._axes[1].limits[0] + l.y_low * y_range y_up = self._axes[1].limits[0] + l.y_up * y_range line = TLine(x_low, y_low, x_up, y_up) apply_line_style(line, l.style) line.Draw() self._root_lines.append(line) def __draw_legends(self): """Encapsulate legend drawing """ if self.root_legend: self.root_legend.Draw() def __style_objects(self, **kwargs): """Style all objects to be plotted Args: kwargs: dict "keep_stats" to keep potential stats boxes associated with e.g. histograms """ # TODO Make that static again keep_stats = kwargs.pop("keep_stats", False) #scale = sqrt(self.size[0] * self.size[1] / SCALE_BASE) for obj, style in zip(self.objects, self.styles): style_object(obj, style) # , scale) if not keep_stats: try_method(obj, "SetStats", 0) def add_object(self, root_object, style=None, label=None): """Add a ROOT object to be plotted inside this ROOTPlot Args: object: ROOT object to be added style: either Style or None, default None label: str to appear in the legend or None, default None """ # Prepare lists if not self.objects: self.objects = [] if not self.styles: self.styles = [] if not self.labels: self.labels = [] # clone the ROOT object and don't touch the original one self.objects.append(clone_root(root_object)) self.styles.append(style) self.labels.append(label) def __create_frame(self, **kwargs): """Make the frame used to plot the axes Args: kwargs: dict x_axis_title: str for x-axis title y_axis_title: str for x-axis title use_any_titles: bool whether or not to use any titles defined for any of the ROOT objects in case title for x- or y-axis are not specified by the user """ self._axes[0].title = kwargs.pop("x_axis_title", self._axes[0].title) self._axes[1].title = kwargs.pop("y_axis_title", self._axes[1].title) use_any_titles = kwargs.pop("use_any_titles", True) # pylint: disable=protected-access x_force_limits = False if self._share_x: self._axes[0].limits[0] = self._share_x._axes[0].limits[0] self._axes[0].limits[1] = self._share_x._axes[0].limits[1] x_force_limits = True y_force_limits = False if self._share_y: self._axes[1].limits[0] = self._share_y._axes[1].limits[0] self._axes[1].limits[1] = self._share_y._axes[1].limits[1] y_force_limits = True # pylint: enable=protected-access # Find the x- and y-limits for this plot x_low, x_up, y_low, y_up, z_low, z_up = \ find_boundaries(self.objects, self._axes[0].limits[0], self._axes[0].limits[1], self._axes[1].limits[0], self._axes[1].limits[1], self._axes[2].limits[0], self._axes[2].limits[1], reserve_ndc_top=kwargs.pop("reserve_ndc_top", None), reserve_ndc_bottom=kwargs.pop("reserve_ndc_bottom", None), x_force_limits=x_force_limits, y_force_limits=y_force_limits, x_log=self._axes[0].is_log, y_log=self._axes[1].is_log, y_account_for_errors=self._axes[1].account_for_errors) # add titles to axes if not specified by the user by trying to # use those which are set for any ROOT object if use_any_titles and \ (not self._axes[0].title or not self._axes[1].title): for obj in self.objects: if not self._axes[0].title and hasattr(obj, "GetXaxis"): self._axes[0].title = obj.GetXaxis().GetTitle() if not self._axes[1].title and hasattr(obj, "GetYaxis"): self._axes[1].title = obj.GetYaxis().GetTitle() if self._axes[0].title and self._axes[1].title: break # Finally create the frame for this plot frame_title = self._title if self._title else "" frame_string = f"{frame_title};{self._axes[0].title};{self._axes[1].title}" self.frame = self.pad.DrawFrame(x_low, y_low, x_up, y_up, frame_string) self._axes[0].limits[0] = x_low self._axes[0].limits[1] = x_up self._axes[1].limits[0] = y_low self._axes[1].limits[1] = y_up self._axes[2].limits[0] = z_low self._axes[2].limits[1] = z_up # Give the frame a unique name, for now just because we do it for # ROOT related object self.frame.SetName(f"{self.name}_frame") def __adjust_text_size(self, size): return int(max(1, size * self._parent_figure_spec.size[1])) def __adjust_text_size_x(self, size): """Helper method to adjust text sizes for x-axis' title and labels TODO That has to be revised """ return size / (self._rel_coordinates[2] - self._rel_coordinates[0]) def __adjust_text_size_y(self, size): """Helper method to adjust text sizes for y-axis' title and labels TODO That has to be revised """ return size / (self._rel_coordinates[3] - self._rel_coordinates[1]) def __adjust_row_margin(self, margin): """Helper method to recompute the relative row margin in the TPad based on the relative values of the user defined for the FigureSpec """ return margin / (self._rel_coordinates[3] - self._rel_coordinates[1]) def __adjust_column_margin(self, margin): """Helper method to recompute the relative column margin in the TPad based on the relative values of the user defined for the FigureSpec """ return margin / (self._rel_coordinates[2] - self._rel_coordinates[0]) def __adjust_tick_size_x(self, size): """Helper method to adjust the x-tick lengths accordingly """ return size / ((self.pad.GetUxmax() - self.pad.GetUxmin()) / \ (self.pad.GetX2()-self.pad.GetX1()) * \ (self._rel_coordinates[3] - self._rel_coordinates[1])) def __adjust_tick_size_y(self, size): """Helper method to adjust the y-tick lengths accordingly """ return size / ((self.pad.GetUymax() - self.pad.GetUymin()) / \ (self.pad.GetY2()-self.pad.GetY1()) * \ (self._rel_coordinates[2] - self._rel_coordinates[0])) def __adjust_legend_coordinates(self, coords): """Helper method to recompute the legend coordinates properly given the margins TODO This seems to work but needs to be revised to be sure """ x_low = map_value(coords[0], 0, 1, self.__adjust_column_margin(self._column_margins[0]), 1 - self.__adjust_column_margin(self._column_margins[1])) x_up = map_value(coords[2], 0, 1, self.__adjust_column_margin(self._column_margins[0]), 1 - self.__adjust_column_margin(self._column_margins[1])) y_low = map_value(coords[1], 0, 1, self.__adjust_row_margin(self._row_margins[0]), 1 - self.__adjust_row_margin(self._row_margins[1])) y_up = map_value(coords[3], 0, 1, self.__adjust_row_margin(self._row_margins[0]), 1 - self.__adjust_row_margin(self._row_margins[1])) return [x_low, y_low, x_up, y_up] def __adjust_coordinate_x(self, x_in): return map_value(x_in, 0, 1, self.__adjust_column_margin(self._column_margins[0]), 1 - self.__adjust_column_margin(self._column_margins[1])) def __adjust_coordinate_y(self, y_in): return map_value(y_in, 0, 1, self.__adjust_row_margin(self._row_margins[0]), 1 - self.__adjust_row_margin(self._row_margins[1])) def __create_legends(self): # pylint: disable=too-many-branches """Create legend(s) So far it only makes one legend but it should be possible to create multiple in general """ # count how many labels we want to have n_labels = sum(l is not None for l in self.labels) # just return if there are no labels if not n_labels: return # Adjust to account for number of columns n_labels = int(n_labels / self._legend_spec.n_columns) # Get the same legend positioning relative to the axes in the plot # adjust legend position starting from top right as default coordinates = [0.5, 0.7, 1, 0.89] if not isinstance(self._legend_spec.position, str): # assume relative coordinates coordinates = self._legend_spec.position # TODO that is rough if coordinates[3] < 0.5 and not self._legend_spec.principal_position: self._legend_spec.principal_position = "bottom" elif not self._legend_spec.principal_position: self._legend_spec.principal_position = "top" else: # deal with text string position # however, catch this one... if "left" in self._legend_spec.position and "right" in self._legend_spec.position: raise ValueError("Choose EITHER \"left\" OR \"right\" for legend positioning") if "bottom" in self._legend_spec.position and "top" in self._legend_spec.position: raise ValueError("Choose EITHER \"bottom\" OR \"top\" for legend positioning") # and now really adjust the coordinates if "left" in self._legend_spec.position: coordinates[0], coordinates[2] = (0.1, 0.5) if "bottom" in self._legend_spec.position: coordinates[1] = 0.1 if not self._legend_spec.principal_position: self._legend_spec.principal_position = "bottom" elif not self._legend_spec.principal_position: self._legend_spec.principal_position = "top" coordinates = self.__adjust_legend_coordinates(coordinates) if self._legend_spec.principal_position == "bottom": coordinates[3] = coordinates[1] + 0.05 * n_labels else: coordinates[1] = coordinates[3] - 0.05 * n_labels self.root_legend = TLegend(*coordinates) self.root_legend.SetNColumns(self._legend_spec.n_columns) # Make legend transparent and remove border self.root_legend.SetFillStyle(0) self.root_legend.SetLineWidth(0) # TODO this has to synced correctly with the line height of the legend which # atm is 0.05 (see above) self.root_legend.SetTextFont(63) self.root_legend.SetTextSize(self.__adjust_text_size(self._legend_spec.text_size)) for obj, lab in zip(self.objects, self.labels): if lab is None: continue self.root_legend.AddEntry(obj, lab) def __style_frame(self): """Style the frame axes """ # recomupte tick lengths self.frame.GetXaxis().SetTickLength(self.__adjust_tick_size_x(self._axes[0].tick_size)) self.frame.GetYaxis().SetTickLength(self.__adjust_tick_size_y(self._axes[1].tick_size)) # limit number of digits, TODO maybe make it configurable in the future self.frame.GetYaxis().SetMaxDigits(4) if self._share_x: # no labels or title in case of shared x-axis self.frame.GetXaxis().SetTitleSize(0) self.frame.GetXaxis().SetLabelSize(0) else: axis = self.frame.GetXaxis() axis.SetLabelFont(63) axis.SetTitleFont(63) axis.SetTitleSize(self.__adjust_text_size(self._axes[0].title_size)) axis.SetLabelSize(self.__adjust_text_size(self._axes[0].label_size)) # TODO properly compute offsets, the following is a wild guess for now #margin = self.__adjust_row_margin(self._row_margins[0]) if self._axes[0].title_offset is not None: axis.SetTitleOffset(self.__adjust_column_margin(self._axes[0].title_offset)) #axis.SetTitleOffset(19 * margin) if self._share_y: # no labels or title in case of shared y-axis self.frame.GetYaxis().SetTitleSize(0) self.frame.GetYaxis().SetLabelSize(0) else: axis = self.frame.GetYaxis() axis.SetLabelFont(63) axis.SetTitleFont(63) axis.SetTitleSize(self.__adjust_text_size(self._axes[1].title_size)) axis.SetLabelSize(self.__adjust_text_size(self._axes[1].label_size)) # TODO properly compute offsets, the following is a wild guess for now #margin = self.__adjust_column_margin(self._column_margins[0]) if self._axes[1].title_offset is not None: axis.SetTitleOffset(self.__adjust_column_margin(self._axes[1].title_offset)) #axis.SetTitleOffset(23 * margin) def __draw_text(self): """Draw potential text into pad """ if not self._texts: return if not self.pave_boxes: self.pave_boxes = [] for text in self._texts: pave_box = TPaveText(self.__adjust_coordinate_x(text.x_low), self.__adjust_coordinate_y(text.y_low), self.__adjust_coordinate_x(1), self.__adjust_coordinate_y(text.y_low + text.size), "brNDC") pave_box.SetLineWidth(0) pave_box.AddText(text.text) pave_box.SetBorderSize(0) pave_box.SetFillStyle(0) pave_box.SetTextAlign(10) pave_box.SetTextFont(63) pave_box.SetTextSizePixels(self.__adjust_text_size(text.size)) self.pave_boxes.append(pave_box) pave_box.Draw() def create(self, name, **kwargs): """Create this plot Args: name: str for TPad name kwargs: dict reserve_ndc_top: float to reserve relative space for the legend at the top """ if not self.objects: return # remember if another TPad was active before prev_pad = gPad.cd() if gPad and gPad.GetName() != name else None self.name = name self.pad = TPad(name, "", *self._rel_coordinates) self.pad.Draw() if self._axes[1].is_log: self.pad.SetLogy() if self._axes[0].is_log: self.pad.SetLogx() # but for now change to this TPad self.pad.cd() # This HAS to come before the frame creation self.pad.SetLeftMargin(self.__adjust_column_margin(self._column_margins[0])) self.pad.SetRightMargin(self.__adjust_column_margin(self._column_margins[1])) self.pad.SetBottomMargin(self.__adjust_row_margin(self._row_margins[0])) self.pad.SetTopMargin(self.__adjust_row_margin(self._row_margins[1])) # Set ticks on either side, might be customisable in the future self.pad.SetTickx(1) self.pad.SetTicky(1) # style objects and create legend self.__style_objects(**kwargs) self.__create_legends() if self.root_legend and self._legend_spec.principal_position == "top": kwargs["reserve_ndc_top"] = \ 1 - map_value(self.root_legend.GetY1(), self.__adjust_row_margin(self._row_margins[0]), 1 - self.__adjust_row_margin(self._row_margins[1]), 0, 1) elif self.root_legend and self._legend_spec.principal_position == "bottom": kwargs["reserve_ndc_bottom"] = \ map_value(self.root_legend.GetY2(), self.__adjust_row_margin(self._row_margins[0]), 1 - self.__adjust_row_margin(self._row_margins[1]), 0, 1) # Create the frame now everything is in place self.__create_frame(**kwargs) # adjust some frame axis properties self.__style_frame() # draw objects and legends self.__draw_objects() self.__draw_lines() self.__draw_legends() self.__draw_text() if prev_pad: # Don't spoil what the user might want to do afterwards prev_pad.cd()