def do_data_mc_plot(dirname, histname, output_filename, **plot_kwargs): data_file = cu.open_root_file(os.path.join(dirname, qgc.JETHT_ZB_FILENAME)) qcd_file = cu.open_root_file(os.path.join(dirname, qgc.QCD_FILENAME)) qcd_py_file = cu.open_root_file( os.path.join(dirname, qgc.QCD_PYTHIA_ONLY_FILENAME)) qcd_hpp_file = cu.open_root_file( os.path.join(dirname, qgc.QCD_HERWIG_FILENAME)) data_hist = cu.get_from_tfile(data_file, histname) qcd_hist = cu.get_from_tfile(qcd_file, histname) qcd_py_hist = cu.get_from_tfile(qcd_py_file, histname) qcd_hpp_hist = cu.get_from_tfile(qcd_hpp_file, histname) conts = [ Contribution(data_hist, label="Data", line_color=ROOT.kBlack, marker_size=0, marker_color=ROOT.kBlack), Contribution(qcd_hist, label="QCD MG+PYTHIA8 MC", line_color=qgc.QCD_COLOUR, subplot=data_hist, marker_size=0, marker_color=qgc.QCD_COLOUR), Contribution(qcd_py_hist, label="QCD PYTHIA8 MC", line_color=qgc.QCD_COLOURS[2], subplot=data_hist, marker_size=0, marker_color=qgc.QCD_COLOURS[2]), # Contribution(qcd_hpp_hist, label="QCD HERWIG++ MC", line_color=qgc.HERWIGPP_QCD_COLOUR, subplot=data_hist, marker_size=0, marker_color=qgc.HERWIGPP_QCD_COLOUR), ] plot = Plot(conts, what='hist', ytitle="N", xtitle="p_{T}^{Leading jet} [GeV]", subplot_type="ratio", subplot_title="Simulation / data", ylim=[1E3, None], lumi=cu.get_lumi_str(do_dijet=True, do_zpj=False), **plot_kwargs) plot.y_padding_max_log = 500 plot.legend.SetX1(0.55) plot.legend.SetX2(0.98) plot.legend.SetY1(0.7) # plot.legend.SetY2(0.88) plot.plot("NOSTACK HIST E") plot.set_logx(do_more_labels=True, do_exponent=False) plot.set_logy(do_more_labels=False) plot.save(output_filename)
def __init__(self, jet_algo, region, angle, output_dir='.', has_data=False, is_ave_pt_binning=False): self.jet_algo = jet_algo self.region = region do_zpj = "ZPlusJets" in region['name'] do_dijet = "Dijet" in region['name'] self.lumi = cu.get_lumi_str(do_dijet=do_dijet, do_zpj=do_zpj) self.pt_var_str = "#LT p_{T}^{jet} #GT" if is_ave_pt_binning else "p_{T}^{jet}" self.pt_str = self.pt_var_str + " [GeV]" self.has_data = has_data self.angle = angle angle_prepend = "Groomed " if "groomed" in region['name'] else "" lower_angle_name = qgc.lower_angle_name(angle) # for plot axis titles self.angle_str = "{prepend}{name} ({lambda_str})".format( prepend=angle_prepend, name=lower_angle_name if angle_prepend != "" else angle.name, lambda_str=angle.lambda_str) # self.particle_title = "Particle-level " + self.angle_str self.particle_title = self.angle_str angle_prepend = "groomed " if "groomed" in region['name'] else "" self.detector_title = "Detector-level {prepend}{name} ({lambda_str})".format( prepend=angle_prepend, name=lower_angle_name, lambda_str=angle.lambda_str) self.pt_bin_normalised_differential_label = "#frac{1}{d#sigma/dp_{T}} #frac{d^{2}#sigma}{dp_{T} d%s}" % ( angle.lambda_str) self.pt_bin_detector_normalised_differential_label = "#frac{1}{dN/dp_{T}} #frac{d^{2}N}{dp_{T} d%s}" % ( angle.lambda_str) self.pt_bin_normalised_differential_times_width_label = "#frac{1}{d#sigma/dp_{T}} #frac{d^{2}#sigma}{dp_{T} d%s}" % ( angle.lambda_str) self.pt_bin_unnormalised_differential_label = "#frac{1}{dN/dp_{T}} #frac{d^{2}N}{dp_{T} d%s}" % ( angle.lambda_str) # FIXME self.pt_bin_unnormalised_differential_label = "N" self.lambda_bin_normalised_differential_label = "#frac{1}{d#sigma/d%s} #frac{d^{2}#sigma}{dp_{T} d%s}" % ( angle.lambda_str, angle.lambda_str) self.lambda_bin_unnormalised_differential_label = "#frac{1}{dN/d%s} #frac{d^{2}N}{dp_{T} d%s}" % ( angle.lambda_str, angle.lambda_str) # FIXME self.lambda_bin_unnormalised_differential_label = "N" self.output_dir = output_dir self.output_fmt = 'pdf' self.append = "%s_%s" % ( region['name'], angle.var ) # common str to put on filenames, etc. don't need angle_prepend as 'groomed' in region name
def __init__(self, contributions=None, what="hist", title=None, xtitle=None, ytitle=None, xlim=None, ylim=None, legend=True, extend=False, subplot=None, subplot_type=None, subplot_title=None, subplot_limits=None, has_data=True, is_preliminary=True, is_supplementary=False, lumi=cu.get_lumi_str(do_dijet=False, do_zpj=True)): """ Class to handle information about one plot, which can have several contributions, can have subplot, etc Parameters ---------- contributions : list[Contribution] List of Contribution objects. what : str, optional Type of thing in contributions: "hist", graph", "function", "both" (=graph+function). title : None, optional Title to put on plot xtitle : None, optional X axis title ytitle : None, optional Y axis title xlim : None, optional Limits of x axis. If None, then determines suitable limits. ylim : None, optional Limits of y axis. If either or both element is None, then determines suitable limits. legend : bool, optional Include legend on plot. extend : bool, optional Extend functions to cover the whole x axis range. subplot : None, optional If not None, draws a plot below the main hist with all plots compared to the object provided as the argument here. subplot_type : None, optional The method of comparison in the subplot: ratio, difference, or ddelta/dlambda subplot_title : None, optional Y axis title for subplot subplot_limits : None, optional Set hard limits on subplot y axis range. If None, will choose some vaguely sensible ones has_data : bool, optional For CMS labelling: If plot contains data is_preliminary : bool, optional For CMS labelling: If plot is not for publication yet (PAS, AN) is_supplementary : bool, optional For CMS labelling: If plot is supplementary material lumi : str, optional Luminosity string to put on plot (ignored if has_data=False) Raises ------ ValueError If `what` not one of possible options If `xlim` or `lim` not length = 2 If `subplot_type` not one of possible options """ self.contributions = contributions if contributions else [] self.contributions_objs = [] options = ['hist', 'graph', 'function', 'both'] if what not in options: raise ValueError("`what` argument must be one of %s" % options) self.plot_what = what self.xtitle = xtitle self.ytitle = ytitle if xlim is not None: if len(xlim) != 2: raise ValueError("xlim must have length 2 or be None") self.xlim = xlim if ylim is not None: if len(ylim) != 2: raise ValueError("ylim must have length 2 or be None") self.ylim = copy(ylim) if isinstance(ylim, tuple): # convert non-mutable tuple to mutable list, since it might be modified # in _set_automatic_y_maximum/minimum() self.ylim = list(ylim) self.y_padding_max_linear = 1.6 # factor to auto extend y upper limit for linear scale self.y_padding_max_log = 10 # factor to auto extend y upper limit for log scale self.y_padding_min_linear = 1.4 # factor to auto extend y lower limit for linear scale self.y_padding_min_log = 0.1 # factor to auto extend y lower limit for log scale # self.y_padding_mode = 'abs' # abs = times max/min, range = times range, add/subtract on self.do_legend = legend self.legend = ROOT.TLegend(0.65, 0.6, 0.94, 0.85) if legend else None if self.do_legend: self._style_legend() self.reverse_legend = False self.splitline_legend = False # if True, use splitline instead of extra entries for \n. Only works with 1 \n occurrence self.do_extend = extend self.container = None self.canvas = None self.default_canvas_size = (600, 800) # self.default_canvas_size = (800, 600) self.main_pad = None self.right_margin = 0.04 self.left_margin = 0.12 # use ROOT default self.top_margin = 0.1 # Subplot vars: self.subplot = subplot # Contribution for subplot if subplot_type and subplot_type not in ['ratio', 'diff', "ddelta"]: raise ValueError( "subplot_type must be one of None, ratio, diff, or ddelta") self.subplot_type = subplot_type if not self.subplot_type: self.subplot = None self.subplot_container = None self.subplot_contributions = [] self.subplot_pad = None self.subplot_maximum_ceil = 2.5 # subplot maximum is always below this... self.subplot_maximum_floor = 1.5 # and at least this... self.subplot_minimum_ceil = 0.5 # subplot minimum is always below this... self.subplot_minimum_floor = 0 # and at least this... self.subplot_limits = subplot_limits self.subplot_pad_height = 0.32 self.subplot_pad_fudge = 0.01 # to get non-overlapping subplot axis self.subplot_line = None # need this to remain visible... self.subplot_title = subplot_title self.subplot_line_style = 2 self.subplot_line_width = 2 self.subplot_line_color = ROOT.kBlack # Labelling vars: self.title = title or "" self.title_start_y = 0.87 self.title_diff_y = 0.04 self.title_left_offset = 0.03 # only for title in plot self.title_font_size = 0.03 self.cms_text_font_size = 0.035 self.cms_text_y = 0.915 self.left_title_offset_fudge_factor = 7 self.text_left_offset = 0 # for title and CMS texts together self.has_data = has_data self.is_preliminary = is_preliminary self.is_supplementary = is_supplementary self.lumi = lumi
def do_1D_plot(hists, components_styles_dicts, output_filename, do_ratio=True, logx=False, logy=False, normalise_hists=True, title="", xtitle=None, mean_rel_error=0.4, data_first=True, show_integrals=False, lumi=cu.get_lumi_str(do_dijet=False, do_zpj=True)): if (len(hists) != len(components_styles_dicts)): raise RuntimeError("# hists != # components_styles_dicts (%d vs %d)" % (len(hists), len(components_styles_dicts))) if len(hists) == 0: return # Ignore if all empty objs total_entries = sum(h.GetEntries() for h in hists) if total_entries == 0: print("WARNING: all plots have 0 entries") return do_ratio = (do_ratio and len(hists) > 1) entries = [] components_styles_dicts = deepcopy(components_styles_dicts) for h, csd in zip(hists, components_styles_dicts): if show_integrals: csd['label'] += "\nIntegral = {:.4g}".format(h.Integral()) entries.append((h.Clone(cu.get_unique_str()), csd)) # print("Auto y limits:", min_val, max_val) ylim = None # if not normalise_hists: # min_val, min_bin, max_val, max_bin = cu.get_min_max_bin_contents_multiple_hists(hists) # if logy: # ylim = [0.5*min_val, 50*max_val] # else: # # ylim = [0.5*min_val, 1.5*max_val] # ylim = [0, 1.5*max_val] xlim = "auto" # Auto calc x limits to avoid lots of empty bins draw_opt = "NOSTACK HIST E1" subplot_title = "Simulation / Data" subplot_limits = (0, 2) if logy else (0.5, 1.5) # subplot_limits = [0.5, None] subplot_limits = None qgp.do_comparison_plot( entries, output_filename, # rebin=rebin, normalise_hist=normalise_hists, draw_opt=draw_opt, title=title, xtitle=xtitle, xlim=xlim, ylim=ylim, logx=logx, logy=logy, mean_rel_error=mean_rel_error, data_first=data_first, subplot_type='ratio' if do_ratio else None, subplot_title=subplot_title, subplot=entries[0][0] if do_ratio else None, subplot_limits=subplot_limits, lumi=lumi)
def do_all_1D_projection_plots_in_dir(directories, components_styles_dicts, output_dir, region_str=None, do_ratio=True, normalise_hists=True, jet_config_str="", title=None, bin_by=None): """ Given a set of TDirs, loop over all 2D hists, do projection hists for chosen bins, and plot all TDir contributions on a canvas for comparison. components_styles_dicts should be a list of style dicts, one for each directory/contribution to a plot. This should include label for this component. """ if len(directories) != len(components_styles_dicts): raise IndexError("Need same number of style dicts and directories") list_of_obj = [get_list_of_obj(d) for d in directories] # check all have same list of plots if not all(x == list_of_obj[0] for x in list_of_obj): print("Different number of object in the TDirectorys") common_list_of_obj = set(list_of_obj[0]) for l in list_of_obj[1:]: common_list_of_obj = common_list_of_obj & set(l) common_list_of_obj = sorted(list(common_list_of_obj)) pt_bins = qgc.PT_BINS lumi = cu.get_lumi_str(do_dijet=False, do_zpj=True) if "dijet" in region_str.lower(): lumi = cu.get_lumi_str(do_dijet=True, do_zpj=False) show_integrals = not normalise_hists for obj_name in common_list_of_obj: if "flav" in obj_name: continue if obj_name in [ 'eta_jet1_vs_eta_jet2', 'phi_jet1_vs_pt_jet1', 'phi_jet2_vs_pt_jet1', # 'reliso_mu1_vs_pt_jet1', 'reliso_mu2_vs_pt_jet1', # 'dphi_mumu_jet1_vs_pt_jet1', # 'dphi_mumu_vs_pt_jet1', 'pt_jet1_z_pt_jet2_z_ratio', # 'met_sig_vs_pt_jet1' 'weight_vs_puHat_genHT_ratio', 'eta_jet_response', ]: continue if "genjet_ind_recojet_ind" in obj_name: continue print("Doing:", obj_name) objs = [ d.Get(obj_name).Clone(obj_name + str(uuid1())) for d in directories ] # Do TH1s separately if not isinstance(objs[0], (ROOT.TH2F, ROOT.TH2D, ROOT.TH2I)): logx = obj_name in [ "pt_jet", "pt_jet1", "pt_jet2", "pt_mumu", 'gen_ht', 'pt_jet_response_binning', 'pt_genjet_response_binning', 'pt_jet1_unweighted', 'pt_jet_unweighted' ] this_title = (("{jet_algo}\n" "{region_label}\n").format(jet_algo=jet_config_str, region_label=region_str)) if title is not None: this_title += "\n%s" % (title) # if obj_name in ['pt_jet', 'pt_jet1', 'pt_jet2', 'pt_mumu']: # # small rebinned version # for obj in objs: # obj.Rebin(1) # if normalise_hists: do_1D_plot(objs, components_styles_dicts=components_styles_dicts, do_ratio=do_ratio, normalise_hists=normalise_hists, logx=logx, logy=True, title=this_title, mean_rel_error=-1, lumi=lumi, show_integrals=show_integrals, output_filename=os.path.join( output_dir, obj_name + ".%s" % (OUTPUT_FMT))) # do a rebinned version for some variables if obj_name in [ 'pt_jet', 'pt_jet1', 'pt_jet2', 'pt_mumu', 'pt_jet_response_binning' ]: for obj in objs: if obj_name == 'pt_jet_response_binning': obj.Rebin(2) # to get gen level pt binning else: obj.Rebin( 20) # this is multiplied by the previous rebin this_title = (("{jet_algo}\n" "{region_label}\n").format( jet_algo=jet_config_str, region_label=region_str)) if title is not None: this_title += "\n%s" % (title) do_1D_plot(objs, components_styles_dicts=components_styles_dicts, do_ratio=do_ratio, normalise_hists=normalise_hists, logx=logx, logy=True, title=this_title, lumi=lumi, show_integrals=show_integrals, output_filename=os.path.join( output_dir, obj_name + "_rebin.%s" % (OUTPUT_FMT))) else: for pt_min, pt_max in pt_bins: # print(pt_min, pt_max) rebin = 1 # exceptions...why didn't I pick the same number of bins... do_not_rebin = any([ "n_jets" in obj_name, "n_mu" in obj_name, "met_sig" in obj_name, # obj_name.startswith('dphi_mumu'), obj_name.startswith('pt_jet3_frac'), obj_name.startswith('pt_jet1_jet2_ratio'), obj_name.startswith('pt_jet1_z_ratio'), obj_name.startswith('pt_jet2_z_ratio'), obj_name.startswith('dphi_jet1_z_vs_pt_jet1'), # obj_name.startswith('m_jj'), ]) if not do_not_rebin: # if objs[0].GetNbinsX() % 5 == 0 and objs[0].GetNbinsX() >= 100: # rebin = 5 if objs[0].GetNbinsX() % 4 == 0 and objs[0].GetNbinsX( ) >= 80: rebin = 2 elif objs[0].GetNbinsX() % 3 == 0 and objs[0].GetNbinsX( ) >= 60: rebin = 3 if obj_name.startswith("m_jj"): rebin = 2 if "reliso" in obj_name: rebin = 1 if "pt_jet1_vs_pt_z" in obj_name: rebin = 20 if "pt_mu1_vs_pt_z" in obj_name: rebin = 10 if pt_min > 250: rebin = 20 if "pt_mu2_vs_pt_z" in obj_name: rebin = 10 if pt_min > 250: rebin = 25 hists = [ qgp.get_projection_plot(ob, pt_min, pt_max) for ob in objs ] for h in hists: h.Rebin(rebin) def _title(region_str, start_val, end_val): pt_var_str = "p_{T}^{jet}" if bin_by == "ave": pt_var_str = "#LT p_{T}^{jet} #GT" elif bin_by == "Z" and "_vs_pt_jet" not in obj_name: pt_var_str = "p_{T}^{Z}" s = (("{jet_algo}\n" "{region_label}\n" "{bin_edge_low:g} < {pt_str} < {bin_edge_high:g} GeV" ).format(jet_algo=jet_config_str, region_label=region_str, pt_str=pt_var_str, bin_edge_low=start_val, bin_edge_high=end_val)) if title is not None: s = "%s\n%s" % (s, title) return s xtitle = None if "eta_jet1_vs_pt" in obj_name and "eta_ordered" in directories[ 0].GetName().lower(): xtitle = "y^{forward jet}" elif "eta_jet2_vs_pt" in obj_name and "eta_ordered" in directories[ 0].GetName().lower(): xtitle = "y^{central jet}" logx = any([ x in obj_name for x in ['pt_jet_response', 'pt_jet1_vs_pt_z'] ]) logy = any([ x in obj_name for x in ['pt_jet_response', 'pt_jet1_vs_pt_z'] ]) do_1D_plot(hists, components_styles_dicts=components_styles_dicts, do_ratio=do_ratio, normalise_hists=normalise_hists, logx=logx, logy=logy, title=_title(region_str, pt_min, pt_max), xtitle=xtitle, mean_rel_error=-1, lumi=lumi, show_integrals=show_integrals, output_filename=os.path.join( output_dir, obj_name + "_pt%dto%d.%s" % (pt_min, pt_max, OUTPUT_FMT)))
def do_plots(root_dir): # QG variable plots pt_bins = qgc.PT_BINS[:] var_list = qgc.COMMON_VARS radius, pus = cu.get_jet_config_from_dirname(root_dir) jet_str = "AK%s" % (radius.upper()) dy_tfile, qcd_tfile = None, None if os.path.isfile(os.path.join(root_dir, qgc.DY_FILENAME)): dy_tfile = cu.TFileCacher(os.path.join(root_dir, qgc.DY_FILENAME)) if os.path.isfile(os.path.join(root_dir, qgc.QCD_FILENAME)): qcd_tfile = cu.TFileCacher(os.path.join(root_dir, qgc.QCD_FILENAME)) for gr_append in ["", "_groomed"]: if gr_append == "_groomed": print("Doing groomed plots...") else: print("Doing ungroomed plots...") # GEnJets matched to recojet, reco selection zpj_dirname = "ZPlusJets_QG%s" % (gr_append) dj_cen_dirname = "Dijet_QG_central_tighter%s" % (gr_append) dj_fwd_dirname = "Dijet_QG_forward_tighter%s" % (gr_append) # Gen Jets from gen selection zpj_dirname = "ZPlusJets_QG_gen%s" % (gr_append) dj_cen_dirname = "Dijet_QG_gen_central%s" % (gr_append) dj_fwd_dirname = "Dijet_QG_gen_forward%s" % (gr_append) for ang in var_list[:]: print("...Doing", ang.name) var_template = "{prefix}%s_vs_pt" % (ang.var ) # {prefix} is for flavour for pt_ind, (start_val, end_val) in enumerate(pt_bins): zpj_entries = [] dijet_cen_entries = [] dijet_fwd_entries = [] # Get all plots lw = 2 msize = 1.1 mc_msize = 1E-3 # small enough to not be seen but not 0 - otherwise the horizontal lines on error bars don't get drawn mc_msize = msize # small enough to not be seen but not 0 - otherwise the horizontal lines on error bars don't get drawn flavours_dicts = [ { "prefix": "q", "label": "u/d/s" }, { "prefix": "g", "label": "g" }, { "prefix": "bc", "label": "b/c" }, ] if dy_tfile: # Z+JETS REGION marker = cu.Marker(qgc.DY_MARKER) for flav_dict, color, mark in zip(flavours_dicts, qgc.DY_COLOURS, marker.cycle()): h2d_dyj_mc = dy_tfile.get( "%s/%s" % (zpj_dirname, var_template.format(**flav_dict))) dy_kwargs_mc = dict(line_color=color, line_width=lw, fill_color=color, marker_color=color, marker_style=mark, marker_size=mc_msize, label="%s flavour" % (flav_dict['label']), subplot=None) zpj_entries.append( (qgp.get_projection_plot(h2d_dyj_mc, start_val, end_val), dy_kwargs_mc)) if qcd_tfile: # DIJET CENTRAL REGION marker = cu.Marker(qgc.QCD_MARKER) for flav_dict, color, mark in zip(flavours_dicts, qgc.QCD_COLOURS, marker.cycle()): h2d_qcd_cen_mc = qcd_tfile.get( "%s/%s" % (dj_cen_dirname, var_template.format(**flav_dict))) qcd_cen_kwargs_mc = dict(line_color=color, line_width=lw, fill_color=color, marker_color=color, marker_style=mark, marker_size=mc_msize, label="%s flavour" % (flav_dict['label']), subplot=None) dijet_mgpy_hist = qgp.get_projection_plot( h2d_qcd_cen_mc, start_val, end_val) dijet_cen_entries.append( (dijet_mgpy_hist, qcd_cen_kwargs_mc)) # DIJET FORWARD REGION marker = cu.Marker(qgc.QCD_MARKER) for flav_dict, color, mark in zip(flavours_dicts, qgc.QCD_COLOURS, marker.cycle()): h2d_qcd_fwd_mc = qcd_tfile.get( "%s/%s" % (dj_fwd_dirname, var_template.format(**flav_dict))) qcd_fwd_kwargs_mc = dict(line_color=color, line_width=lw, fill_color=color, marker_color=color, marker_style=mark, marker_size=mc_msize, label="%s flavour" % (flav_dict['label']), subplot=None) dijet_mgpy_hist = qgp.get_projection_plot( h2d_qcd_fwd_mc, start_val, end_val) dijet_fwd_entries.append( (dijet_mgpy_hist, qcd_fwd_kwargs_mc)) ################# # SETUP PLOTTING ################# rebin = 2 v_lower = var_template.lower() if "multiplicity" in v_lower: rebin = 1 # elif "flavour" in v_lower or "thrust" in v_lower: # rebin = 1 # elif 'ptd' in v_lower: # rebin = 4 # elif 'lha_charged' in v_lower: # rebin = 4 # rebin = 1 xlim = None if "width" in v_lower or "ptd" in v_lower: xlim = (0, 1) elif "thrust" in v_lower: xlim = (0, 0.5) # elif "multiplicity" in v_lower and "ak4" in root_dir.lower(): # if end_val <= 150: # xlim = (0, 50) # else: # xlim = (0, 80) auto_xlim = False if "multiplicity" in v_lower or "thrust" in v_lower: auto_xlim = True ylim = [0, None] if "flavour" in v_lower: ylim = (0, 1) # elif "lha" in v_lower: # ylim = (0, 5) plot_dir = os.path.join( root_dir, "plots_gen_lambda_flav_comparison%s" % (gr_append)) subplot_title = "Simulation / Data" subplot_limits = (0, 2) xlabel = ang.name + " (" + ang.lambda_str + ")" if gr_append is not "": xlabel = "Groomed " + ang.name + " (" + ang.lambda_str + ")" def _title(region_str, start_val, end_val): pt_var_str = "p_{T}^{jet}" s = (("{jet_algo}\n" "{region_label}\n" "{mc_sample}\n" "{bin_edge_low:g} < {pt_str} < {bin_edge_high:g} GeV" ).format(jet_algo=jet_str, region_label=region_str, mc_sample="MG5+Pythia8", pt_str=pt_var_str, bin_edge_low=start_val, bin_edge_high=end_val)) return s has_data = False draw_opt = "NOSTACK HIST E1" # dj central only # dont' try to do multiple signal regions per plot, it looks rubbish if len(dijet_cen_entries) > 0: qgp.do_comparison_plot( dijet_cen_entries, "%s/ptBinned/%s_pt%dto%d_dijet_central.%s" % (plot_dir, ang.var, start_val, end_val, OUTPUT_FMT), rebin=rebin, draw_opt=draw_opt, title=_title(qgc.Dijet_CEN_LABEL, start_val, end_val), xtitle=xlabel, xlim='auto' if auto_xlim else xlim, # don't use calc_auto_xlim, since do_comparison_plot will rebin it anyway ylim=ylim, data_first=has_data, mean_rel_error=0.4, subplot_type=None, lumi=cu.get_lumi_str( do_dijet=False, do_zpj=True)) # full lumi as just MC # dj forward only if len(dijet_fwd_entries) > 0: qgp.do_comparison_plot( dijet_fwd_entries, "%s/ptBinned/%s_pt%dto%d_dijet_forward.%s" % (plot_dir, ang.var, start_val, end_val, OUTPUT_FMT), rebin=rebin, draw_opt=draw_opt, title=_title(qgc.Dijet_FWD_LABEL, start_val, end_val), xtitle=xlabel, xlim='auto' if auto_xlim else xlim, ylim=ylim, data_first=has_data, mean_rel_error=0.4, subplot_type=None, lumi=cu.get_lumi_str( do_dijet=False, do_zpj=True)) # full lumi as just MC # zpj only if len(zpj_entries) > 0: if start_val > 149: # rebin *= 2 rebin += 1 # find nearest divisor while (zpj_entries[0][0].GetNbinsX() % rebin != 0): rebin += 1 if "multiplicity" in v_lower: if start_val > 300: rebin += 1 # find nearest divisor while (zpj_entries[0][0].GetNbinsX() % rebin != 0): rebin += 1 qgp.do_comparison_plot( zpj_entries, "%s/ptBinned/%s_pt%dto%d_zpj.%s" % (plot_dir, ang.var, start_val, end_val, OUTPUT_FMT), rebin=rebin, draw_opt=draw_opt, title=_title(qgc.ZpJ_LABEL, start_val, end_val), xtitle=xlabel, xlim=qgp.calc_auto_xlim([d[0] for d in zpj_entries]) if auto_xlim else xlim, ylim=ylim, data_first=has_data, mean_rel_error=0.4, subplot_type=None, lumi=cu.get_lumi_str(do_dijet=False, do_zpj=True))
def plot_detector_unfolded(self, do_dijet=True, do_zpj=True): for ibin, (bin_edge_low, bin_edge_high) in enumerate( zip(self.bins[:-1], self.bins[1:])): hbc_args = dict(ind=ibin, axis='pt', do_norm=True, do_div_bin_width=True, binning_scheme='generator') print("----------pt bin", ibin, "=", bin_edge_low, "-", bin_edge_high) def determine_num_dp(values): """Determine correct number of decimal places so that the smallest value has 1 digit If smallest > 1, then just returns 0 """ smallest_value = min([v for v in values if v > 0]) print('determine_num_dp', smallest_value) if smallest_value > 1: return 0 # use log10 to figure out exponent, then floor it # e.g. log10(5.5E-3) = -2.25...., floor(-2.25...) = -3 n_dp = abs(floor(log10(smallest_value))) return n_dp def setup_beta_function(name): fit = ROOT.TF1(name, "[2]*TMath::BetaDist(x,[0],[1])", 0, 1) fit.SetParameter(0, 3) fit.SetParLimits(0, 0, 100) fit.SetParameter(1, 5) fit.SetParLimits(1, 0, 100) fit.SetParameter(2, 0.05) fit.SetParLimits(2, 0, 10) # fit.SetParameter(3, 0) # fit.SetParLimits(3, 0, 10) # fit.SetParameter(4, 1) # fit.SetParLimits(4, 0.1, 10) return fit fit_opts = "S" # Weird setup here: basically need all the values going into legend first, # to be able to determine the number of decimal points # Then we can actually create the Contributions and plot afterwards dijet_detector_hist, dijet_unfolded_hist = None, None dijet_detector_mean, dijet_detector_mean_err = None, None dijet_unfolded_mean, dijet_unfolded_mean_err = None, None zpj_detector_hist, zpj_unfolded_hist = None, None zpj_detector_mean, zpj_detector_mean_err = None, None zpj_unfolded_mean, zpj_unfolded_mean_err = None, None dijet_entries, zpj_entries = [], [] errors = [] if do_dijet: # get detector-level data dijet_detector_hist = self.dijet_hbc.get_bin_plot( 'input_hist_gen_binning_bg_subtracted', **hbc_args) dijet_detector_mean, dijet_detector_mean_err = self.get_uncorrelated_mean_err( dijet_detector_hist, is_density=True) errors.append(dijet_detector_mean_err) # fit with beta function # dijet_detector_fit = setup_beta_function("beta_fit_dijet_detector") # fit_result = dijet_detector_hist.Fit(dijet_detector_fit, fit_opts, "") # fit_result.Print() # get unfolded data dijet_unfolded_hist = self.dijet_hbc.get_bin_plot( "unfolded", **hbc_args) dijet_cov_matrix = self.dijet_hbc.get_bin_plot( self.dijet_region['unfolder'].total_ematrix_name, **hbc_args) dijet_unfolded_mean, dijet_unfolded_mean_err = self.get_correlated_mean_err( dijet_unfolded_hist, dijet_cov_matrix, is_density=True) errors.append(dijet_unfolded_mean_err) # dijet_unfolded_fit = setup_beta_function("beta_fit_dijet_unfolded") # fit_result = dijet_unfolded_hist.Fit(dijet_unfolded_fit, fit_opts, "") # fit_result.Print() if do_zpj: # get detector-level data zpj_detector_hist = self.zpj_hbc.get_bin_plot( 'input_hist_gen_binning_bg_subtracted', **hbc_args) zpj_detector_mean, zpj_detector_mean_err = self.get_uncorrelated_mean_err( zpj_detector_hist, is_density=True) errors.append(zpj_detector_mean_err) # zpj_detector_fit = setup_beta_function("beta_fit_zpj_detector") # fit_result = zpj_detector_hist.Fit(zpj_detector_fit, fit_opts, "") # fit_result.Print() # get unfolded data zpj_unfolded_hist = self.zpj_hbc.get_bin_plot( "unfolded", **hbc_args) zpj_cov_matrix = self.zpj_hbc.get_bin_plot( self.zpj_region['unfolder'].total_ematrix_name, **hbc_args) zpj_unfolded_mean, zpj_unfolded_mean_err = self.get_correlated_mean_err( zpj_unfolded_hist, zpj_cov_matrix, is_density=True) errors.append(zpj_unfolded_mean_err) # zpj_unfolded_fit = setup_beta_function("beta_fit_zpj_unfolded") # fit_result = zpj_unfolded_hist.Fit(zpj_unfolded_fit, fit_opts, "") # fit_result.Print() # n_dp = determine_num_dp(errors) n_dp = 3 # kerning necessary as it puts massive space around #pm # but the first #kern doesn't affect the space after #pm as much (?!), # so I have to add another one with harder kerning # we use %.(n_dp)f as our float format str to ensure the correct number of dp are shown (and not rounded off) stat_template = 'Mean = {:.%df}#kern[-0.2dx]{{ #pm}}#kern[-0.5dx]{{ }}{}' % ( n_dp) err_template = "{:.%df}" % n_dp def _stat_label(mean, err, dp): err_str = err_template.format(err) # if the error is so small that it would display as 0.000, # i.e. < 0.0005, instead show < 0.001 if err < 5 * 10**(-dp - 1): err_str = "#lower[-0.09dy]{<}#kern[-0.75dx]{ }" + err_template.format( 1 * 10**(-dp)) return stat_template.format(round(mean, dp), err_str) if do_dijet: dijet_entries.append( Contribution( dijet_detector_hist, label='Detector-level (stat. only)\n%s' % (_stat_label(dijet_detector_mean, dijet_detector_mean_err, n_dp)), line_color=self.plot_colours['dijet_colour'], line_width=self.line_width, line_style=self.line_style_detector, marker_color=self.plot_colours['dijet_colour'], marker_style=cu.Marker.get('circle', filled=False), marker_size=0.75, subplot=zpj_detector_hist if do_zpj else None)) dijet_entries.append( Contribution( dijet_unfolded_hist, label='Particle-level\n%s' % (_stat_label(dijet_unfolded_mean, dijet_unfolded_mean_err, n_dp)), line_color=self.plot_colours['dijet_colour'], line_width=self.line_width, line_style=1, marker_color=self.plot_colours['dijet_colour'], marker_style=cu.Marker.get('circle', filled=True), marker_size=0.75, subplot=zpj_unfolded_hist if do_zpj else None)) if do_zpj: zpj_entries.append( Contribution( zpj_detector_hist, label='Detector-level (stat. only)\n%s' % (_stat_label( zpj_detector_mean, zpj_detector_mean_err, n_dp)), line_color=self.plot_colours['zpj_colour'], line_width=self.line_width, line_style=self.line_style_detector, marker_color=self.plot_colours['zpj_colour'], marker_style=cu.Marker.get('square', filled=False), marker_size=0.75)) zpj_entries.append( Contribution( zpj_unfolded_hist, label='Particle-level\n%s' % (_stat_label( zpj_unfolded_mean, zpj_unfolded_mean_err, n_dp)), line_color=self.plot_colours['zpj_colour'], line_width=self.line_width, line_style=1, marker_color=self.plot_colours['zpj_colour'], marker_style=cu.Marker.get('square', filled=True), marker_size=0.75)) all_entries = list(chain(dijet_entries, zpj_entries)) plot = Plot( all_entries, ytitle=self.pt_bin_normalised_differential_label, title=self.get_pt_bin_title(bin_edge_low, bin_edge_high), legend=True, xlim=qgp.calc_auto_xlim( all_entries), # set x lim to where data is non-0 what="hist", xtitle=self.particle_title, has_data=self.has_data, ylim=[0, None], is_preliminary=self.is_preliminary) # plot.default_canvas_size = (600, 600) # plot.left_margin = 0.2 # plot.left_title_offset_fudge_factor = 8 plot.y_padding_max_linear = 1.8 plot.top_margin = 0.07 plot.title_start_y = 0.888 plot.cms_text_y = 0.94 plot.lumi = cu.get_lumi_str(do_dijet=do_dijet, do_zpj=do_zpj) if do_zpj and do_dijet: plot.subplot_type = 'ratio' plot.subplot_title = 'Dijet / Z+jet' plot.subplot_limits = (0.25, 2.75) # disable adding objects to legend & drawing - we'll do it manually # since we want proper error bar plot.do_legend = False plot.splitline_legend = False # plot.legend.SetFillColor(ROOT.kRed) # plot.legend.SetFillStyle(1001) plot.plot("NOSTACK E1 X0") # plot.get_modifier().GetYaxis().SetTitleOffset(plot.get_modifier().GetYaxis().GetTitleOffset()*1.5) plot.main_pad.cd() for e in [plot.contributions[0].obj, plot.contributions[2].obj]: e.Draw("HIST SAME") for e in [plot.contributions[1].obj, plot.contributions[3].obj]: e.Draw("L SAME") plot.canvas.cd() # unfolded_fit = ROOT.TF1("beta_fit_dijet_unfolded", "[2]*TMath::BetaDist(x,[0],[1])", 0, 1) # unfolded_fit.SetParameter(0, 3) # unfolded_fit.SetParLimits(0, 0, 100) # unfolded_fit.SetParameter(1, 5) # unfolded_fit.SetParLimits(1, 0, 100) # unfolded_fit.SetParameter(2, .1) # unfolded_fit.SetParLimits(2, 0, 1000) # # fit_result = unfolded_hist.Fit(unfolded_fit, "EMSR", "", 0, 1) # # fit_result.Print() # unfolded_fit.SetLineColor(ROOT.kRed) # unfolded_fit.SetLineWidth(2) # plot.main_pad.cd() # unfolded_fit.Draw("SAME") # Create dummy graphs with the same styling to put into the legend dummy_gr = ROOT.TGraphErrors(1, array('d', [1]), array('d', [1]), array('d', [1]), array('d', [1])) dummies = [] # to stop garbage collection dummy_entries = [] # to stop garbage collection label_height = 0.03 legend_height = 0.12 legend_x1 = 0.54 legend_x2 = 0.75 # this doesn't really control width - legend_text_size mainly does label_left_offset = 0.01 label_text_size = 0.032 label_top = plot.title_start_y legend_text_size = 0.028 inter_region_offset = 0.025 if do_dijet: dijet_legend = plot.legend.Clone() dijet_legend.SetX1(legend_x1) dijet_legend.SetX2(legend_x2) dijet_legend.SetY1(label_top - label_height - legend_height) dijet_legend.SetY2(label_top - label_height + 0.01) dijet_legend.SetTextSize(legend_text_size) # Add text with region label dijet_pt = ROOT.TPaveText(legend_x1 - label_left_offset, label_top - label_height, legend_x2 - label_left_offset, label_top, "NDC NB") dijet_pt.SetFillStyle(0) dijet_pt.SetBorderSize(0) text = dijet_pt.AddText(qgc.Dijet_CEN_LABEL) text.SetTextAlign(11) text.SetTextFont(62) text.SetTextSize(label_text_size) dummies.append(dijet_pt) dummies.append(text) dijet_pt.Draw() for cont in dijet_entries: this_dummy_entry = dummy_gr.Clone() cont.update_obj_styling(this_dummy_entry) if "\n" in cont.label: parts = cont.label.split("\n") dijet_legend.AddEntry( this_dummy_entry, "#splitline{%s}{%s}" % (parts[0], parts[1]), "LEP") else: dijet_legend.AddEntry(this_dummy_entry, cont.label, "LEP") dummy_entries.append( this_dummy_entry) # to avoid garbage collection dijet_legend.Draw() dummies.append(dijet_legend) # setup for Z+J label_top -= label_height + legend_height + inter_region_offset if do_zpj: zpj_legend = plot.legend.Clone() zpj_legend.SetX1(legend_x1) zpj_legend.SetX2(legend_x2) zpj_legend.SetY1(label_top - label_height - legend_height) zpj_legend.SetY2(label_top - label_height + 0.01) zpj_legend.SetTextSize(legend_text_size) # Add text with region label zpj_pt = ROOT.TPaveText(legend_x1 - label_left_offset, label_top - label_height, legend_x2 - label_left_offset, label_top, "NDC NB") zpj_pt.SetFillStyle(0) zpj_pt.SetBorderSize(0) text = zpj_pt.AddText(qgc.ZpJ_LABEL) text.SetTextAlign(11) text.SetTextFont(62) text.SetTextSize(label_text_size) dummies.append(zpj_pt) dummies.append(text) zpj_pt.Draw() for cont in zpj_entries: this_dummy_entry = dummy_gr.Clone() cont.update_obj_styling(this_dummy_entry) if "\n" in cont.label: parts = cont.label.split("\n") zpj_legend.AddEntry( this_dummy_entry, "#splitline{%s}{%s}" % (parts[0], parts[1]), "LEP") else: zpj_legend.AddEntry(this_dummy_entry, cont.label, "LEP") dummy_entries.append(this_dummy_entry) zpj_legend.Draw() dummies.append(zpj_legend) # Add legend to ratio plot plot.subplot_pad.cd() for e in [plot.subplot_contributions[0]]: e.Draw("HIST SAME") for e in [plot.subplot_contributions[1]]: e.Draw("L SAME") plot.subplot_leg = ROOT.TLegend(0.3, 0.73, 0.9, 0.9) plot.subplot_leg.SetTextSize(0.07) plot.subplot_leg.SetFillStyle(0) plot.subplot_leg.SetNColumns(2) plot.subplot_leg.AddEntry(dummy_entries[0], "Detector-level", "LEP") plot.subplot_leg.AddEntry(dummy_entries[1], "Particle-level", "LEP") plot.subplot_leg.Draw() plot.canvas.cd() parts = [ 'detector_unfolded', 'dijet' if do_dijet else None, 'zpj' if do_zpj else None, self.append, 'bin_%d' % ibin, 'divBinWidth', f'{self.paper_str}.{self.output_fmt}' ] filename = '_'.join([x for x in parts if x]) plot.save("%s/%s" % (self.output_dir, filename)) print("%s/%s" % (self.output_dir, filename))
def do_plots(root_dir, title): # QG variable plots pt_bins = qgc.PT_BINS[:] print(pt_bins) var_list = qgc.COMMON_VARS var_prepend = "" radius, pus = cu.get_jet_config_from_dirname(root_dir) jet_str = "AK%s PF %s" % (radius.upper(), pus.upper()) if radius == "8": pt_bins = qgc.PT_BINS[2:] print(pt_bins) single_mu_tfile = cu.TFileCacher(os.path.join(root_dir, qgc.SINGLE_MU_FILENAME)) dy_tfile = cu.TFileCacher(os.path.join(root_dir, qgc.DY_FILENAME)) dy_hpp_tfile = cu.TFileCacher(os.path.join(root_dir, qgc.DY_HERWIG_FILENAME)) jetht_zb_tfile = cu.TFileCacher(os.path.join(root_dir, qgc.JETHT_ZB_FILENAME)) qcd_tfile = cu.TFileCacher(os.path.join(root_dir, qgc.QCD_FILENAME)) qcd_hpp_tfile = cu.TFileCacher(os.path.join(root_dir, qgc.QCD_HERWIG_FILENAME)) for gr_append in ["", "_groomed"]: if gr_append == "_groomed": print("Doing groomed plots...") else: print("Doing ungroomed plots...") zpj_dirname = "ZPlusJets_QG%s" % (gr_append) dj_cen_dirname = "Dijet_QG_central_tighter%s" % (gr_append) dj_fwd_dirname = "Dijet_QG_forward_tighter%s" % (gr_append) for ang in var_list[:]: print("...Doing", ang.name) v = "%s%s_vs_pt" % (var_prepend, ang.var) zpj_2d_entries = [] dijet_cen_2d_entries = [] dijet_fwd_2d_entries = [] zpj_1d_entries = [] dijet_cen_1d_entries = [] dijet_fwd_1d_entries = [] for pt_ind, (start_val, end_val) in enumerate(pt_bins): entries = [] zpj_entries = [] dijet_cen_entries = [] dijet_fwd_entries = [] # Get all plots lw = 2 msize = 1.1 data_line_width = lw mc_msize = 1E-3 # small enough to not be seen but not 0 - otherwise the horizontal lines on error bars don't get drawn mgpy_label = "MG5+Pythia8" hpp_label = "Herwig++" #################### # Z+JETS REGION #################### # SINGLE MU DATA if single_mu_tfile: h2d_dyj_data = single_mu_tfile.get("%s/%s" % (zpj_dirname, v)) dy_kwargs_data = dict(line_color=qgc.SINGLE_MU_COLOUR, line_width=data_line_width, fill_color=qgc.SINGLE_MU_COLOUR, marker_color=qgc.SINGLE_MU_COLOUR, marker_style=cu.Marker.get(qgc.DY_MARKER), marker_size=msize*0.7, label="Data") zpj_data_hist = qgp.get_projection_plot(h2d_dyj_data, start_val, end_val) entries.append((zpj_data_hist, dy_kwargs_data)) zpj_entries.append((zpj_data_hist, dy_kwargs_data)) if pt_ind == 0: zpj_2d_entries.append((h2d_dyj_data, dy_kwargs_data)) # PYTHIA DY MC if dy_tfile: h2d_dyj_mc = dy_tfile.get("%s/%s" % (zpj_dirname, v)) dy_kwargs_mc = dict(line_color=qgc.DY_COLOUR, line_width=lw, fill_color=qgc.DY_COLOUR, marker_color=qgc.DY_COLOUR, marker_style=cu.Marker.get(qgc.DY_MARKER), marker_size=mc_msize, label=mgpy_label, subplot=zpj_data_hist) entries.append((qgp.get_projection_plot(h2d_dyj_mc, start_val, end_val), dy_kwargs_mc)) zpj_entries.append((qgp.get_projection_plot(h2d_dyj_mc, start_val, end_val), dy_kwargs_mc)) if pt_ind == 0: zpj_2d_entries.append((h2d_dyj_mc, dy_kwargs_mc)) # HERWIG++ DY if dy_hpp_tfile: h2d_dyj_mc_hpp = dy_hpp_tfile.get("%s/%s" % (zpj_dirname, v)) col_hpp = qgc.DY_COLOURS[2] dy_kwargs_mc_hpp = dict(line_color=col_hpp, line_width=lw, fill_color=col_hpp, marker_color=col_hpp, marker_style=cu.Marker.get(qgc.DY_MARKER), marker_size=mc_msize, label=hpp_label, subplot=zpj_data_hist) entries.append((qgp.get_projection_plot(h2d_dyj_mc_hpp, start_val, end_val), dy_kwargs_mc_hpp)) zpj_entries.append((qgp.get_projection_plot(h2d_dyj_mc_hpp, start_val, end_val), dy_kwargs_mc_hpp)) if pt_ind == 0: zpj_2d_entries.append((h2d_dyj_mc_hpp, dy_kwargs_mc_hpp)) # MG+HERWIG++ DY # if end_val < 151: # h2d_dyj_mc3 = get("%s/%s" % (zpj_dirname, v)) # col4 = qgc.DY_COLOURS[3] # dy_kwargs_mc3 = dict(line_color=col4, line_width=lw, fill_color=col4, # marker_color=col4, marker_style=cu.Marker.get(qgc.DY_MARKER), marker_size=0, # label="MG+Herwig++", # subplot=zpj_data_hist) # entries.append((qgp.get_projection_plot(h2d_dyj_mc3, start_val, end_val), dy_kwargs_mc3)) # zpj_entries.append((qgp.get_projection_plot(h2d_dyj_mc3, start_val, end_val), dy_kwargs_mc3)) # if pt_ind == 0: # zpj_2d_entries.append((h2d_dyj_mc3, dy_kwargs_mc3)) # else: # zpj_entries.append(None) #################### # DIJET CENTRAL REGION #################### # JETHT/ZEROBIAS DATA if jetht_zb_tfile: h2d_qcd_cen_data = jetht_zb_tfile.get("%s/%s" % (dj_cen_dirname, v)) # use already merged jetht+zb qcd_cen_kwargs_data = dict(line_color=qgc.JETHT_COLOUR, line_width=data_line_width, fill_color=qgc.JETHT_COLOUR, marker_color=qgc.JETHT_COLOUR, marker_style=cu.Marker.get(qgc.QCD_MARKER), marker_size=msize, label="Data") dijet_cen_data_hist = qgp.get_projection_plot(h2d_qcd_cen_data, start_val, end_val) entries.append((dijet_cen_data_hist, qcd_cen_kwargs_data)) dijet_cen_entries.append((dijet_cen_data_hist, qcd_cen_kwargs_data)) if pt_ind == 0: dijet_cen_2d_entries.append((h2d_qcd_cen_data, qcd_cen_kwargs_data)) # MG+PYTHIA QCD MC if qcd_tfile: h2d_qcd_cen_mc = qcd_tfile.get("%s/%s" % (dj_cen_dirname, v)) qcd_cen_kwargs_mc = dict(line_color=qgc.QCD_COLOUR, line_width=lw, fill_color=qgc.QCD_COLOUR, marker_color=qgc.QCD_COLOUR, marker_style=cu.Marker.get(qgc.QCD_MARKER), marker_size=mc_msize, label=mgpy_label, subplot=dijet_cen_data_hist) dijet_mgpy_hist = qgp.get_projection_plot(h2d_qcd_cen_mc, start_val, end_val) entries.append((dijet_mgpy_hist, qcd_cen_kwargs_mc)) dijet_cen_entries.append((dijet_mgpy_hist, qcd_cen_kwargs_mc)) if pt_ind == 0: dijet_cen_2d_entries.append((h2d_qcd_cen_mc, qcd_cen_kwargs_mc)) # PYTHIA ONLY # if qcd_py_tfile: # col = qgc.QCD_COLOURS[2] # h2d_qcd_cen_mc2 = qcd_py_tfile.get("%s/%s" % (dj_cen_dirname, v)) # qcd_cen_kwargs_mc2 = dict(line_color=col, line_width=lw, fill_color=col, # marker_color=col, marker_style=cu.Marker.get(qgc.QCD_MARKER), marker_size=mc_msize, # label="Pythia8", # subplot=dijet_cen_data_hist) # entries.append((qgp.get_projection_plot(h2d_qcd_cen_mc2, start_val, end_val), qcd_cen_kwargs_mc2)) # dijet_cen_entries.append((qgp.get_projection_plot(h2d_qcd_cen_mc2, start_val, end_val), qcd_cen_kwargs_mc2)) # if pt_ind == 0: # dijet_cen_2d_entries.append((h2d_qcd_cen_mc2, qcd_cen_kwargs_mc2)) # HERWIG++ QCD if qcd_hpp_tfile: h2d_qcd_cen_mc_hpp = qcd_hpp_tfile.get("%s/%s" % (dj_cen_dirname, v)) qcd_cen_kwargs_mc_hpp = dict(line_color=qgc.HERWIGPP_QCD_COLOUR, line_width=lw, fill_color=qgc.HERWIGPP_QCD_COLOUR, marker_color=qgc.HERWIGPP_QCD_COLOUR, marker_style=cu.Marker.get(qgc.QCD_MARKER), marker_size=mc_msize, label=hpp_label, subplot=dijet_cen_data_hist) dijet_hpp_hist = qgp.get_projection_plot(h2d_qcd_cen_mc_hpp, start_val, end_val) entries.append((dijet_hpp_hist, qcd_cen_kwargs_mc_hpp)) dijet_cen_entries.append((dijet_hpp_hist, qcd_cen_kwargs_mc_hpp)) if pt_ind == 0: dijet_cen_2d_entries.append((h2d_qcd_cen_mc_hpp, qcd_cen_kwargs_mc_hpp)) #################### # DIJET FORWARD REGION #################### # JETHT/ZEROBIAS DATA if jetht_zb_tfile: h2d_qcd_fwd_data = jetht_zb_tfile.get("%s/%s" % (dj_fwd_dirname, v)) # use already merged jetht+zb qcd_fwd_kwargs_data = dict(line_color=qgc.JETHT_COLOUR, line_width=data_line_width, fill_color=qgc.JETHT_COLOUR, marker_color=qgc.JETHT_COLOUR, marker_style=cu.Marker.get('triangleDown'), marker_size=msize, label="Data") dijet_fwd_data_hist = qgp.get_projection_plot(h2d_qcd_fwd_data, start_val, end_val) entries.append((dijet_fwd_data_hist, qcd_fwd_kwargs_data)) dijet_fwd_entries.append((dijet_fwd_data_hist, qcd_fwd_kwargs_data)) if pt_ind == 0: dijet_fwd_2d_entries.append((h2d_qcd_fwd_data, qcd_fwd_kwargs_data)) # MG+PYTHIA QCD MC if qcd_tfile: h2d_qcd_fwd_mc = qcd_tfile.get("%s/%s" % (dj_fwd_dirname, v)) qcd_fwd_kwargs_mc = dict(line_color=qgc.QCD_COLOUR, line_width=lw, fill_color=qgc.QCD_COLOUR, marker_color=qgc.QCD_COLOUR, marker_style=cu.Marker.get(qgc.QCD_MARKER), marker_size=mc_msize, label=mgpy_label, subplot=dijet_fwd_data_hist) dijet_mgpy_hist = qgp.get_projection_plot(h2d_qcd_fwd_mc, start_val, end_val) entries.append((dijet_mgpy_hist, qcd_fwd_kwargs_mc)) dijet_fwd_entries.append((dijet_mgpy_hist, qcd_fwd_kwargs_mc)) if pt_ind == 0: dijet_fwd_2d_entries.append((h2d_qcd_fwd_mc, qcd_fwd_kwargs_mc)) # PYTHIA ONLY # if qcd_py_tfile: # col = qgc.QCD_COLOURS[2] # h2d_qcd_fwd_mc2 = qcd_py_tfile.get("%s/%s" % (dj_fwd_dirname, v)) # qcd_fwd_kwargs_mc2 = dict(line_color=col, line_width=lw, fill_color=col, # marker_color=col, marker_style=cu.Marker.get(qgc.QCD_MARKER), marker_size=mc_msize, # label="Pythia8", # subplot=dijet_fwd_data_hist) # entries.append((qgp.get_projection_plot(h2d_qcd_fwd_mc2, start_val, end_val), qcd_fwd_kwargs_mc2)) # dijet_fwd_entries.append((qgp.get_projection_plot(h2d_qcd_fwd_mc2, start_val, end_val), qcd_fwd_kwargs_mc2)) # if pt_ind == 0: # dijet_fwd_2d_entries.append((h2d_qcd_fwd_mc2, qcd_fwd_kwargs_mc2)) # HERWIG++ QCD if qcd_hpp_tfile: h2d_qcd_fwd_mc_hpp = qcd_hpp_tfile.get("%s/%s" % (dj_fwd_dirname, v)) qcd_fwd_kwargs_mc_hpp = dict(line_color=qgc.HERWIGPP_QCD_COLOUR, line_width=lw, fill_color=qgc.HERWIGPP_QCD_COLOUR, marker_color=qgc.HERWIGPP_QCD_COLOUR, marker_style=cu.Marker.get(qgc.QCD_MARKER), marker_size=mc_msize, label=hpp_label, subplot=dijet_fwd_data_hist) dijet_hpp_hist = qgp.get_projection_plot(h2d_qcd_fwd_mc_hpp, start_val, end_val) entries.append((dijet_hpp_hist, qcd_fwd_kwargs_mc_hpp)) dijet_fwd_entries.append((dijet_hpp_hist, qcd_fwd_kwargs_mc_hpp)) if pt_ind == 0: dijet_fwd_2d_entries.append((h2d_qcd_fwd_mc_hpp, qcd_fwd_kwargs_mc_hpp)) zpj_1d_entries.append(zpj_entries) dijet_cen_1d_entries.append(dijet_cen_entries) dijet_fwd_1d_entries.append(dijet_fwd_entries) ################# # SETUP PLOTTING ################# rebin = 2 v_lower = v.lower() if "multiplicity" in v_lower: rebin = 1 # elif "flavour" in v_lower or "thrust" in v_lower: # rebin = 1 # elif 'ptd' in v_lower: # rebin = 4 # elif 'lha_charged' in v_lower: # rebin = 4 # rebin = 1 xlim = None if "width" in v_lower or "ptd" in v_lower: xlim = (0, 1) elif "thrust" in v_lower: xlim = (0, 0.5) # elif "multiplicity" in v_lower and "ak4" in root_dir.lower(): # if end_val <= 150: # xlim = (0, 50) # else: # xlim = (0, 80) auto_xlim = False if "multiplicity" in v_lower or "thrust" in v_lower: auto_xlim = True ylim = [0, None] if "flavour" in v_lower: ylim = (0, 1) # elif "lha" in v_lower: # ylim = (0, 5) plot_dir = os.path.join(root_dir, "plots_lambda_mc_vs_data%s" % (gr_append)) subplot_title = "Simulation / Data" subplot_limits = (0, 2) xlabel = ang.name + " (" + ang.lambda_str + ")" if gr_append is not "": xlabel = "Groomed " + ang.name + " (" + ang.lambda_str + ")" def _title(region_str, start_val, end_val): pt_var_str = "p_{T}^{jet}" s = (("{jet_algo}\n" "{region_label}\n" "{bin_edge_low:g} < {pt_str} < {bin_edge_high:g} GeV") .format( jet_algo=jet_str, region_label=region_str, pt_str=pt_var_str, bin_edge_low=start_val, bin_edge_high=end_val)) if title is not None: s = "%s\n%s" % (s, title) return s has_data = True draw_opt = "NOSTACK HIST E1" # dj central only # dont' try to do multiple signal regions per plot, it looks rubbish if len(dijet_cen_entries) > 0: qgp.do_comparison_plot(dijet_cen_entries, "%s/ptBinned/%s_pt%dto%d_dijet_central.%s" % (plot_dir, v, start_val, end_val, OUTPUT_FMT), rebin=rebin, draw_opt=draw_opt, title=_title(qgc.Dijet_CEN_LABEL, start_val, end_val), xtitle=xlabel, xlim='auto' if auto_xlim else xlim, # don't use calc_auto_xlim, since do_comparison_plot will rebin it anyway ylim=ylim, data_first=has_data, mean_rel_error=0.4, subplot_type='ratio', subplot_title=subplot_title, subplot_limits=subplot_limits, lumi=cu.get_lumi_str(do_dijet=True, do_zpj=False)) # dj forward only if len(dijet_fwd_entries) > 0: qgp.do_comparison_plot(dijet_fwd_entries, "%s/ptBinned/%s_pt%dto%d_dijet_forward.%s" % (plot_dir, v, start_val, end_val, OUTPUT_FMT), rebin=rebin, draw_opt=draw_opt, title=_title(qgc.Dijet_FWD_LABEL, start_val, end_val), xtitle=xlabel, xlim='auto' if auto_xlim else xlim, ylim=ylim, data_first=has_data, mean_rel_error=0.4, subplot_type='ratio', subplot_title=subplot_title, subplot_limits=subplot_limits, lumi=cu.get_lumi_str(do_dijet=True, do_zpj=False)) # zpj only if len(zpj_entries) > 0: if start_val > 149: # rebin *= 2 rebin += 1 # find nearest divisor while (zpj_entries[0][0].GetNbinsX() % rebin != 0): rebin += 1 if "multiplicity" in v_lower: if start_val > 300: rebin += 1 # find nearest divisor while (zpj_entries[0][0].GetNbinsX() % rebin != 0): rebin += 1 qgp.do_comparison_plot(zpj_entries, "%s/ptBinned/%s_pt%dto%d_zpj.%s" % (plot_dir, v, start_val, end_val, OUTPUT_FMT), rebin=rebin, draw_opt=draw_opt, title=_title(qgc.ZpJ_LABEL, start_val, end_val), xtitle=xlabel, xlim=qgp.calc_auto_xlim([d[0] for d in zpj_entries]) if auto_xlim else xlim, ylim=ylim, data_first=has_data, mean_rel_error=0.4, subplot_type='ratio', subplot_title=subplot_title, subplot_limits=subplot_limits, lumi=cu.get_lumi_str(do_dijet=False, do_zpj=True)) # Do overall summary plots across all pt bins # ------------------------------------------------------------------ ylim_mean = None if "width" in v_lower or "ptd" in v_lower: ylim_mean = (0, 0.4) elif"thrust" in v_lower: ylim_mean = (0, 0.5) elif "multiplicity" in v_lower and "ak4" in root_dir.lower(): ylim_mean = (0, 100) ylim_mean = (0, 80) if end_val < 150: ylim_mean = (0, 50) ylim_mean=None ylim_rms=None # Setup variable names for MPL marker = "" if "_" in ang.name or "^" in ang.name: marker = "$" var_label = marker + ang.name + marker + " ($%s$)" % ang.lambda_str if gr_append != "": var_label = "Groomed " + marker + ang.name + marker + " ($%s$)" % ang.lambda_str # construct a dataframe from the hists # df = construct_dataframe_from_hists(dijet_cen_entries=dijet_cen_1d_entries, # dijet_fwd_entries=dijet_fwd_entries, # zpj_entries=zpj_entries) # pt_low = 88 if "8" in radius else 50 pt_low = pt_bins[0][0] qgp.do_mean_rms_summary_plot(dijet_cen_1d_entries, pt_bins, "%s/ptBinned/%s_box_dijet_cen_mpl.%s" % (plot_dir, v, OUTPUT_FMT), var_label=var_label, xlim=(pt_low, 4000), ylim_mean=ylim_mean, ylim_rms=ylim_rms, region_title="%s jets in %s" % (jet_str, qgc.Dijet_CEN_LABEL.lower())) qgp.do_mean_rms_summary_plot(dijet_fwd_1d_entries, pt_bins, "%s/ptBinned/%s_box_dijet_fwd_mpl.%s" % (plot_dir, v, OUTPUT_FMT), var_label=var_label, xlim=(pt_low, 4000), ylim_mean=ylim_mean, ylim_rms=ylim_rms, region_title="%s jets in %s" % (jet_str, qgc.Dijet_FWD_LABEL.lower())) # zpj_1d_entries[i][j] is the jth sample in the ith pt bin qgp.do_mean_rms_summary_plot(zpj_1d_entries, pt_bins, "%s/ptBinned/%s_box_zpj_mpl.%s" % (plot_dir, v, OUTPUT_FMT), var_label=var_label, xlim=(pt_low, 800), ylim_mean=ylim_mean, ylim_rms=ylim_rms, region_title="%s jets in %s" % (jet_str, qgc.ZpJ_LABEL))
def do_pileup_plot(input_dir, trigger_names, output_filename): # get histograms hists = [ cu.grab_obj_from_file( os.path.join(input_dir, 'MyDataPileupHistogram_%s.root' % t), 'pileup') for t in trigger_names ] h_up = cu.grab_obj_from_file( os.path.join(input_dir, 'MyDataPileupHistogram_PFJet500_72383.root'), 'pileup') h_down = cu.grab_obj_from_file( os.path.join(input_dir, 'MyDataPileupHistogram_PFJet500_66017.root'), 'pileup') h_down3 = cu.grab_obj_from_file( os.path.join(input_dir, 'MyDataPileupHistogram_PFJet500_59650.root'), 'pileup') ratio_up = h_up.Clone() ratio_up.Divide(hists[-1]) ratio_down = h_down.Clone() ratio_down.Divide(hists[-1]) # hists.append(h_up) # hists.append(h_down) # trigger_names.append('72.383') # trigger_names.append('66.017') # Create contributions mark = cu.Marker() n_hists = len(hists) conts = [ Contribution(h, label=t, line_width=2, line_color=cu.get_colour_seq(ind, n_hists), marker_color=cu.get_colour_seq(ind, n_hists), marker_style=m, normalise_hist=True) for ind, (h, t, m) in enumerate( zip(hists, trigger_names, mark.cycle(cycle_filling=True))) ] conts.insert( -1, Contribution( h_up, label='72.383 (+4.6%)', line_width=2, line_color=ROOT.kRed, marker_color=ROOT.kRed, normalise_hist=True, )) conts.insert( -1, Contribution( h_down, label='66.017 (-4.6%)', line_width=2, line_color=ROOT.kMagenta, marker_color=ROOT.kMagenta, normalise_hist=True, )) conts.insert( -1, Contribution( h_down3, label='59.650 (-13.8%)', line_width=2, line_style=1, line_color=ROOT.kMagenta + 3, marker_color=ROOT.kMagenta + 3, normalise_hist=True, )) print([h.Integral() for h in hists]) plot = Plot( conts, what='hist', xtitle='Pileup', lumi=cu.get_lumi_str(do_dijet=True, do_zpj=True), subplot_type='ratio', subplot=conts[-1], ) plot.subplot_maximum_ceil = 4.5 plot.plot("NOSTACK HISTE", "NOSTACK HIST") plot.subplot_pad.cd() # To shade region between up and down hists, need to create graph with # the error bars as the up/down variations x_low = np.array([ ratio_up.GetBinLowEdge(i) for i in range(1, ratio_up.GetNbinsX() + 1) ], dtype=float) x_high = np.array([ ratio_up.GetBinLowEdge(i) for i in range(2, ratio_up.GetNbinsX() + 2) ], dtype=float) x_mid = 0.5 * (x_low + x_high) x_err = x_high - x_low y_high = np.array([ max(ratio_up.GetBinContent(i), ratio_down.GetBinContent(i)) for i in range(1, ratio_up.GetNbinsX() + 1) ]) y_high -= 1 y_low = np.array([ min(ratio_up.GetBinContent(i), ratio_down.GetBinContent(i)) for i in range(1, ratio_up.GetNbinsX() + 1) ]) y_low = 1 - y_low y_mid = np.array([1. for i in range(1, ratio_up.GetNbinsX() + 1)]) gr = ROOT.TGraphAsymmErrors(len(x_mid), x_mid, y_mid, x_err, x_err, y_low, y_high) gr.SetFillColor(ROOT.kGray + 2) gr.SetFillStyle(3254) gr.Draw('2 SAME') plot.subplot_container.Draw("SAME NOSTACK HIST") plot.subplot_line.Draw() plot.save(output_filename)