Example #1
0
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)))
Example #6
0
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))
Example #9
0
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)