def plot_unfolded_normalised_pt_bin_offset(self, bin_offset_2=0): for ibin, (bin_edge_low, bin_edge_high) in enumerate(zip(self.bins[:-1], self.bins[1:])): # print(bin_edge_low, bin_edge_high) ind2 = ibin+bin_offset_2 if ind2 < 0: # print("...skipping") continue hbc1_args = dict(ind=ibin, binning_scheme='generator') unfolded1_hist_bin_stat_errors = self.hist_bin_chopper1.get_pt_bin_normed_div_bin_width('unfolded_stat_err', **hbc1_args) hbc2_args = dict(ind=ind2, binning_scheme='generator') unfolded2_hist_bin_stat_errors = self.hist_bin_chopper2.get_pt_bin_normed_div_bin_width('unfolded_stat_err', **hbc2_args) entries = [ Contribution(unfolded1_hist_bin_stat_errors, label="Data (stat. unc.)\n%s" % self.setup1.label, line_color=self.plot_styles['unfolded_stat_colour'], line_width=self.line_width, line_style=1, marker_color=self.plot_styles['unfolded_stat_colour'], marker_style=cu.Marker.get('circle'), marker_size=0.75), Contribution(unfolded2_hist_bin_stat_errors, label="Data (stat. unc.)\n%s" % self.setup2.label, line_color=self.plot_styles['unfolded_unreg_colour'], line_width=self.line_width, line_style=1, marker_color=self.plot_styles['unfolded_unreg_colour'], marker_style=cu.Marker.get('square', filled=False), marker_size=0.75, subplot=unfolded1_hist_bin_stat_errors), ] if not self.check_entries(entries, "plot_unfolded_normalised_pt_bin_offset %d" % (ibin)): return plot = Plot(entries, ytitle=self.setup1.pt_bin_normalised_differential_label, title=self.get_pt_bin_title(bin_edge_low, bin_edge_high), xlim=qgp.calc_auto_xlim(entries), subplot_limits=(0.8, 1.2), **self.pt_bin_plot_args) self._modify_plot(plot) plot.subplot_title = "* / %s" % (self.region1['label']) plot.plot("NOSTACK E1") plot.save("%s/compare_unfolded_%s_bin_%d_divBinWidth.%s" % (self.setup1.output_dir, self.setup1.append, ibin, self.setup1.output_fmt))
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 plot_unfolded_with_yoda_normalised(self, do_chi2=False, do_zoomed=True): data_total_errors_style = dict( label="Data (total unc.)", line_color=self.plot_styles['unfolded_total_colour'], line_width=self.line_width, line_style=1, marker_color=self.plot_styles['unfolded_total_colour'], marker_style=cu.Marker.get('circle'), marker_size=self.plot_styles['unfolded_marker_size'], leg_draw_opt="LEP") data_stat_errors_style = dict( label="Data (stat. unc.)", line_color=self.plot_styles['unfolded_stat_colour'], line_width=self.line_width, line_style=1, marker_color=self.plot_styles['unfolded_stat_colour'], marker_style=cu.Marker.get('circle'), marker_size=0.0001, leg_draw_opt="LEP" ) # you need a non-0 marker to get the horizontal bars at the end of errors mc_style = dict(label=self.region['mc_label'], line_color=self.plot_styles['gen_colour'], line_width=self.line_width, marker_color=self.plot_styles['gen_colour'], marker_size=self.plot_styles['gen_marker_size'], marker_style=self.plot_styles['gen_marker'], leg_draw_opt="LEP" if self.plot_styles['gen_marker_size'] > 0 else "LE") rivet_path, rivet_region, rivet_radius, rivet_lambda, rivet_pt_bins = get_matching_rivet_setup( self.setup) for ibin, (bin_edge_low, bin_edge_high) in enumerate( zip(self.bins[:-1], self.bins[1:])): hbc_args = dict(ind=ibin, binning_scheme='generator') mc_gen_hist_bin = self.hist_bin_chopper.get_pt_bin_normed_div_bin_width( 'hist_truth', **hbc_args) unfolded_hist_bin_stat_errors = self.hist_bin_chopper.get_pt_bin_normed_div_bin_width( 'unfolded_stat_err', **hbc_args) unfolded_hist_bin_total_errors = self.hist_bin_chopper.get_pt_bin_normed_div_bin_width( 'unfolded', **hbc_args) # Get RIVET hists, which are absolute counts, so need normalising rivet_hist_name = '/%s/%s' % ( rivet_path, rn.get_plot_name(rivet_radius, rivet_region, rivet_lambda, rivet_pt_bins[ibin])) rivet_hists = [ qgp.normalise_hist_divide_bin_width( yoda.root.to_root(ent['yoda_dict'][rivet_hist_name])) for ent in self.rivet_entries ] # Create copy of data to go on top of stat unc, # but remove vertical error bar so we can see the stat unc # Note that you CAN'T set it to 0, otherwise vertical lines connecting # bins start being drawn. Instead set it to some super small value. unfolded_hist_bin_total_errors_marker_noerror = unfolded_hist_bin_total_errors.Clone( ) # clone to avoid restyling the original as well for i in range( 1, unfolded_hist_bin_total_errors_marker_noerror.GetNbinsX() + 1): unfolded_hist_bin_total_errors_marker_noerror.SetBinError( i, 1E-100) data_entries = [ Contribution(unfolded_hist_bin_total_errors, **data_total_errors_style), Contribution(unfolded_hist_bin_stat_errors, **data_stat_errors_style), # do data with black marker to get it on top Contribution(unfolded_hist_bin_total_errors_marker_noerror, **data_total_errors_style), ] # For subplot to ensure only MC errors drawn, not MC+data data_no_errors = unfolded_hist_bin_total_errors_marker_noerror.Clone( ) cu.remove_th1_errors(data_no_errors) this_mc_style = deepcopy(mc_style) rivet_styles = [] for ind, _ in enumerate(rivet_hists): s_dict = self.rivet_entries[ind]['style_dict'] rivet_styles.append( dict(label=s_dict['label'], line_color=s_dict['color'], line_width=self.line_width, marker_color=s_dict['color'], marker_size=s_dict.get( 'marker_size', self.plot_styles['gen_marker_size']), marker_style=s_dict['marker_style'], leg_draw_opt="LEP" if self.plot_styles['gen_marker_size'] > 0 else "LE")) # Calculate chi2 between data and MCs if desired if do_chi2: # print("unfolded_alt_truth bin", ibin) ematrix = self.hist_bin_chopper.get_pt_bin_normed_div_bin_width( self.unfolder.total_ematrix_name, **hbc_args) # stats are chi2, ndof, p mc_stats = calc_chi2_stats(unfolded_hist_bin_total_errors, mc_gen_hist_bin, ematrix) # print(mc_stats) # print(alt_mc_stats) nbins = sum([ 1 for i in range( 1, unfolded_hist_bin_total_errors.GetNbinsX() + 1) if unfolded_hist_bin_total_errors.GetBinContent(i) != 0 ]) # reduced_chi2 = mc_stats[0] / nbins # alt_reduced_chi2 = alt_mc_stats[0] / nbins n_sig_fig = 2 chi2_template = "\n#lower[-0.1]{{(#chi^{{2}} / N_{{bins}} = {chi2:g} / {nbins:d})}}" this_mc_style['label'] += chi2_template.format(chi2=cu.nsf( mc_stats[0], n_sig_fig), nbins=nbins) for ind, h in enumerate(rivet_hists): this_stats = calc_chi2_stats( unfolded_hist_bin_total_errors, h, ematrix) rivet_styles[ind]['label'] += chi2_template.format( chi2=cu.nsf(this_stats[0], n_sig_fig), nbins=nbins) mc_entries = [ Contribution(mc_gen_hist_bin, subplot=data_no_errors, **this_mc_style), ] for h, s_dict in zip(rivet_hists, rivet_styles): mc_entries.append( Contribution(h, subplot=data_no_errors, **s_dict)) entries = [ # Draw MC *mc_entries, # Draw data after to put on top of MC *data_entries ] func_name = cu.get_current_func_name() if not self.check_entries(entries, "%s bin %d" % (func_name, ibin)): return ymin = 0 if np.any( cu.th1_to_ndarray(unfolded_hist_bin_total_errors)[0] < 0): ymin = None # let it do its thing and auto calc ymin max_rel_err = 0.5 if "multiplicity" in self.setup.angle.var.lower( ) else -1 plot = Plot( entries, ytitle=self.setup.pt_bin_normalised_differential_label, title=self.get_pt_bin_title(bin_edge_low, bin_edge_high), legend=True, xlim=qgp.calc_auto_xlim( entries[2:3], max_rel_err=0.5), # set x lim to where data is non-0 ylim=[ymin, None], **self.pt_bin_plot_args) plot.subplot_title = qgc.SIM_DATA_STR self._modify_plot_paper(plot) # disable adding objects to legend & drawing - we'll do it manually plot.do_legend = False plot.legend.SetTextSize(0.03) plot.legend.SetY1(0.6) plot.legend.SetX1(0.57) plot.legend.SetX2(0.93) if len(entries) > 4: # if lots of entries, try auto-expand plot.legend.SetY1(0.6 - (0.02 * (len(entries) - 4))) # plot.legend.SetEntrySeparation(0.005) subplot_draw_opts = "NOSTACK E1" plot.plot("NOSTACK E1", subplot_draw_opts) dummy_graphs = qgp.do_fancy_legend(chain(data_entries[:2], mc_entries), plot, use_splitline=False) plot.canvas.cd() plot.legend.Draw() # Create hists for data with error region for ratio # Easiest way to get errors right is to do data (with 0 errors) # and divide by data (with errors), as if you had MC = data with 0 error data_stat_ratio = data_no_errors.Clone() data_stat_ratio.Divide(unfolded_hist_bin_stat_errors) data_stat_ratio.SetFillStyle(3245) data_stat_ratio.SetFillColor( self.plot_styles['unfolded_stat_colour']) data_stat_ratio.SetLineWidth(0) data_stat_ratio.SetMarkerSize(0) data_total_ratio = data_no_errors.Clone() data_total_ratio.Divide(unfolded_hist_bin_total_errors) data_total_ratio.SetFillStyle(3254) data_total_ratio.SetFillColor( self.plot_styles['unfolded_total_colour']) data_total_ratio.SetLineWidth(0) data_total_ratio.SetMarkerSize(0) # now draw the data error shaded area # this is a bit hacky - basically draw them on the ratio pad, # then redraw the existing hists & line to get them ontop # note that we use "same" for all - this is to keep the original axes # (we may want to rethink this later?) plot.subplot_pad.cd() draw_opt = "E2 SAME" data_stat_ratio.Draw(draw_opt) data_total_ratio.Draw(draw_opt) plot.subplot_line.Draw() plot.subplot_container.Draw("SAME" + subplot_draw_opts) # Add subplot legend x_left = 0.25 y_bottom = 0.75 width = 0.67 height = 0.15 plot.subplot_legend = ROOT.TLegend(x_left, y_bottom, x_left + width, y_bottom + height) plot.subplot_legend.AddEntry(data_total_ratio, qgc.DATA_TOTAL_UNC_STR, "F") plot.subplot_legend.AddEntry(data_stat_ratio, qgc.DATA_STAT_UNC_STR, "F") plot.subplot_legend.SetTextSize(0.085) plot.subplot_legend.SetFillStyle(0) plot.subplot_legend.SetNColumns(2) plot.subplot_legend.Draw() plot.canvas.cd() stp = self.setup fname = f"unfolded_{stp.append}_rivet_bin_{ibin:d}_divBinWidth{stp.paper_str}.{stp.output_fmt}" self.save_plot(plot, os.path.join(stp.output_dir, fname)) # Do version with small x values only if do_zoomed: if self.setup.angle.var in [ "jet_thrust_charged", "jet_width_charged", "jet_thrust", "jet_width" ]: # plot.ylim = (1E-5) plot.y_padding_max_log = 50 plot.y_padding_min_log = 0.5 plot.ylim = None plot.set_logy(do_exponent=False, do_more_labels=False) fname = f"unfolded_{stp.append}_alt_truth_bin_{ibin:d}_divBinWidth_logY.{stp.output_fmt}" self.save_plot(plot, os.path.join(stp.output_dir, fname)) if self.setup.angle.var in [ "jet_LHA_charged", "jet_thrust_charged", "jet_width_charged", "jet_thrust", "jet_width" ]: bin_edges = cu.get_bin_edges(mc_gen_hist_bin, 'x') # get the bin edge thats smallest between 0.2, and 5th bin bin_lt_lim = [x for x in bin_edges if x < 0.2][-1] upper_bin = min(bin_edges[5], bin_lt_lim) plot2 = Plot( entries, ytitle=self.setup.pt_bin_normalised_differential_label, title=self.get_pt_bin_title(bin_edge_low, bin_edge_high), xlim=(0, upper_bin), **self.pt_bin_plot_args) self._modify_plot(plot2) plot2.subplot_title = "* / Generator" plot2.plot("NOSTACK E1") # plot2.set_logx(do_exponent=False) fname = f"unfolded_{stp.append}_rivet_bin_{ibin:d}_divBinWidth_lowX.{stp.output_fmt}" self.save_plot(plot2, os.path.join(stp.output_dir, fname))