def analysis_tree_all_reweighed(graph, cuts, snodes, **kwargs): cutnodes = [] for cut_name, cut in cuts: lepton = cut_name.split("_")[0] cutnode = tree.CutNode(cut, graph, cut_name, snodes, [], filter_funcs=[ lambda x,lepton=lepton: tree.is_samp(x, lepton) ]) cutnodes.append( cutnode ) #an extra QCD cleaning cut on top of the previous cut, which is only done in antiiso for syst in ["nominal", "up", "down"]: cn = tree.CutNode( Cuts.antiiso(lepton, syst) * Cuts.deltaR_QCD(), graph, "antiiso_%s" % syst, [cutnode], [], filter_funcs=[ lambda p: tree.is_samp(p, "antiiso") ] ) cutnodes.append( cn ) from histo_descs import create_plots create_plots(graph, cutnodes, **kwargs)
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
isos[lep] = dict() isos[lep]['iso'] = CutNode( Cut("1.0"), #At present no special cuts have to be applied on the ISO region graph, lep + "__iso", par, [], filter_funcs=[lambda x: "/iso/" in x[0].name] ) isol.append(isos[lep]['iso']) #Antiiso with variations in the isolation cut for aiso_syst in ["nominal", "up", "down"]: #dR with variations for dr_syst in ["nominal", "up", "down"]: cn = 'antiiso_' + aiso_syst + '_dR_' + dr_syst isos[lep][cn] = CutNode( #Apply any additional anti-iso cuts (like dR) along with antiiso variations. Cuts.antiiso(lep, aiso_syst) * Cuts.deltaR_QCD(dr_syst), graph, lep + "__" + cn, par, [], filter_funcs=[ lambda x: is_samp(x, "antiiso") and is_samp(x, "data") ] ) isol.append(isos[lep][cn]) # [iso, antiiso] --> jet --> [jets2-3] jet = Node(graph, "jet", isol, []) jets = dict() for i in [2,3]: jets[i] = CutNode(Cuts.n_jets(i), graph, "%dj"%i, [jet], []) tag = Node(graph, "tag", jet.children(), []) tags = dict()