def post_projection_processing_for_2d_correlation( hist: Hist, normalization_factor: float, title_label: str, jet_pt: analysis_objects.JetPtBin, track_pt: analysis_objects.TrackPtBin, rebin_factors: Optional[Tuple[int, int]] = None) -> None: """ Basic post processing tasks for a new 2D correlation observable. Args: hist: Histogram to be post processed. normalization_factor: Factor by which the hist should be scaled. title_label: Histogram title label. jet_pt: Jet pt bin. track_pt: Track pt bin. rebin_factors: (x rebin factor, y rebin factor). Both values must be specified (can set to 1 if you don't want to rebin a particular axis). Default: None. Returns: None. The histogram is modified in place. """ # If we specify a rebin factor, then rebin. if rebin_factors is not None: hist.Rebin2D(*rebin_factors) # Scale hist.Scale(1.0 / normalization_factor) # Set title, axis labels jet_pt_bins_title = labels.jet_pt_range_string(jet_pt) track_pt_bins_title = labels.track_pt_range_string(track_pt) hist.SetTitle( rf"{title_label}\:\mathrm{{with}}\:{jet_pt_bins_title} \mathrm{{,}} {track_pt_bins_title}" ) hist.GetXaxis().SetTitle(r"$\Delta\varphi$") hist.GetYaxis().SetTitle(r"$\Delta\eta$")
def delta_eta_fit_subtracted(analysis: "correlations.Correlations") -> None: """ Plot the subtracted delta eta near-side and away-side. """ # Setup fig, ax = plt.subplots(figsize=(8, 6)) # Plot both the near side and the away side. attribute_names = ["near_side", "away_side"] for attribute_name in attribute_names: # Setup an individual hist correlation = getattr(analysis.correlation_hists_delta_eta_subtracted, attribute_name) h = correlation.hist # Plot the data ax.errorbar( h.x, h.y, yerr=h.errors, marker="o", linestyle="", label=f"Subtracted {correlation.type.display_str()}", ) # Add horizontal line at 0 for comparison. ax.axhline(y=0, color="black", linestyle="dashed", zorder=1) # Labels. ax.set_xlabel( labels.make_valid_latex_string(correlation.axis.display_str())) ax.set_ylabel( labels.make_valid_latex_string(labels.delta_eta_axis_label())) jet_pt_label = labels.jet_pt_range_string(analysis.jet_pt) track_pt_label = labels.track_pt_range_string(analysis.track_pt) ax.set_title( fr"Subtracted 1D ${correlation.axis.display_str()}$," f" {analysis.reaction_plane_orientation.display_str()} event plane orient.," f" {jet_pt_label}, {track_pt_label}") ax.legend(loc="upper right") # Final adjustments fig.tight_layout() # Save plot and cleanup plot_base.save_plot( analysis.output_info, fig, f"jetH_delta_eta_{analysis.identifier}_{attribute_name}_subtracted" ) # Reset for the next iteration of the loop ax.clear() # Final cleanup plt.close(fig)
def fit_subtracted_signal_dominated( analysis: "correlations.Correlations") -> None: """ Plot the subtracted signal dominated hist. """ # Setup fig, ax = plt.subplots(figsize=(8, 6)) hists = analysis.correlation_hists_delta_phi_subtracted h = hists.signal_dominated.hist # Plot the subtracted hist ax.errorbar( h.x, h.y, yerr=h.errors, label=f"Subtracted {hists.signal_dominated.type.display_str()}", marker="o", linestyle="", ) # Plot the background uncertainty separately. background_error = analysis.fit_object.calculate_background_function_errors( h.x) ax.fill_between( h.x, h.y - background_error, h.y + background_error, label="RP background uncertainty", color=plot_base.AnalysisColors.fit, ) # Line for comparison ax.axhline(y=0, color="black", linestyle="dashed", zorder=1) # Labels. ax.set_xlabel( labels.make_valid_latex_string( hists.signal_dominated.axis.display_str())) ax.set_ylabel(labels.make_valid_latex_string( labels.delta_phi_axis_label())) jet_pt_label = labels.jet_pt_range_string(analysis.jet_pt) track_pt_label = labels.track_pt_range_string(analysis.track_pt) ax.set_title( fr"Subtracted 1D ${hists.signal_dominated.axis.display_str()}$," f" {analysis.reaction_plane_orientation.display_str()} event plane orient.," f" {jet_pt_label}, {track_pt_label}") ax.legend(loc="upper right", frameon=False) # Final adjustments fig.tight_layout() # Save plot and cleanup plot_base.save_plot(analysis.output_info, fig, f"jetH_delta_phi_{analysis.identifier}_subtracted") plt.close(fig)
def plot_and_label_1d_signal_and_background_with_matplotlib_on_axis(ax: matplotlib.axes.Axes, jet_hadron: "correlations.Correlations", apply_correlation_scale_factor: bool = True) -> None: """ Plot and label the signal and background dominated hists on the given axis. This is a helper function so that we don't have to repeat code when we need to plot these hists. It can also be used in other modules. Args: ax: Axis on which the histograms should be plotted. jet_hadron: Correlations object from which the delta_phi hists should be retrieved. apply_correlation_scale_factor: Whether to scale the histogram by the correlation scale factor. Returns: None. The given axis is modified. """ # Setup hists = jet_hadron.correlation_hists_delta_phi h_signal = histogram.Histogram1D.from_existing_hist(hists.signal_dominated.hist) if apply_correlation_scale_factor: h_signal *= jet_hadron.correlation_scale_factor ax.errorbar( h_signal.x, h_signal.y, yerr = h_signal.errors, label = hists.signal_dominated.type.display_str(), marker = "o", linestyle = "", ) h_background = histogram.Histogram1D.from_existing_hist(hists.background_dominated.hist) if apply_correlation_scale_factor: h_background *= jet_hadron.correlation_scale_factor # Plot with opacity first background_plot = ax.errorbar( h_background.x, h_background.y, yerr = h_background.errors, marker = "o", linestyle = "", alpha = 0.5, ) # Then restrict range and plot without opacity near_side = len(h_background.x) // 2 ax.errorbar( h_background.x[:near_side], h_background.y[:near_side], yerr = h_background.errors[:near_side], label = hists.background_dominated.type.display_str(), marker = "o", linestyle = "", color = background_plot[0].get_color() ) # Set labels. ax.set_xlabel(labels.make_valid_latex_string(hists.signal_dominated.hist.GetXaxis().GetTitle())) ax.set_ylabel(labels.make_valid_latex_string(hists.signal_dominated.hist.GetYaxis().GetTitle())) jet_pt_label = labels.jet_pt_range_string(jet_hadron.jet_pt) track_pt_label = labels.track_pt_range_string(jet_hadron.track_pt) ax.set_title(fr"Unsubtracted 1D ${hists.signal_dominated.axis.display_str()}$," f" {jet_hadron.reaction_plane_orientation.display_str()} event plane orient.," f" {jet_pt_label}, {track_pt_label}")
def test_track_pt_strings(self, logging_mixin): """ Test the track pt string generation functions. Each bin is tested. """ pt_bins = [] for i, (min, max) in enumerate( zip(self.track_pt_bins[:-1], self.track_pt_bins[1:])): pt_bins.append( analysis_objects.TrackPtBin(bin=i, range=params.SelectedRange( min, max))) for pt_bin, expected_min, expected_max in zip(pt_bins, self.track_pt_bins[:-1], self.track_pt_bins[1:]): logger.debug( f"Checking bin {pt_bin}, {pt_bin.range}, {type(pt_bin)}") assert labels.track_pt_range_string( pt_bin ) == r"$%(lower)s < p_{\text{T}}^{\text{assoc}} < %(upper)s\:\mathrm{GeV/\mathit{c}}$" % { "lower": expected_min, "upper": expected_max }
def post_creation_processing_for_1d_correlations( hist: Hist, normalization_factor: float, rebin_factor: int, title_label: str, axis_label: str, jet_pt: analysis_objects.JetPtBin, track_pt: analysis_objects.TrackPtBin) -> None: """ Basic post processing tasks for a new 1D correlation observable. """ # Rebin to decrease the fluctuations in the correlations # We don't scale by the rebin factor here because we will scale by bin width later. # Since we will handle it later, it doesn't make sense to try to preserve normalization here. hist.Rebin(rebin_factor) # Scale hist.Scale(1.0 / normalization_factor) # Set title, labels jet_pt_bins_title = labels.jet_pt_range_string(jet_pt) track_pt_bins_title = labels.track_pt_range_string(track_pt) # This won't look so good in ROOT, but that's just because their latex rendering is absolutely atrocious... hist.SetTitle( rf"{title_label} with {jet_pt_bins_title}, {track_pt_bins_title}") hist.GetXaxis().SetTitle(axis_label) hist.GetYaxis().SetTitle(fr"$\mathrm{{dN}}/\mathrm{{d}}{axis_label}$")
def delta_eta_fit(analysis: "correlations.Correlations") -> None: """ Plot the delta eta correlations with the fit. """ # Setup fig, ax = plt.subplots(figsize=(8, 6)) # Plot both the near side and the away side. for (attribute_name, correlation), (fit_attribute_name, fit_object) in \ zip(analysis.correlation_hists_delta_eta, analysis.fit_objects_delta_eta): if attribute_name != fit_attribute_name: raise ValueError( "Issue extracting hist and pedestal fit object together." f"Correlation obj name: {attribute_name}, pedestal fit obj name: {fit_attribute_name}" ) # Setup an individual hist h = histogram.Histogram1D.from_existing_hist(correlation.hist) label = correlation.type.display_str() # Determine the fit range so we can show it in the plot. # For example, -1.2 < h.x < -0.8 negative_restricted_range = ( (h.x < -1 * analysis.background_dominated_eta_region.min) & (h.x > -1 * analysis.background_dominated_eta_region.max)) # For example, 0.8 < h.x < 1.2 positive_restricted_range = ( (h.x > analysis.background_dominated_eta_region.min) & (h.x < analysis.background_dominated_eta_region.max)) restricted_range = negative_restricted_range | positive_restricted_range # First plot all of the data with opacity data_plot = ax.errorbar( h.x, h.y, yerr=h.errors, marker="o", linestyle="", alpha=0.5, ) # Then plot again without opacity highlighting the fit range. ax.errorbar(h.x[restricted_range], h.y[restricted_range], yerr=h.errors[restricted_range], label=label, marker="o", linestyle="", color=data_plot[0].get_color()) # Next, plot the pedestal following the same format # First plot the restricted values # We have to plot the fit data in two separate halves to prevent the lines # from being connected across the region where were don't fit. # Plot the left half pedestal_plot = ax.plot( h.x[negative_restricted_range], fit_object(h.x[negative_restricted_range], **fit_object.fit_result.values_at_minimum), label="Pedestal", ) # And then the right half ax.plot( h.x[positive_restricted_range], fit_object(h.x[positive_restricted_range], **fit_object.fit_result.values_at_minimum), color=pedestal_plot[0].get_color(), ) # Then plot the errors over the entire range. fit_values = fit_object(h.x, **fit_object.fit_result.values_at_minimum) fit_errors = fit_object.calculate_errors(h.x) ax.fill_between( h.x, fit_values - fit_errors, fit_values + fit_errors, facecolor=pedestal_plot[0].get_color(), alpha=0.7, ) # Then plot over the entire range using a dashed line. ax.plot( h.x, fit_values, linestyle="--", color=pedestal_plot[0].get_color(), ) # Labels. ax.set_xlabel( labels.make_valid_latex_string(correlation.axis.display_str())) ax.set_ylabel( labels.make_valid_latex_string(labels.delta_eta_axis_label())) jet_pt_label = labels.jet_pt_range_string(analysis.jet_pt) track_pt_label = labels.track_pt_range_string(analysis.track_pt) ax.set_title( fr"Unsubtracted 1D ${correlation.axis.display_str()}$," f" {analysis.reaction_plane_orientation.display_str()} event plane orient.," f" {jet_pt_label}, {track_pt_label}") ax.legend(loc="upper right") # Final adjustments fig.tight_layout() # Save plot and cleanup plot_base.save_plot( analysis.output_info, fig, f"jetH_delta_eta_{analysis.identifier}_{attribute_name}_fit") # Reset for the next iteration of the loop ax.clear() # Final cleanup plt.close(fig)
def plot_RP_fit(rp_fit: reaction_plane_fit.fit.ReactionPlaneFit, inclusive_analysis: "correlations.Correlations", ep_analyses: List[Tuple[Any, "correlations.Correlations"]], output_info: analysis_objects.PlottingOutputWrapper, output_name: str) -> None: """ Basic plot of the reaction plane fit. Args: rp_fit: Reaction plane fit object. inclusive_analysis: Inclusive analysis object. Mainly used for labeling. ep_analyses: Event plane dependent correlation analysis objects. output_info: Output information. output_name: Name of the output plot. Returns: None. The plot will be saved. """ # Setup n_components = len(rp_fit.components) fig, axes = plt.subplots(2, n_components, sharey="row", sharex=True, gridspec_kw={"height_ratios": [3, 1]}, figsize=(3 * n_components, 6)) flat_axes = axes.flatten() # Plot the fits on the upper panels. _plot_rp_fit_components(rp_fit=rp_fit, ep_analyses=ep_analyses, axes=flat_axes[:n_components]) # Plot the residuals on the lower panels. _plot_rp_fit_residuals(rp_fit=rp_fit, ep_analyses=ep_analyses, axes=flat_axes[n_components:]) # Define upper panel labels. # In-plane text = labels.track_pt_range_string(inclusive_analysis.track_pt) text += "\n" + labels.constituent_cuts() text += "\n" + labels.make_valid_latex_string( inclusive_analysis.leading_hadron_bias.display_str()) _add_label_to_rpf_plot_axis(ax=flat_axes[0], label=text) # Mid-plane text = labels.make_valid_latex_string( inclusive_analysis.alice_label.display_str()) text += "\n" + labels.system_label( energy=inclusive_analysis.collision_energy, system=inclusive_analysis.collision_system, activity=inclusive_analysis.event_activity) text += "\n" + labels.jet_pt_range_string(inclusive_analysis.jet_pt) text += "\n" + labels.jet_finding() _add_label_to_rpf_plot_axis(ax=flat_axes[1], label=text) # Out-of-plane #text = "Background: $0.8<|\Delta\eta|<1.2$" #text += "\nSignal + Background: $|\Delta\eta|<0.6$" #_add_label_to_rpf_plot_axis(ax = flat_axes[2], label = text) # Inclusive text = (r"\chi^{2}/\mathrm{NDF} = " f"{rp_fit.fit_result.minimum_val:.1f}/{rp_fit.fit_result.nDOF} = " f"{rp_fit.fit_result.minimum_val / rp_fit.fit_result.nDOF:.3f}") _add_label_to_rpf_plot_axis(ax=flat_axes[2], label=labels.make_valid_latex_string(text)) # Define lower panel labels. for ax in flat_axes[n_components:]: # Increase the frequency of major ticks to once every integer. ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(base=1.0)) # Add axis labels ax.set_xlabel( labels.make_valid_latex_string( inclusive_analysis.correlation_hists_delta_phi. signal_dominated.axis.display_str())) # Improve the viewable range for the lower panels. # This value is somewhat arbitrarily selected, but seems to work well enough. flat_axes[n_components].set_ylim(-0.2, 0.2) # Specify shared y axis label # Delta phi correlations first flat_axes[0].set_ylabel(labels.delta_phi_axis_label()) # Then label the residual flat_axes[n_components].set_ylabel("data - fit / fit") # Final adjustments fig.tight_layout() # Reduce spacing between subplots fig.subplots_adjust(hspace=0, wspace=0) # Save plot and cleanup plot_base.save_plot(output_info, fig, output_name) plt.close(fig)
def rp_fit_subtracted(ep_analyses: List[Tuple[Any, "correlations.Correlations"]], inclusive_analysis: "correlations.Correlations", output_info: analysis_objects.PlottingOutputWrapper, output_name: str) -> None: """ Basic plot of the reaction plane fit subtracted hists. Args: ep_analyses: Event plane dependent correlation analysis objects. inclusive_analysis: Inclusive analysis object. Mainly used for labeling. output_info: Output information. output_name: Name of the output plot. Returns: None. The plot will be saved. """ # Setup n_components = len(ep_analyses) fig, axes = plt.subplots( 1, n_components, sharey="row", sharex=True, #gridspec_kw = {"height_ratios": [3, 1]}, figsize=(3 * n_components, 6)) flat_axes = axes.flatten() # Plot the fits on the upper panels. _plot_rp_fit_subtracted(ep_analyses=ep_analyses, axes=flat_axes[:n_components]) # Define upper panel labels. # In-plane text = labels.track_pt_range_string(inclusive_analysis.track_pt) text += "\n" + labels.constituent_cuts() text += "\n" + labels.make_valid_latex_string( inclusive_analysis.leading_hadron_bias.display_str()) _add_label_to_rpf_plot_axis(ax=flat_axes[0], label=text) # Mid-plane text = labels.make_valid_latex_string( inclusive_analysis.alice_label.display_str()) text += "\n" + labels.system_label( energy=inclusive_analysis.collision_energy, system=inclusive_analysis.collision_system, activity=inclusive_analysis.event_activity) text += "\n" + labels.jet_pt_range_string(inclusive_analysis.jet_pt) text += "\n" + labels.jet_finding() _add_label_to_rpf_plot_axis(ax=flat_axes[1], label=text) # Out-of-plane #text = "Background: $0.8<|\Delta\eta|<1.2$" #text += "\nSignal + Background: $|\Delta\eta|<0.6$" #_add_label_to_rpf_plot_axis(ax = flat_axes[2], label = text) _add_label_to_rpf_plot_axis(ax=flat_axes[2], label=labels.make_valid_latex_string(text)) for ax in flat_axes: # Increase the frequency of major ticks to once every integer. ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(base=1.0)) # Set label ax.set_xlabel(labels.make_valid_latex_string(r"\Delta\varphi")) flat_axes[0].set_ylabel( labels.make_valid_latex_string(labels.delta_phi_axis_label())) #jet_pt_label = labels.jet_pt_range_string(inclusive_analysis.jet_pt) #track_pt_label = labels.track_pt_range_string(inclusive_analysis.track_pt) #ax.set_title(fr"Subtracted 1D ${inclusive_analysis.correlation_hists_delta_phi_subtracted.signal_dominated.axis.display_str()}$," # f" {inclusive_analysis.reaction_plane_orientation.display_str()} event plane orient.," # f" {jet_pt_label}, {track_pt_label}") ax.legend(loc="upper right") # Final adjustments fig.tight_layout() # Reduce spacing between subplots fig.subplots_adjust(hspace=0, wspace=0) # Save plot and cleanup plot_base.save_plot( output_info, fig, f"jetH_delta_phi_{inclusive_analysis.identifier}_rp_subtracted") plt.close(fig)
def plot_RPF_fit_regions(jet_hadron: "correlations.Correlations", filename: str) -> None: """ Plot showing highlighted RPF fit regions. Args: jet_hadron: Main analysis object. filename: Filename under which the hist should be saved. Returns: None """ # Retrieve the hist to be plotted # Here we selected the corrected 2D correlation hist = jet_hadron.correlation_hists_2d.signal.hist.Clone(f"{jet_hadron.correlation_hists_2d.signal.name}_RPF_scaled") hist.Scale(jet_hadron.correlation_scale_factor) with sns.plotting_context(context = "notebook", font_scale = 1.5): # Perform the plotting # The best option for clarify of viewing seems to be to just replace the colors with the overlay colors. # mathematical_blending and screen_colors look similar and seem to be the next most promising option. (fig, ax) = highlight_RPF.plot_RPF_fit_regions( histogram.get_array_from_hist2D(hist), highlight_regions = define_highlight_regions( signal_dominated_eta_region = jet_hadron.signal_dominated_eta_region, background_dominated_eta_region = jet_hadron.background_dominated_eta_region, near_side_phi_region = jet_hadron.near_side_phi_region, ), use_color_overlay = False, use_color_screen = False, use_mathematical_blending = False, ) # Add additional labeling # Axis # Needed to fix z axis rotation. See: https://stackoverflow.com/a/21921168 ax.zaxis.set_rotate_label(False) ax.set_zlabel(r"$1/N_{\mathrm{trig}}\mathrm{d^{2}}N/\mathrm{d}\Delta\varphi\mathrm{d}\Delta\eta$", rotation=90) # Set the distance from axis to label in pixels. # This is not ideal, but clearly tight_layout doesn't work as well for 3D plots ax.xaxis.labelpad = 12 # Visually, dEta looks closer ax.yaxis.labelpad = 15 ax.zaxis.labelpad = 12 # Overall alice_label = labels.make_valid_latex_string(jet_hadron.alice_label.display_str()) system_label = labels.system_label( energy = jet_hadron.collision_energy, system = jet_hadron.collision_system, activity = jet_hadron.event_activity ) jet_finding = labels.jet_finding() constituent_cuts = labels.constituent_cuts() leading_hadron = "$" + jet_hadron.leading_hadron_bias.display_str() + "$" jet_pt = labels.jet_pt_range_string(jet_hadron.jet_pt) assoc_pt = labels.track_pt_range_string(jet_hadron.track_pt) # Upper left side upper_left_text = "" upper_left_text += alice_label upper_left_text += "\n" + system_label upper_left_text += "\n" + jet_pt upper_left_text += "\n" + jet_finding # Upper right side upper_right_text = "" upper_right_text += leading_hadron upper_right_text += "\n" + constituent_cuts upper_right_text += "\n" + assoc_pt # Need a different text function since we have a 3D axis ax.text2D(0.01, 0.99, upper_left_text, horizontalalignment = "left", verticalalignment = "top", multialignment = "left", transform = ax.transAxes) ax.text2D(0.00, 0.00, upper_right_text, horizontalalignment = "left", verticalalignment = "bottom", multialignment = "left", transform = ax.transAxes) # Finish up plot_base.save_plot(jet_hadron.output_info, fig, filename) plt.close(fig)
def plot_2d_correlations(jet_hadron: "correlations.Correlations") -> None: """ Plot the 2D correlations. """ canvas = ROOT.TCanvas("canvas2D", "canvas2D") # Iterate over 2D hists for name, observable in jet_hadron.correlation_hists_2d: hist = observable.hist.Clone(f"{observable.name}_scaled") logger.debug(f"name: {name}, hist: {hist}") # We don't want to scale the mixed event hist because we already determined the normalization if "mixed" not in observable.type: hist.Scale(jet_hadron.correlation_scale_factor) # We don't need the title with all of the labeling hist.SetTitle("") # Draw plot hist.Draw("surf2") # Label axes hist.GetXaxis().CenterTitle(True) hist.GetXaxis().SetTitleSize(0.08) hist.GetXaxis().SetLabelSize(0.06) hist.GetYaxis().CenterTitle(True) hist.GetYaxis().SetTitleSize(0.08) # If I remove this, it looks worse, even though this is not supposed to do anything hist.GetYaxis().SetTitleOffset(1.2) hist.GetYaxis().SetLabelSize(0.06) hist.GetZaxis().CenterTitle(True) hist.GetZaxis().SetTitleSize(0.06) hist.GetZaxis().SetLabelSize(0.05) hist.GetZaxis().SetTitleOffset(0.8) canvas.SetLeftMargin(0.13) if "mixed" in observable.type: hist.GetZaxis().SetTitle(r"$a(\Delta\varphi,\Delta\eta)$") hist.GetZaxis().SetTitleOffset(0.9) else: z_title = r"$1/N_{\mathrm{trig}}\mathrm{d^{2}}N%(label)s/\mathrm{d}\Delta\varphi\mathrm{d}\Delta\eta$" if "signal" in observable.type: z_title = z_title % {"label": ""} else: z_title = z_title % {"label": r"_{\mathrm{raw}}"} # Decrease size so it doesn't overlap with the other labels hist.GetZaxis().SetTitleSize(0.05) hist.GetZaxis().SetTitle(z_title) # Add labels # PDF DOES NOT WORK HERE: https://root-forum.cern.ch/t/latex-sqrt-problem/17442/15 # Instead, print to EPS and then convert to PDF alice_label = labels.make_valid_latex_string(jet_hadron.alice_label.display_str()) system_label = labels.system_label( energy = jet_hadron.collision_energy, system = jet_hadron.collision_system, activity = jet_hadron.event_activity ) jet_finding = labels.jet_finding() constituent_cuts = labels.constituent_cuts() leading_hadron = "$" + jet_hadron.leading_hadron_bias.display_str() + "$" jet_pt = labels.jet_pt_range_string(jet_hadron.jet_pt) assoc_pt = labels.track_pt_range_string(jet_hadron.track_pt) logger.debug(f"label: {alice_label}, system_label: {system_label}, constituent_cuts: {constituent_cuts}, leading_hadron: {leading_hadron}, jet_pt: {jet_pt}, assoc_pt: {assoc_pt}") tex = ROOT.TLatex() tex.SetTextSize(0.04) # Upper left side tex.DrawLatexNDC(.005, .96, labels.use_label_with_root(alice_label)) tex.DrawLatexNDC(.005, .91, labels.use_label_with_root(system_label)) tex.DrawLatexNDC(.005, .86, labels.use_label_with_root(jet_pt)) tex.DrawLatexNDC(.005, .81, labels.use_label_with_root(jet_finding)) # Upper right side tex.DrawLatexNDC(.67, .96, labels.use_label_with_root(assoc_pt)) tex.DrawLatexNDC(.7275, .91, labels.use_label_with_root(leading_hadron)) tex.DrawLatexNDC(.73, .86, labels.use_label_with_root(constituent_cuts)) # Save plot plot_base.save_plot(jet_hadron.output_info, canvas, observable.name) # Draw as colz to view more precisely hist.Draw("colz") plot_base.save_plot(jet_hadron.output_info, canvas, observable.name + "_colz") canvas.Clear()
def delta_eta_with_gaussian(analysis: "correlations.Correlations") -> None: """ Plot the subtracted delta eta near-side. """ # Setup fig, ax = plt.subplots(figsize=(8, 6)) for (attribute_name, width_obj), (correlation_attribute_name, correlation) in \ zip(analysis.widths_delta_eta, analysis.correlation_hists_delta_eta_subtracted): # Setup # Sanity check if attribute_name != correlation_attribute_name: raise ValueError( "Issue extracting width and hist together." f"Width obj name: {attribute_name}, hist obj name: {correlation_attribute_name}" ) # Plot only the near side for now because the away-side doesn't have a gaussian shape if attribute_name == "away_side": continue # Plot the data. h = correlation.hist ax.errorbar( h.x, h.y, yerr=h.errors, marker="o", linestyle="", label=f"{correlation.type.display_str()}", ) # Plot the fit gauss = width_obj.fit_object(h.x, **width_obj.fit_result.values_at_minimum) fit_plot = ax.plot( h.x, gauss, label= fr"Gaussian fit: $\mu = $ {width_obj.mean:.2f}, $\sigma = $ {width_obj.width:.2f}", ) # Fill in the error band. error = width_obj.fit_object.calculate_errors(x=h.x) ax.fill_between( h.x, gauss - error, gauss + error, facecolor=fit_plot[0].get_color(), alpha=0.5, ) # Labels. ax.set_xlabel( labels.make_valid_latex_string(correlation.axis.display_str())) ax.set_ylabel( labels.make_valid_latex_string(labels.delta_eta_axis_label())) jet_pt_label = labels.jet_pt_range_string(analysis.jet_pt) track_pt_label = labels.track_pt_range_string(analysis.track_pt) ax.set_title( fr"Subtracted 1D ${correlation.axis.display_str()}$," f" {analysis.reaction_plane_orientation.display_str()} event plane orient.," f" {jet_pt_label}, {track_pt_label}") ax.legend(loc="upper right") # Final adjustments fig.tight_layout() # Save plot and cleanup plot_base.save_plot( analysis.output_info, fig, f"jetH_delta_eta_{analysis.identifier}_width_{attribute_name}_fit") # Reset for the next iteration of the loop ax.clear() # Final cleanup. plt.close(fig)
def delta_phi_with_gaussians(analysis: "correlations.Correlations") -> None: """ Plot the subtracted delta phi correlation with gaussian fits to the near and away side. """ # Setup fig, ax = plt.subplots(figsize=(8, 6)) correlation = analysis.correlation_hists_delta_phi_subtracted.signal_dominated h = correlation.hist # First we plot the data ax.errorbar( h.x, h.y, yerr=h.errors, marker="o", linestyle="", label=f"{correlation.type.display_str()}", ) # Plot the fit. for attribute_name, width_obj in analysis.widths_delta_phi: # Setup # Convert the attribute name to display better. Ex: "near_side" -> "Near side" attribute_display_name = attribute_name.replace("_", " ").capitalize() # We only want to plot the fit over the range that it was fit. restricted_range = (h.x > width_obj.fit_object.fit_range.min) & ( h.x < width_obj.fit_object.fit_range.max) x = h.x[restricted_range] # Plot the fit gauss = width_obj.fit_object(x, **width_obj.fit_result.values_at_minimum) fit_plot = ax.plot( x, gauss, label= fr"{attribute_display_name} gaussian fit: $\mu = $ {width_obj.mean:.2f}" fr", $\sigma = $ {width_obj.width:.2f}", ) # Fill in the error band. error = width_obj.fit_object.calculate_errors(x=x) ax.fill_between( x, gauss - error, gauss + error, facecolor=fit_plot[0].get_color(), alpha=0.5, ) # This means that we extracted values from the RP fit. Let's also plot them for comparison if width_obj.fit_args != {}: args = dict(width_obj.fit_result.values_at_minimum) args.update({ # Help out mypy... k: cast(float, v) for k, v in width_obj.fit_args.items() if "error_" not in k }) rpf_gauss = width_obj.fit_object(x, **args) rp_fit_plot = ax.plot( x, rpf_gauss, label= fr"RPF {attribute_display_name} gaussian fit: $\mu = $ {width_obj.mean:.2f}" fr", $\sigma = $ {width_obj.fit_args['width']:.2f}", ) # Fill in the error band. # NOTE: Strictly speaking, this error band isn't quite right (since it is dependent on the fit result # of the actual width fit), but I think it's fine for these purposes. error = width_obj.fit_object.calculate_errors(x=x) ax.fill_between( x, rpf_gauss - error, rpf_gauss + error, facecolor=rp_fit_plot[0].get_color(), alpha=0.5, ) # Labels. ax.set_xlabel( labels.make_valid_latex_string(correlation.axis.display_str())) ax.set_ylabel(labels.make_valid_latex_string( labels.delta_phi_axis_label())) jet_pt_label = labels.jet_pt_range_string(analysis.jet_pt) track_pt_label = labels.track_pt_range_string(analysis.track_pt) ax.set_title( fr"Subtracted 1D ${correlation.axis.display_str()}$," f" {analysis.reaction_plane_orientation.display_str()} event plane orient.," f" {jet_pt_label}, {track_pt_label}") ax.legend(loc="upper right") # Final adjustments fig.tight_layout() # Save plot and cleanup plot_base.save_plot( analysis.output_info, fig, f"jetH_delta_phi_{analysis.identifier}_width_signal_dominated_fit") plt.close(fig)