def rho_centrality(rho_hist: Hist, output_info: analysis_objects.PlottingOutputWrapper, includes_constituent_cut: bool = True) -> None: """ Plot rho as a function of centrality vs jet pt. Args: rho_hist: Rho centrality dependent hist. output_info: Output information. includes_constituent_cut: True if the plot was produced using the constituent cut. Returns: None. The figure is plotted. """ # Setup import ROOT canvas = ROOT.TCanvas("c", "c") canvas.SetRightMargin(0.15) # Set labels rho_hist.SetTitle("") rho_hist.Draw("colz") # Keep the range more meaningful. rho_hist.GetYaxis().SetRangeUser(0, 50) # Draw a profile of the mean rho_hist_profile = rho_hist.ProfileX(f"{rho_hist.GetName()}_profile") rho_hist_profile.SetMarkerStyle(ROOT.kFullCircle) rho_hist_profile.SetMarkerColor(ROOT.kRed) rho_hist_profile.SetMarkerSize(1.4) rho_hist_profile.Draw("same") # Finally, save and cleanup output_name = "rho_background" if includes_constituent_cut: output_name += "_3GeVConstituents" plot_base.save_plot(output_info, canvas, output_name)
def trigger_jets_EP( ep_analyses: List[Tuple[Any, "correlations.Correlations"]], output_info: analysis_objects.PlottingOutputWrapper) -> None: """ Plot jets triggers as a function of event plane orientation. Args: ep_analyses: Event plane dependent analyses. output_info: Output information. Returns: None. The triggers are plotted. """ # Setup fig, ax = plt.subplots(figsize=(8, 6)) # Plot for key_index, analysis in ep_analyses: h = histogram.Histogram1D.from_existing_hist( analysis.number_of_triggers_observable.hist) # Scale by the bin width h *= 1.0 / h.bin_widths[0] ax.errorbar( h.x, h.y, xerr=h.bin_widths / 2, yerr=h.errors, marker="o", linestyle="None", label= fr"{analysis.reaction_plane_orientation.display_str()}: $N_{{\text{{trig}}}} = {analysis.number_of_triggers:g}$", ) ax.set_xlim(0, 100) ax.text( 0.025, 0.025, r"$N_{\text{trig}}$ restricted to " + labels.jet_pt_range_string(analysis.jet_pt), transform=ax.transAxes, horizontalalignment="left", verticalalignment="bottom", multialignment="left", ) # Final presentation settings ax.set_xlabel( labels.make_valid_latex_string( fr"{labels.jet_pt_display_label()}\:({labels.momentum_units_label_gev()})" )) ax.set_ylabel( labels.make_valid_latex_string( fr"d\text{{n}}/d{labels.jet_pt_display_label()}\:({labels.momentum_units_label_gev()}^{{-1}})" )) ax.set_yscale("log") ax.legend(frameon=False, loc="upper right") fig.tight_layout() # Finally, save and cleanup output_name = f"trigger_jet_spectra_EP" plot_base.save_plot(output_info, fig, output_name) plt.close(fig)
def z_vertex(raw_z_vertex: List[Hist], z_vertices: Dict[params.EventActivity, Hist], output_info: analysis_objects.PlottingOutputWrapper) -> None: """ Plot the z_vertex distribution for a list of centralities. Args: raw_z_vertex: Raw z_vertex. Each entry should have the same content. z_vertices: Centrality selected z_vertex distributions. output_info: Output information. Returns: None. The z_vertex are plotted. """ # Setup fig, ax = plt.subplots(figsize=(8, 6)) # First plot the first raw distribution (we don't need the others). h = histogram.Histogram1D.from_existing_hist(raw_z_vertex[0]) ax.plot(h.x, h.y, label=r"Raw $z_{\text{vtx}}$") # Then plot the selected ones for event_activity, hist in z_vertices.items(): h = histogram.Histogram1D.from_existing_hist(hist) ax.plot(h.x, h.y, label=event_activity.display_str()) # Final presentation settings ax.set_yscale("log") ax.legend(frameon=False, loc="upper right") fig.tight_layout() # Finally, save and cleanup plot_base.save_plot(output_info, fig, "z_vertex") plt.close(fig)
def matched_jet_energy_scale( plot_labels: plot_base.PlotLabels, output_name: str, output_info: analysis_objects.PlottingOutputWrapper, obj: "response_matrix.ResponseMatrixBase") -> None: # Setup canvas = ROOT.TCanvas("canvas", "canvas") canvas.SetLogz(True) hist = obj.matched_jet_pt_difference logger.debug(f"hist: {hist}") # Plot the histogram plot_labels.apply_labels(hist) hist.Draw("colz") # Axis ranges hist.GetXaxis().SetRangeUser(0, 150) # Scale Z axis. Otherwise, we won't see much. min_val = ctypes.c_double(0) max_val = ctypes.c_double(0) hist.GetMinimumAndMaximum(min_val, max_val) # * 1.1 to put it slightly above the max value # min_val doesn't work here, because there are some entries at 0 hist.GetZaxis().SetRangeUser(10e-7, max_val.value * 1.1) # Save plot_base.save_plot(output_info, canvas, output_name)
def plot_RPF_regions(input_file: str, hist_name: str, output_prefix: str = ".", printing_extensions: Optional[List[str]] = None) -> None: """ Main entry point for stand-alone highlight plotting functionality. If this is being used as a library, call ``plot_RPF_fit_regions(...)`` directly instead. Args: input_file (str): Path to the input file. hist_name (str): Name of the histogram to be highlighted. output_prefix (str): Directory where the output file should be stored. Default: "." printing_extensions (list): Printing extensions to be used. Default: None, which corresponds to printing to ``.pdf``. Returns: None. """ # Argument validation if printing_extensions is None: printing_extensions = [".pdf"] # Basic setup # Create logger logging.basicConfig(level=logging.DEBUG) # Quiet down the matplotlib logging logging.getLogger("matplotlib").setLevel(logging.INFO) # Retrieve hist with histogram.RootOpen(filename = input_file, mode = "READ") as f: hist = f.Get(hist_name) hist.SetDirectory(0) # Increase the size of the fonts, etc with sns.plotting_context(context = "notebook", font_scale = 1.5): # See the possible arguments to highlight_region_of_surface(...) # For example, to turn on the color overlay, it would be: #highlight_args = {"use_color_screen" : True} highlight_args: Dict[str, bool] = {} # Call plotting functions fig, ax = plot_RPF_fit_regions( histogram.get_array_from_hist2D(hist), highlight_regions = define_highlight_regions(), colormap = "ROOT_kBird", view_angle = (35, 225), **highlight_args, ) # Modify axis labels # Set the distance from axis to label in pixels. # Having to set this by hand isn't ideal, but tight_layout doesn't work as well for 3D plots. ax.xaxis.labelpad = 12 # Visually, delta eta looks closer ax.yaxis.labelpad = 15 # If desired, add additional labeling here. # Probably want to use, for examxple, `ax.text2D(0.1, 0.9, "label text", transform = ax.transAxes)` # This would place the text in the upper left corner (it's like NDC) # Save and finish up # The figure will be saved at ``output_prefix/output_path.printing_extension`` output_wrapper = analysis_objects.PlottingOutputWrapper(output_prefix = output_prefix, printing_extensions = printing_extensions) plot_base.save_plot(output_wrapper, fig, output_name = "highlightRPFRegions") plt.close(fig)
def plot_residual(residual: np.ndarray, pts: List[float], etas: List[float], period: str, centrality_bin: int, centrality_ranges: Dict[int, params.SelectedRange], output_info: analysis_objects.PlottingOutputWrapper) -> None: """ Plot the residual between the data and the parametrization. Args: residual: Calculated residual. pts: Pt values where the residual was evaluated. etas: Eta values where the residual was evaluated. period: Name of the data taking period. centrality_bin: Centrality bin. centraliy_ranges: Map of centrality bins to ranges. output_info: Output info for saving figures. Returns: None. """ fig, ax = plt.subplots(figsize = (8, 6)) im = ax.imshow( residual.T, extent = [np.nanmin(pts), np.nanmax(pts), np.nanmin(etas), np.nanmax(etas)], interpolation = "nearest", aspect = "auto", origin = "lower", # An even normalization is better for the colorscheme. # NOTE: This causes clipping at the lowest pt values, but I don't think this is a big problem. norm = matplotlib.colors.Normalize( #vmin = np.nanmin(residuals[centrality_bin]), vmax = np.nanmax(residuals[centrality_bin]) vmin = -40, vmax = 40 ), # This is a good diverging color scheme when it's centered at 0. cmap = "RdBu", ) # Add the colorbar color_bar = fig.colorbar(im, ax = ax) color_bar.set_label(r"(data - fit)/fit (\%)") # Labels ax.set_xlabel(fr"${labels.pt_display_label()}\:({labels.momentum_units_label_gev()})$") ax.set_ylabel(r"$\eta$") title = f"{period} tracking efficiency residuals" if system != params.CollisionSystem.pp: centrality_range = centrality_ranges[centrality_bin] title += rf", ${centrality_range.min} \textendash {centrality_range.max}\%$" ax.set_title(title, size = 16) # Final adjustments fig.tight_layout() name = f"efficiency_residuals_{period}" if system != params.CollisionSystem.pp: centrality_range = centrality_ranges[centrality_bin] name += f"_centrality_{centrality_range.min}_{centrality_range.max}" plot_base.save_plot(output_info, fig, name) # Cleanup plt.close(fig)
def plot_1D_pt_efficiency(efficiency: Hist, PublicUtils: T_PublicUtils, efficiency_period: Any, centrality_bin: int, centrality_range: params.SelectedRange, output_info: analysis_objects.PlottingOutputWrapper) -> None: """ Plot 1D pt efficiency. Args: efficiency: Pt efficiency hist. PublicUtils: Jet-H public utils class. efficiency_period: Data taking period in the efficiency enum. centrality_bin: int centrality_range: Centrality range. output_info: Output info for saving figures. Returns: None. """ # 1D efficiency as a function of pt logger.debug(f"max efficiency_1D: {efficiency.GetMaximum()}") h = histogram.Histogram1D.from_existing_hist(efficiency) fig, ax = plt.subplots(figsize = (8, 6)) ax.errorbar( h.x, h.y, yerr = h.errors, label = "${labels.pt_display_label()}$", color = "black", marker = ".", linestyle = "", ) # Efficiency function parametrization = [] for x in h.x: parametrization.append(PublicUtils.LHC15oPtEfficiency(x, centrality_bin)) ax.plot( h.x, parametrization, label = "${labels.pt_display_label()}$ param.", color = "red", ) # Ensure that it's on a consistent axis ax.set_ylim(0.6, 1) # Labels ax.set_xlabel(fr"${labels.pt_display_label()}\:({labels.momentum_units_label_gev()})$") ax.set_ylabel(r"Efficiency") title = f"{period} ${labels.pt_display_label()}$ tracking efficiency" if system != params.CollisionSystem.pp: title += rf", ${centrality_range.min} \textendash {centrality_range.max}\%$" ax.set_title(title, size = 16) # Final adjustments fig.tight_layout() name = f"efficiency_pt_{period}" if system != params.CollisionSystem.pp: name += f"_centrality_{centrality_range.min}_{centrality_range.max}" plot_base.save_plot(output_info, fig, name)
def delta_eta_unsubtracted(hists: "correlations.CorrelationHistogramsDeltaEta", correlation_scale_factor: float, jet_pt: analysis_objects.JetPtBin, track_pt: analysis_objects.TrackPtBin, reaction_plane_orientation: params.ReactionPlaneOrientation, identifier: str, output_info: analysis_objects.PlottingOutputWrapper) -> None: """ Plot 1D delta eta correlations on a single plot. Args: hists: Unsubtracted delta eta histograms. correlation_scale_factor: Overall correlation scale factor. jet_pt: Jet pt bin. track_pt: Track pt bin. reaction_plane_orientation: Reaction plane orientation. identifier: Analysis identifier string. Usually contains jet pt, track pt, and other information. output_info: Standard information needed to store the output. Returns: None. """ # Setup fig, ax = plt.subplots(figsize = (8, 6)) # Plot NS, AS h_near_side = histogram.Histogram1D.from_existing_hist(hists.near_side.hist) h_near_side *= correlation_scale_factor ax.errorbar( h_near_side.x, h_near_side.y, yerr = h_near_side.errors, label = hists.near_side.type.display_str(), marker = "o", linestyle = "", ) h_away_side = histogram.Histogram1D.from_existing_hist(hists.away_side.hist) h_away_side *= correlation_scale_factor ax.errorbar( h_away_side.x, h_away_side.y, yerr = h_away_side.errors, label = hists.away_side.type.display_str(), marker = "o", linestyle = "", ) # Set labels. ax.set_xlabel(labels.make_valid_latex_string(hists.near_side.hist.GetXaxis().GetTitle())) ax.set_ylabel(labels.make_valid_latex_string(hists.near_side.hist.GetYaxis().GetTitle())) ax.set_title(fr"Unsubtracted 1D ${hists.near_side.axis.display_str()}$," f" {reaction_plane_orientation.display_str()} event plane orient.," f" {labels.jet_pt_range_string(jet_pt)}, {labels.track_pt_range_string(track_pt)}") # Labeling ax.legend(loc = "upper right") # Final adjustments fig.tight_layout() # Save and cleanup output_name = f"jetH_delta_eta_{identifier}_near_away_side_comparison" plot_base.save_plot(output_info, fig, output_name) plt.close(fig)
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 finalize(self, n_events_accepted: int) -> None: """ Finalize the analysis. """ # Sanity check assert len(self.events) == n_events_accepted logger.info( f"number of accepted events: {len(self.events)}, jets in tree: {len(self.jets)}" ) # Finally, convert to a proper numpy array. It's only converted here because it's not efficient to expand # existing numpy arrays. self.jets = np.array(self.jets, dtype=DTYPE_JETS) self.events = np.array(self.events, dtype=DTYPE_EVENT_PROPERTIES) # And save out the tree so we don't have to calculate it again later. self.save_tree(arr=self.jets, output_name="jets") self.save_tree(arr=self.events, output_name="event_properties") # Create the response matrix and plot it as a cross check. # Create histogram h, x_edges, y_edges = np.histogram2d(self.jets["det_pT"], self.jets["part_pT"], bins=(60, 60), range=((0, 60), (0, 60))) # Plot import matplotlib import matplotlib.pyplot as plt # Fix normalization h[h == 0] = np.nan fig, ax = plt.subplots(figsize=(8, 6)) resp = ax.imshow( h, extent=(x_edges[0], x_edges[-1], y_edges[0], y_edges[-1]), interpolation="nearest", aspect="auto", origin="lower", norm=matplotlib.colors.Normalize(vmin=np.nanmin(h), vmax=np.nanmax(h)), ) fig.colorbar(resp) # Final labeling and presentation ax.set_xlabel( labels.make_valid_latex_string(labels.jet_pt_display_label("det"))) ax.set_ylabel( labels.make_valid_latex_string( labels.jet_pt_display_label("part"))) fig.tight_layout() fig.subplots_adjust(hspace=0, wspace=0, right=0.99) plot_base.save_plot(self.output_info, fig, f"response") plt.close(fig)
def _plot_all_1d_correlations_with_matplotlib( jet_hadron: "correlations.Correlations") -> None: """ Plot all 1D correlations in a very basic way with matplotlib. Note: We don't want to scale the histogram any further here because it's already been fully scaled! """ # Not ideal, but it's much more convenient to import it here. Importing it at the top # of the file would cause an import loop. from jet_hadron.analysis import correlations fig, ax = plt.subplots() for correlations_groups in [ jet_hadron.correlation_hists_delta_phi, jet_hadron.correlation_hists_delta_eta ]: # Help out mypy... assert isinstance(correlations_groups, (correlations.CorrelationHistogramsDeltaPhi, correlations.CorrelationHistogramsDeltaEta)) for _, observable in correlations_groups: # Draw the 1D histogram. h = histogram.Histogram1D.from_existing_hist(observable.hist) ax.errorbar( h.x, h.y, yerr=h.errors, label=observable.hist.GetName(), marker="o", linestyle="", ) # Set labels. ax.set_xlabel( labels.make_valid_latex_string( observable.hist.GetXaxis().GetTitle())) ax.set_ylabel( labels.make_valid_latex_string( observable.hist.GetYaxis().GetTitle())) ax.set_title( labels.make_valid_latex_string(observable.hist.GetTitle())) # Final adjustments fig.tight_layout() # Save and cleanup output_name = observable.hist.GetName() + "_mpl" plot_base.save_plot(jet_hadron.output_info, fig, output_name) ax.clear() # Cleanup plt.close(fig)
def plot(self, obj: "generic_tasks.PlotTaskHists", output_name: str = "") -> None: # Ensure that the output directory is available. path = os.path.join(obj.output_prefix, os.path.dirname(output_name)) if not os.path.exists(path): os.makedirs(path) # Make any pre draw adjustments. self._pre_draw_options() # Make the plots fig, ax = plt.subplots(figsize=(8, 6)) # Draw the hist import ROOT if isinstance(self._first_hist(), ROOT.TH2): self._plot_2D_hists(fig=fig, ax=ax) elif isinstance(self._first_hist(), ROOT.TH1): self._plot_1D_hists(fig=fig, ax=ax) else: raise ValueError( f"Histogram must be 1D or 2D. Type provided: {type(self._first_hist())}" ) # Apply the options # Need to apply these here because rplt messes with them! self._apply_hist_settings(ax) # Apply post drawing options self._post_draw_options(ax) self._add_text_labels(ax, obj) # Final plotting options plt.tight_layout() # Determine the final output path # Use ``self.output_name`` for the end of the output name if it's set. If it's not set, then we just # use the plot configuration key name passed in via ``output_name`` final_output_name = output_name if self.output_name: final_output_name = os.path.join( os.path.dirname(final_output_name), self.output_name) logger.debug( f"final_output_name: {final_output_name}, self.output_name: {self.output_name}" ) # Save and close the figure plot_base.save_plot(obj.output_info, fig, final_output_name) 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_tracking_efficiency_parametrization(efficiency: np.ndarray, centrality_range: params.SelectedRange, period: str, system: params.CollisionSystem, output_info: analysis_objects.PlottingOutputWrapper) -> None: """ Plot the given tracking efficiencies parametrization. Args: efficiency: Calculated tracking efficiencies. centrality_range: Associated centrality range. period: Data taking period. system: Collision system. output_info: Output info for saving figures. Returns: None. """ # Get the parameters pt_values, eta_values, n_cent_bins, centrality_ranges = generate_parameters(system) logger.debug(fr"Plotting efficiencies for {centrality_range.min}--{centrality_range.max}%") fig, ax = plt.subplots(figsize = (8, 6)) im = ax.imshow( efficiency.T, extent = [np.min(pt_values), np.max(pt_values), np.min(eta_values), np.max(eta_values)], interpolation = "nearest", aspect = "auto", origin = "lower", norm = matplotlib.colors.Normalize(vmin = 0.5, vmax = 1), cmap = "viridis", ) # Add the colorbar fig.colorbar(im, ax = ax) # Labels ax.set_xlabel(fr"${labels.pt_display_label()}\:({labels.momentum_units_label_gev()})$") ax.set_ylabel(r"$\eta$") title = f"{period} tracking efficiency parametrization" if system != params.CollisionSystem.pp: title += rf", ${centrality_range.min} \textendash {centrality_range.max}\%$" ax.set_title(title, size = 16) # Final adjustments fig.tight_layout() name = f"efficiency_{period}" if system != params.CollisionSystem.pp: name += f"_centrality_parametrization_{centrality_range.min}_{centrality_range.max}" plot_base.save_plot(output_info, fig, name) # Cleanup plt.close(fig)
def _plot_1d_signal_and_background_with_ROOT( jet_hadron: "correlations.Correlations", output_name: str) -> None: """ Plot 1D signal and background hists on a single plot with ROOT. """ # Setup canvas = ROOT.TCanvas("canvas1D", "canvas1D") hists = jet_hadron.correlation_hists_delta_phi # Plot hists.signal_dominated.hist.SetLineColor(ROOT.kBlack) hists.signal_dominated.hist.SetMarkerColor(ROOT.kBlack) hists.signal_dominated.hist.Draw("") hists.background_dominated.hist.SetLineColor(ROOT.kBlue) hists.background_dominated.hist.SetMarkerColor(ROOT.kBlue) hists.background_dominated.hist.Draw("same") # Save output_name += "_ROOT" plot_base.save_plot(jet_hadron.output_info, canvas, output_name)
def _plot_fit_parameter_vs_assoc_pt( fit_objects: FitObjects, parameter: ParameterInfo, reference_data: ReferenceData, selected_analysis_options: params.SelectedAnalysisOptions, output_info: analysis_objects.PlottingOutputWrapper) -> None: """ Implementation to plot the fit parameters vs associated track pt. """ fig, ax = plt.subplots(figsize=(8, 6)) # Extract the parameter values from each fit object. bin_centers = np.zeros(len(fit_objects)) parameter_values = np.zeros(len(fit_objects)) parameter_values_errors = np.zeros(len(fit_objects)) for i, (key_index, fit_object) in enumerate(fit_objects.items()): bin_centers[i] = key_index.track_pt_bin.bin_center parameter_values[i] = fit_object.fit_result.values_at_minimum[ parameter.name] parameter_values_errors[ i] = fit_object.fit_result.errors_on_parameters[parameter.name] # Plot the particular parameter. ax.errorbar( bin_centers, parameter_values, yerr=parameter_values_errors, marker="o", linestyle="", label=parameter.labels.title, ) if parameter.plot_reference_data_func: parameter.plot_reference_data_func( reference_data, ax, selected_analysis_options, ) # Labeling parameter.labels.apply_labels(ax) ax.legend(loc="upper left", frameon=False) # Final adjustments fig.tight_layout() # Save plot and cleanup plot_base.save_plot(output_info, fig, parameter.output_name) plt.close(fig)
def plot_2D_efficiency_data(efficiency_hist: Hist, centrality_range: params.SelectedRange, output_info: analysis_objects.PlottingOutputWrapper) -> None: """ Plot the 2D efficiency data Args: efficiency_hist: Efficiecny histogram. centrality_range: Centrality range. output_info: Output info for saving figures. Returns: None. """ X, Y, efficiency_data = histogram.get_array_from_hist2D(hist = efficiency_hist) logger.debug(f"efficiency data min: {np.nanmin(efficiency_data)}, max: {np.nanmax(efficiency_data)}") fig, ax = plt.subplots(figsize = (8, 6)) im = ax.imshow( efficiency_data.T, extent = [np.nanmin(X), np.nanmax(X), np.nanmin(Y), np.nanmax(Y)], interpolation = "nearest", aspect = "auto", origin = "lower", norm = matplotlib.colors.Normalize( vmin = np.nanmin(efficiency_data), vmax = np.nanmax(efficiency_data) #vmin = 0.5, vmax = 1, ), cmap = "viridis", ) # Add the colorbar color_bar = fig.colorbar(im, ax = ax) color_bar.set_label("Efficiency") # Labels ax.set_xlabel(fr"${labels.pt_display_label()}\:({labels.momentum_units_label_gev()})$") ax.set_ylabel(r"$\eta$") title = f"{period} tracking efficiency data" if system != params.CollisionSystem.pp: title += rf", ${centrality_range.min} \textendash {centrality_range.max}\%$" ax.set_title(title, size = 16) # Final adjustments fig.tight_layout() name = f"efficiency_{period}" if system != params.CollisionSystem.pp: name += f"_centrality_{centrality_range.min}_{centrality_range.max}" plot_base.save_plot(output_info, fig, name) # Cleanup plt.close(fig)
def _example_plots(self) -> None: """ Produce some images of example collisions. """ logger.info("Creating example interaction region plots") # Setup c = ROOT.TCanvas("c", "c") # Iterate over the min and max impact parameters, plotting an example interaction from each. for _, impact_parameter in self.impact_parameters[self.selected_analysis_options.event_activity]: logger.debug(f"impact_parameter: {impact_parameter}") # Setup self.analysis.glauber.SetBmin(impact_parameter) self.analysis.glauber.SetBmax(impact_parameter) # Generate self.analysis.event_loop( n_events = 1, progress_manager = self._progress_manager ) # Draw self.analysis.glauber.Draw() plot_base.save_plot(self.output_info, c, f"example_collision_b_{impact_parameter}")
def signal_dominated_with_background_function( analysis: "correlations.Correlations") -> None: """ Plot the signal dominated hist with the background function. """ # Setup fig, ax = plt.subplots(figsize=(8, 6)) # Plot signal and background dominated hists plot_correlations.plot_and_label_1d_signal_and_background_with_matplotlib_on_axis( ax=ax, jet_hadron=analysis) # Plot background function # First we retrieve the signal dominated histogram to get reference x values and bin edges. h = histogram.Histogram1D.from_existing_hist( analysis.correlation_hists_delta_phi.signal_dominated.hist) background = histogram.Histogram1D( bin_edges=h.bin_edges, y=analysis.fit_object.evaluate_background(h.x), errors_squared=analysis.fit_object. calculate_background_function_errors(h.x)**2, ) background_plot = ax.plot(background.x, background.y, label="Background function") ax.fill_between( background.x, background.y - background.errors, background.y + background.errors, facecolor=background_plot[0].get_color(), alpha=0.9, ) # Labeling 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}_signal_background_function_comparison" ) plt.close(fig)
def _plot_1d_signal_and_background_with_matplotlib(jet_hadron: "correlations.Correlations", output_name: str) -> None: """ Plot 1D signal and background hists on a single plot with matplotlib. """ # Setup fig, ax = plt.subplots(figsize = (8, 6)) # Perform the actual plot plot_and_label_1d_signal_and_background_with_matplotlib_on_axis( ax = ax, jet_hadron = jet_hadron, apply_correlation_scale_factor = True ) # Labeling ax.legend(loc = "upper right") # Final adjustments fig.tight_layout() # Save and cleanup output_name += "_mpl" plot_base.save_plot(jet_hadron.output_info, fig, output_name) plt.close(fig)
def plot_particle_level_spectra_agreement( difference: Hist, absolute_value_of_difference: Hist, output_info: analysis_objects.PlottingOutputWrapper) -> None: """ Plot the agreement of the particle level spectra between the inclusive and sum of all EP orientations. Args: difference: Hist of the sum of the EP orientations spectra minus the inclusive spectra. absolute_value_of_difference: Same as the difference hist, but having taken the absolute value. This allows us to plot the difference on a log scale (which is useful if the differences are small). output_info: Output information. Returns: None. """ # Setup output_name = "difference_of_sum_EP_orientations_vs_inclusive" canvas = ROOT.TCanvas("canvas", "canvas") # Labeling x_label = labels.use_label_with_root( fr"{labels.jet_pt_display_label(upper_label = 'part')}\:({labels.momentum_units_label_gev()})" ) y_label = r"\mathrm{d}N/\mathrm{d}p_{\mathrm{T}}" # Apply settings to hists for h in [difference, absolute_value_of_difference]: # Labeling h.GetXaxis().SetTitle(x_label) h.GetYaxis().SetTitle(y_label) # Center axis title h.GetXaxis().CenterTitle(True) h.GetYaxis().CenterTitle(True) # Draw and save the difference histogram. difference.Draw() plot_base.save_plot(output_info, canvas, output_name) # Draw and save the absolute value of the difference histogram. absolute_value_of_difference.Draw() canvas.SetLogy(True) output_name += "_abs" plot_base.save_plot(output_info, canvas, output_name)
def _plot_all_1d_correlations_with_ROOT(jet_hadron: "correlations.Correlations") -> None: """ Plot all 1D correlations in a very basic way with ROOT. Note: We scaled with the correlation scale factor before plotting to ensure that the stored plots are always scaled properly. """ # Not ideal, but it's much more convenient to import it here. Importing it at the top # of the file would cause an import loop. from jet_hadron.analysis import correlations canvas = ROOT.TCanvas("canvas1D", "canvas1D") for correlations_groups in [jet_hadron.correlation_hists_delta_phi, jet_hadron.correlation_hists_delta_eta]: # Help out mypy... assert isinstance(correlations_groups, (correlations.CorrelationHistogramsDeltaPhi, correlations.CorrelationHistogramsDeltaEta)) for name, observable in correlations_groups: # Draw the 1D histogram. hist = observable.hist.Clone(f"{name}_scaled") hist.Scale(jet_hadron.correlation_scale_factor) hist.Draw("") output_name = observable.hist.GetName() + "_ROOT" plot_base.save_plot(jet_hadron.output_info, canvas, output_name)
def _plot_response_matrix_with_ROOT( name: str, x_label: str, y_label: str, output_name: str, hist: Hist, plot_errors_hist: bool, output_info: analysis_objects.PlottingOutputWrapper) -> None: """ Underlying function to actually plot a response matrix with ROOT. Args: name: Name of the histogram. x_label: X axis label. y_label: Y axis label. output_name: Output name of the histogram. hist: The response matrix related 2D hist. errors_hist: True if the hist is the response matrix errors hist. output_info: Output information. Returns: None """ # Setup canvas = ROOT.TCanvas("canvas", "canvas") canvas.SetLogz(True) # Plot the histogram hist.SetTitle(name) hist.GetXaxis().SetTitle(labels.use_label_with_root(x_label)) hist.GetYaxis().SetTitle(labels.use_label_with_root(y_label)) hist.Draw("colz") # Set the final axis ranges. # Z axis min_val = ctypes.c_double(0) max_val = ctypes.c_double(0) hist.GetMinimumAndMaximum(min_val, max_val) # * 1.1 to put it slightly above the max value # min_val doesn't work here, because there are some entries at 0 hist.GetZaxis().SetRangeUser(10e-7, max_val.value * 1.1) # Save output_name += "_ROOT" plot_base.save_plot(output_info, canvas, output_name)
def comparison_1d(output_info: analysis_objects.PlottingOutputWrapper, our_hist: histogram.Histogram1D, their_hist: histogram.Histogram1D, ratio: histogram.Histogram1D, title: str, x_label: str, y_label: str, output_name: str) -> None: """ Compare our hist and their hist. """ fig, ax = plt.subplots(2, 1, sharex=True, gridspec_kw={"height_ratios": [3, 1]}, figsize=(8, 6)) # Plot data ax[0].errorbar(our_hist.x, our_hist.y, yerr=our_hist.errors, label="Our hist") ax[0].errorbar(their_hist.x, their_hist.y, yerr=their_hist.errors, label="Their hist") # Plot ratio ax[1].errorbar(ratio.x, ratio.y, yerr=ratio.errors, label="Theirs/ours") # Set plot properties ax[0].set_title(title) ax[0].set_ylabel(r"$\mathrm{d}N/\mathrm{d}\varphi$") ax[0].legend(loc="best") ax[1].set_xlabel(r"$\Delta\varphi$") ax[1].set_ylabel("Theirs/ours") # Final adjustments fig.tight_layout() # Reduce spacing between subplots fig.subplots_adjust(hspace=0, wspace=0.05) # Save and cleanup plot_base.save_plot(output_info, fig, output_name) plt.close(fig)
def event_cut_stats( cut_stats: Dict[str, Hist], event_activity: params.EventActivity, output_info: analysis_objects.PlottingOutputWrapper) -> None: """ Plot the event cut stats. Args: cut_stats: Collections of cut stats to plot. event_activity: Event activity of the stats info. output_info: Output information. Returns: None. The centralities are plotted. """ # Setup import ROOT canvas = ROOT.TCanvas("canvas", "canvas") # Legend legend = ROOT.TLegend(0.1, 0.35, 0.3, 0.6) # Increase text size legend.SetTextSize(0.03) # Remove the legend border legend.SetBorderSize(0) # Make the legend transparent legend.SetFillStyle(0) # Plot colors = [ROOT.kBlack, ROOT.kRed, ROOT.kBlue] for (name, hist), color in zip(cut_stats.items(), colors): hist.SetLineColor(color) hist.Draw("same") legend.AddEntry(hist, name) # Final presentation settings legend.Draw("same") # Finally, save and cleanup plot_base.save_plot(output_info, canvas, f"event_cuts_{str(event_activity)}")
def _plot_all_1d_correlations_with_ROOT( jet_hadron: "correlations.Correlations") -> None: """ Plot all 1D correlations in a very basic way with ROOT. Note: We don't want to scale the histogram any further here because it's already been fully scaled! """ # Not ideal, but it's much more convenient to import it here. Importing it at the top # of the file would cause an import loop. from jet_hadron.analysis import correlations canvas = ROOT.TCanvas("canvas1D", "canvas1D") for correlations_groups in [ jet_hadron.correlation_hists_delta_phi, jet_hadron.correlation_hists_delta_eta ]: # Help out mypy... assert isinstance(correlations_groups, (correlations.CorrelationHistogramsDeltaPhi, correlations.CorrelationHistogramsDeltaEta)) for _, observable in correlations_groups: # Draw the 1D histogram. observable.hist.Draw("") output_name = observable.hist.GetName() + "_ROOT" plot_base.save_plot(jet_hadron.output_info, canvas, output_name)
def test_save_plot(logging_mixin, setup_save_tests, use_canvas): """ Test the wrapper for saving a matplotlib plot. """ (obj, figure, canvas, expected_filenames) = setup_save_tests filename = "filename" args = { "obj": obj, "figure": canvas if use_canvas else figure, "output_name": filename, "pdf_with_ROOT": True, } filenames = plot_base.save_plot(**args) # Check the result if use_canvas: canvas.SaveAs.assert_called() else: figure.savefig.assert_called() assert filenames == [ name.format(filename=filename) for name in expected_filenames ]
def _plot_response_spectra_with_ROOT( plot_labels: plot_base.PlotLabels, output_name: str, merged_analysis: analysis_objects.JetHBase, pt_hard_analyses: Analyses, hist_attribute_name: str, colors: Sequence[Tuple[float, float, float]]) -> None: """ Plot 1D response spectra with ROOT. Args: plot_labels: Labels for the plot. output_name: Name under which the plot should be stored. merged_analysis: Full merged together analysis object. pt_hard_analyses: Pt hard dependent analysis objects to be plotted. hist_attribute_name: Name of the attribute under which the histogram is stored. colors: List of colors to be used for plotting the pt hard spectra. """ # Setup canvas = ROOT.TCanvas("canvas", "canvas") canvas.SetLogy(True) # Legend legend = ROOT.TLegend(0.37, 0.55, 0.9, 0.9) legend.SetHeader(r"p_{\mathrm{T}}\:\mathrm{bins}", "C") # Increase text size legend.SetTextSize(0.025) # Use two columns because we have a lot of entries. legend.SetNColumns(2) # Remove the legend border legend.SetBorderSize(0) # Make the legend transparent legend.SetFillStyle(0) # First, we plot the merged analysis. This is the sum of the various pt hard bin contributions. merged_hist = utils.recursive_getattr(merged_analysis, hist_attribute_name) # Apply axis labels (which must be set on the hist) plot_labels.apply_labels(merged_hist) # Style the merged hist to ensure that it is possible to see the points merged_hist.SetMarkerStyle(ROOT.kFullCircle) merged_hist.SetMarkerSize(1) merged_hist.SetMarkerColor(ROOT.kBlack) merged_hist.SetLineColor(ROOT.kBlack) # Ensure that the max is never beyond 300 for better presentation. max_limit = merged_hist.GetXaxis().GetXmax() if max_limit > 300: max_limit = 300 merged_hist.GetXaxis().SetRangeUser(0, max_limit) # Label and draw legend.AddEntry(merged_hist, "Merged") merged_hist.Draw("same") # Now, we plot the pt hard dependent hists for i, ((key_index, analysis), color) in enumerate(zip(pt_hard_analyses.items(), colors)): # Setup color = ROOT.TColor.GetColor(*color) # Determine the proper label. label = labels.pt_range_string( pt_bin=key_index.pt_hard_bin, lower_label="T", upper_label="hard", only_show_lower_value_for_last_bin=True, ) # Retrieve and style the hist hist = utils.recursive_getattr(analysis, hist_attribute_name) hist.SetMarkerStyle(ROOT.kFullCircle + i) hist.SetMarkerSize(1) hist.SetMarkerColor(color) hist.SetLineColor(color) # Label and draw legend.AddEntry(hist, labels.use_label_with_root(label)) hist.Draw("same") # Final presentation settings legend.Draw() # Save and cleanup output_name += "_ROOT" plot_base.save_plot(merged_analysis.output_info, canvas, output_name)
def _plot_response_spectra_with_matplotlib( plot_labels: plot_base.PlotLabels, output_name: str, merged_analysis: analysis_objects.JetHBase, pt_hard_analyses: Analyses, hist_attribute_name: str, colors: Sequence[Tuple[float, float, float]]) -> None: """ Plot 1D response spectra with matplotlib. Args: plot_labels: Labels for the plot. output_name: Name under which the plot should be stored. merged_analysis: Full merged together analysis object. pt_hard_analyses: Pt hard dependent analysis objects to be plotted. hist_attribute_name: Name of the attribute under which the histogram is stored. colors: List of colors to be used for plotting the pt hard spectra. """ # Setup fig, ax = plt.subplots(figsize=(8, 6)) plot_labels.apply_labels(ax) # First, we plot the merged analysis. This is the sum of the various pt hard bin contributions. merged_hist = utils.recursive_getattr(merged_analysis, hist_attribute_name) merged_hist = histogram.Histogram1D.from_existing_hist(merged_hist) ax.errorbar( merged_hist.x, merged_hist.y, yerr=merged_hist.errors, label="Merged", color="black", marker=".", linestyle="", ) # Now, we plot the pt hard dependent hists for (key_index, analysis), color in zip(pt_hard_analyses.items(), colors): # Determine the proper label. label = labels.pt_range_string( pt_bin=key_index.pt_hard_bin, lower_label="T", upper_label="hard", only_show_lower_value_for_last_bin=True, ) # Plot the histogram. hist = utils.recursive_getattr(analysis, hist_attribute_name) h = histogram.Histogram1D.from_existing_hist(hist) ax.errorbar( h.x, h.y, yerr=h.errors, label=label, color=color, marker=".", linestyle="", ) # Final presentation settings # Ensure that the max is never beyond 300 for better presentation. max_limit = np.max(merged_hist.x) if max_limit > 300: max_limit = 300 ax.set_xlim(0, max_limit) ax.set_yscale("log") ax.legend(loc="best", frameon=False) fig.tight_layout() # Save and cleanup output_name += "_mpl" plot_base.save_plot(merged_analysis.output_info, fig, output_name) plt.close(fig)
def _plot_response_matrix_with_matplotlib( name: str, x_label: str, y_label: str, output_name: str, hist: Hist, plot_errors_hist: bool, output_info: analysis_objects.PlottingOutputWrapper) -> None: """ Underlying function to actually plot a response matrix with matplotlib. Args: name: Name of the histogram. x_label: X axis label. y_label: Y axis label. output_name: Output name of the histogram. hist: The response matrix related 2D hist. errors_hist: True if the hist is the response matrix errors hist. output_info: Output information. Returns: None """ # Setup fig, ax = plt.subplots(figsize=(8, 6)) # Convert the histogram X, Y, hist_array = histogram.get_array_from_hist2D( hist=hist, set_zero_to_NaN=True, return_bin_edges=True, ) # Determine and fill args kwargs = {} # Create a log z axis heat map. kwargs["norm"] = matplotlib.colors.LogNorm(vmin=np.nanmin(hist_array), vmax=np.nanmax(hist_array)) logger.debug(f"min: {np.nanmin(hist_array)}, max: {np.nanmax(hist_array)}") # The colormap that we use is the default from sns.heatmap kwargs["cmap"] = plot_base.prepare_colormap(sns.cm.rocket) # Label is included so we could use a legend if we want kwargs["label"] = name logger.debug("kwargs: {}".format(kwargs)) # Determine the edges extent = [np.amin(X), np.amax(X), np.amin(Y), np.amax(Y)] # Finally, create the plot ax_from_imshow = ax.imshow(hist_array.T, extent=extent, interpolation="nearest", aspect="auto", origin="lower", **kwargs) # Add colorbar # It needs to be defined on the figure because it is stored in a separate axis. fig.colorbar(ax_from_imshow, ax=ax) # Final styling ax.set_title(name) ax.set_xlabel(x_label) ax.set_ylabel(y_label) fig.tight_layout() # Save and cleanup output_name += "_mpl" plot_base.save_plot(output_info, fig, output_name) plt.close(fig)