def plot_data_mc(hists_mc, hist_data, name): canv = ROOT.TCanvas() p1 = ROOT.TPad("p1", "p1", 0, 0.3, 1, 1) p1.Draw() p1.SetTicks(1, 1); p1.SetGrid(); p1.SetFillStyle(0); p1.cd() stacks_d = OrderedDict() print "MC",hists_mc print "VAL",hists_mc.values() stacks_d["mc"] = hists_mc.values() stacks_d["data"] = [hist_data] stacks = plot_hists_stacked( p1, stacks_d, x_label=var, y_label="", do_log_y=True ) leg = legend([hist_data] + list(reversed(hists_mc.values())), styles=["p", "f"]) print canv, hist_data print get_stack_total_hist(stacks["mc"]) ratio_pad, hratio = plot_data_mc_ratio(canv, get_stack_total_hist(stacks["mc"]), hist_data) plot_info = PlotMetaInfo( name, "CUT", "WEIGHT", [infile], subdir=fit.name, comments=str(result[SIGNAL]) ) of.savePlot(canv, plot_info) canv.Close()
def data_mc_plot(samples, plot_def, name, lepton_channel, lumi, weight, physics_processes, use_antiiso=False): logger.info('Plot in progress %s' % name) merge_cmds = PhysicsProcess.get_merge_dict(physics_processes) #The actual merge dictionary var = plot_def['var'] #Id var is a list/tuple, assume if not isinstance(var, basestring): try: if lepton_channel == 'ele': var = var[0] elif lepton_channel == 'mu': var = var[1] except Exception as e: logger.error("Plot variable 'var' specification incorrect for multi-variable plot: %s" % str(var)) raise e cut = None if lepton_channel == 'ele': cut = plot_def['elecut'] elif lepton_channel == 'mu': cut = plot_def['mucut'] cut_str = str(cut) plot_range = plot_def['range'] do_norm = False if 'normalize' in plot_def.keys() and plot_def['normalize']: do_norm = True hists_mc = dict() hists_data = dict() for name, sample in samples.items(): logger.debug("Starting to plot %s" % name) if sample.isMC: hist = sample.drawHistogram(var, cut_str, weight=str(weight), plot_range=plot_range) hist.Scale(sample.lumiScaleFactor(lumi)) hists_mc[sample.name] = hist if do_norm: Styling.mc_style_nostack(hists_mc[sample.name], sample.name) else: Styling.mc_style(hists_mc[sample.name], sample.name) if "fitpars" in plot_def.keys(): rescale_to_fit(sample.name, hist, plot_def["fitpars"][lepton_channel]) elif "antiiso" in name and plot_def['estQcd'] and not use_antiiso: # Make loose template #Y U NO LOOP :) -JP region = '2j1t' if '2j0t' in plot_def['estQcd']: region='2j0t' if '3j0t' in plot_def['estQcd']: region='3j0t' if '3j1t' in plot_def['estQcd']: region='3j1t' if '3j2t' in plot_def['estQcd']: region='3j2t' qcd_extra_cut = Cuts.deltaR(0.3)*Cuts.antiiso(lepton_channel) #Take the loose template with a good shape from the N-jet, M-tag, post lepton selection region with high statistics qcd_loose_cut = cutlist[region]*cutlist['presel_'+lepton_channel]*qcd_extra_cut #Take the template which can be correctly normalized from the actual region with inverted isolation cuts qcd_cut = cut*qcd_extra_cut hist_qcd_loose = sample.drawHistogram(var, str(qcd_loose_cut), weight="1.0", plot_range=plot_range) hist_qcd = sample.drawHistogram(var, str(qcd_cut), weight="1.0", plot_range=plot_range) logger.debug("Using the QCD scale factor %s: %.2f" % (plot_def['estQcd'], qcdScale[lepton_channel][plot_def['estQcd']])) hist_qcd.Scale(qcdScale[lepton_channel][plot_def['estQcd']]) hist_qcd_loose.Scale(hist_qcd.Integral()/hist_qcd_loose.Integral()) if var=='cos_theta': hist_qcd=hist_qcd_loose sampn = "QCD"+sample.name #Rescale the QCD histogram to the eta_lj fit if "fitpars" in plot_def.keys(): rescale_to_fit(sampn, hist_qcd, plot_def["fitpars"][lepton_channel]) hists_mc[sampn] = hist_qcd hists_mc[sampn].SetTitle('QCD') if do_norm: Styling.mc_style_nostack(hists_mc[sampn], 'QCD') else: Styling.mc_style(hists_mc[sampn], 'QCD') #Real ordinary data in the isolated region elif not "antiiso" in name or use_antiiso: hist_data = sample.drawHistogram(var, cut_str, weight="1.0", plot_range=plot_range) hist_data.SetTitle('Data') Styling.data_style(hist_data) hists_data[name] = hist_data if len(hists_data.values())==0: raise Exception("Couldn't draw the data histogram") #Combine the subsamples to physical processes hist_data = sum(hists_data.values()) merge_cmds['QCD']=["QCD"+merge_cmds['data'][0]] order=['QCD']+PhysicsProcess.desired_plot_order if plot_def['log']: order = PhysicsProcess.desired_plot_order_log+['QCD'] merged_hists = merge_hists(hists_mc, merge_cmds, order=order) if hist_data.Integral()<=0: logger.error(hists_data) logger.error("hist_data.entries = %d" % hist_data.GetEntries()) logger.error("hist_data.integral = %d" % hist_data.Integral()) raise Exception("Histogram for data was empty. Something went wrong, please check.") if do_norm: for k,v in merged_hists.items(): v.Scale(1./v.Integral()) hist_data.Scale(1./hist_data.Integral()) htot = sum(merged_hists.values()) chi2 = hist_data.Chi2Test(htot, "UW CHI2/NDF") if chi2>20:#FIXME: uglyness logger.error("The chi2 between data and MC is large (%s, chi2=%.2f). You may have errors with your samples!" % (name, chi2) ) logger.info("MC : %s" % " ".join(map(lambda x: "%.1f" % x, list(htot.y())))) logger.info("DATA: %s" % " ".join(map(lambda x: "%.1f" % x, list(hist_data.y())))) logger.info("diff: %s" % str( " ".join(map(lambda x: "%.1f" % x, numpy.abs(numpy.array(list(htot.y())) - numpy.array(list(hist_data.y()))))) )) merged_hists_l = merged_hists.values() PhysicsProcess.name_histograms(physics_processes, merged_hists) leg_style = ['p','f'] if do_norm: leg_style=['p','l'] leg = legend([hist_data] + list(reversed(merged_hists_l)), legend_pos=plot_def['labloc'], styles=leg_style) canv = ROOT.TCanvas() #Make the stacks stacks_d = OrderedDict() stacks_d["mc"] = merged_hists_l stacks_d["data"] = [hist_data] #label xlab = plot_def['xlab'] if not isinstance(xlab, basestring): if lepton_channel == 'ele': xlab = xlab[0] else: xlab = xlab[1] ylab = 'N / '+str((1.*(plot_range[2]-plot_range[1])/plot_range[0])) if plot_def['gev']: ylab+=' GeV' fact = 1.5 if plot_def['log']: fact = 10 plow=0.3 if do_norm: plow=0 #Make a separate pad for the stack plot p1 = ROOT.TPad("p1", "p1", 0, plow, 1, 1) p1.Draw() p1.SetTicks(1, 1); p1.SetGrid(); p1.SetFillStyle(0); p1.cd() stacks = plot_hists_stacked(p1, stacks_d, x_label=xlab, y_label=ylab, max_bin_mult = fact, do_log_y = plot_def['log'], stack = (not do_norm)) #Put the the lumi box where the legend is not boxloc = 'top-right' if plot_def['labloc'] == 'top-right': boxloc = 'top-left' chan = 'Electron' if lepton_channel == "mu": chan = 'Muon' additional_comments = "" if 'cutname' in plot_def.keys(): additional_comments += ", " + plot_def['cutname'][lepton_channel] lbox = lumi_textbox(lumi, boxloc, 'preliminary', chan + ' channel' + additional_comments ) #Draw everything lbox.Draw() leg.Draw() canv.Draw() #Keep the handles just in case canv.PAD1 = p1 canv.STACKS = stacks canv.LEGEND = legend canv.LUMIBOX = lbox return canv, merged_hists, htot, hist_data
elif name == "SingleMu": hist_data = sample.drawHistogram(var, cut_str, weight="1.0", plot_range=plot_range) Styling.data_style(hist_data) elif name == "SingleMu_aiso": hist_qcd = sample.drawHistogram(var, cut_str, weight="1.0", plot_range=plot_range) #hist_qcd. pass #Combine the subsamples to physical processes merged_hists = merge_hists(hists_mc, merge_cmds).values() #Some printout for h in merged_hists + [hist_data]: print h.GetName(), h.GetTitle(), h.Integral() canv = ROOT.TCanvas() stacks_d = OrderedDict() stacks_d["mc"] = merged_hists stacks_d["data"] = [hist_data] stacks = plot_hists_stacked(canv, stacks_d) canv.Draw() #Create the dir if it doesn't exits try: os.mkdir("muon_out") except OSError: pass canv.SaveAs("muon_out/test.pdf")
canv = ROOT.TCanvas("c", "c") canv.SetWindowSize(500, 500) canv.SetCanvasSize(600, 600) #!!!!LOOK HERE!!!!! #---- #Draw the stacked histograms #---- stacks_d = OrderedDict( ) #<<< need to use OrderedDict to have data drawn last (dict does not preserve order) stacks_d["mc"] = [h_mc1, h_mc2, h_mc3] # <<< order is important here, mc1 is bottom-most stacks_d["data"] = [h_d1] stacks = plot_hists_stacked(canv, stacks_d, x_label="variable x [GeV]", y_label="", do_log_y=False) #Draws the lumi box from plots.common.utils import lumi_textbox lumibox = lumi_textbox(19432) #Draw the legend from plots.common.legend import legend leg = legend( [h_d1, h_mc3, h_mc2, h_mc1 ], # <<< need to reverse MC order here, mc3 is top-most styles=["p", "f"], width=0.25)
def data_mc_plot(pd): hists = load_theta_format(pd.infile, styles) for (variable, sample, systtype, systdir), hist in hists.items_flat(): #Scale all MC samples except QCD to the luminosity if sample_types.is_mc(sample) and not sample=="qcd": hist.Scale(pd.lumi) if hasattr(pd, "rebin"): hist.Rebin(pd.rebin) if sample=="qcd" and hasattr(pd, "qcd_yield"): hist.Scale(pd.qcd_yield / hist.Integral()) rescale_to_fit(sample, hist, pd.process_scale_factor) hist.SetTitle(sample) hist.SetName(sample) #Assuming we only have 1 variable hists = hists[pd.var] hists_nominal = hists.pop("nominal")[None] hists_nom_data = hists_nominal.pop('data') hists_nom_mc = hists_nominal.values() hists_syst = hists hists_nom_data.SetTitle('data') #A list of all the systematic up, down variation templates as 2-tuples all_systs = [ ] all_systs = hists_syst.keys() systs_to_consider = [] #See which systematics where asked to switch on for syst in all_systs: for sm in pd.systematics: if re.match(sm, syst): systs_to_consider.append(syst) #The total nominal MC histogram nom = sum(hists_nom_mc) if pd.normalize: ratio = hists_nom_data.Integral() / nom.Integral() hists_nom_data.Scale(1.0/ratio) #Get all the variated up/down total templates #A list with all the up/down total templates all_systs = [] sumsqs = [] logger.info("Considering systematics %s" % str(systs_to_consider)) for syst in systs_to_consider: #A list with the up/down variated template for a particular systematic totupdown = [] sumsq = [] for systdir in ["up", "down"]: #Get all the templates corresponding to a systematic scenario and a variation _hists = hists_syst[syst][systdir] for k, h in _hists.items(): """ Consider only the shape variation of the systematic, hence the variated template is normalized to the corresponding unvariated template. """ if pd.systematics_shapeonly: if h.Integral()>0: h.Scale(hists_nominal[k].Integral() / h.Integral()) #For the missing variated templates, use the nominal ones, but warn the user present = set(_hists.keys()) all_mc = set(hists_nominal.keys()) missing = list(all_mc.difference(present)) for m in missing: logger.warning("Missing systematic template for %s:%s" % (syst, systdir)) #Calculate the total variated template tot = sum(_hists.values()) + sum([hists_nominal[m] for m in missing]) totupdown.append(tot) sumsq.append( math.sqrt(numpy.sum(numpy.power(numpy.array(list(nom.y())) - numpy.array(list(tot.y())), 2))) ) logger.debug("Systematic %s: sumsq=%.2Eu, %.2Ed" % (syst, sumsq[0], sumsq[1])) sumsqs.append((syst, max(sumsq))) all_systs.append( (syst, tuple(totupdown)) ) sumsqs = sorted(sumsqs, key=lambda x: x[1], reverse=True) for syst, sumsq in sumsqs[0:7]: logger.info("Systematic %s, %.4f" % (syst, sumsq)) #Calculate the total up/down variated templates by summing in quadrature syst_stat_up, syst_stat_down = total_syst( nom, all_systs, ) for k, v in hists_nominal.items(): if hasattr(PhysicsProcess, k): pp = getattr(PhysicsProcess, k) v.SetTitle(pp.pretty_name) else: logger.warning("Not setting pretty name for %s" % k) #If QCD is high-stats, put it in the bottom plotorder = copy.copy(PhysicsProcess.desired_plot_order_mc) if hists_nominal["qcd"].GetEntries()>100: plotorder.pop(plotorder.index("qcd")) plotorder.insert(0, "qcd") stacks_d = OrderedDict() stacks_d['mc'] = reorder(hists_nominal, plotorder) stacks_d['data'] = [hists_nom_data] #Systematic style for s in [syst_stat_up, syst_stat_down]: s.SetFillStyle(0) s.SetLineWidth(3) s.SetMarkerSize(0) s.SetLineColor(ROOT.kBlue+2) s.SetLineStyle('dashed') s.SetTitle("stat. + syst.") #c = ROOT.TCanvas("c", "c", 1000, 1000) c = ROOT.TCanvas("c", "c") p1 = ROOT.TPad("p1", "p1", 0, 0.3, 1, 1) p1.Draw() p1.SetTicks(1, 1); p1.SetGrid(); p1.SetFillStyle(0); p1.cd() stacks = plot_hists_stacked( p1, stacks_d, x_label=pd.get_x_label(), max_bin_mult=pd.get_max_bin_mult(), min_bin=pd.get_min_bin() ) p1.SetLogy(pd.log) syst_stat_up.Draw("SAME hist") syst_stat_down.Draw("SAME hist") ratio_pad, hratio = plot_data_mc_ratio( c, hists_nom_data, nom, syst_hists=(syst_stat_down, syst_stat_up), min_max=pd.get_ratio_minmax() ) p1.cd() leg = legend( stacks_d['data'] + list(reversed(stacks_d['mc'])) + [syst_stat_up], nudge_x=pd.legend_nudge_x, nudge_y=pd.legend_nudge_y, **pd.__dict__ ) lb = lumi_textbox(pd.lumi, line2=pd.get_lumibox_comments(channel=pd.channel_pretty), pos=pd.get_lumi_pos() ) c.children = [p1, ratio_pad, stacks, leg, lb] tot = 0 for k, v in hists_nominal.items(): print k, v.Integral(), v.GetEntries() tot += v.Integral() tot_data = hists_nom_data.Integral() print "MC: %.2f Data: %.2f" % (tot, tot_data) #import pdb; pdb.set_trace() return c, (hists_nominal, hists_nom_data)
#Create the canvas canv = ROOT.TCanvas("c", "c") canv.SetWindowSize(500, 500) canv.SetCanvasSize(600, 600) #!!!!LOOK HERE!!!!! #---- #Draw the stacked histograms #---- stacks_d = OrderedDict() #<<< need to use OrderedDict to have data drawn last (dict does not preserve order) stacks_d["mc"] = [h_mc1, h_mc2, h_mc3] # <<< order is important here, mc1 is bottom-most stacks_d["data"] = [h_d1] stacks = plot_hists_stacked( canv, stacks_d, x_label="variable x [GeV]", y_label="", do_log_y=False ) #Draws the lumi box from plots.common.utils import lumi_textbox lumibox = lumi_textbox(19432) #Draw the legend from plots.common.legend import legend leg = legend( [h_d1, h_mc3, h_mc2, h_mc1], # <<< need to reverse MC order here, mc3 is top-most styles=["p", "f"], width=0.25 )