Пример #1
0
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$")
Пример #2
0
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)
Пример #3
0
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)
Пример #4
0
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}")
Пример #5
0
    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
            }
Пример #6
0
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}$")
Пример #7
0
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)
Пример #8
0
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)
Пример #9
0
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)
Пример #10
0
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)
Пример #11
0
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()
Пример #12
0
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)
Пример #13
0
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)