def test_recursive_getattr_fail(logging_mixin: Any, mocker: Any) -> None: """ Test for failure of recursive getattr. It will fail the same was as the standard getattr. """ obj = mocker.MagicMock(spec=["sole_attr"]) with pytest.raises(AttributeError) as exception_info: utils.recursive_getattr(obj, "nonexistent_attr") assert "nonexistent_attr" in exception_info.value.args[0]
def merge_pt_hard_binned_analyses(analyses: Iterator[Tuple[Any, analysis_objects.JetHBase]], hist_attribute_name: str, output_analysis_object: Any) -> None: """ Merge together all scaled histograms. Args: analyses: Pt hard dependent analyses which should be merged together. hist_attribute_name: Name of the attribute where the hist is stored. output_analysis_object: Object where the histogram will be stored under ``hist_attribute_name``. Returns: None """ output_hist: Hist = None for _, analysis in analyses: input_hist = utils.recursive_getattr(analysis, hist_attribute_name) if output_hist is None: # NOTE: We don't need to set a new name - it will be fine with the same name. output_hist = input_hist.Clone() # Reset so we can just Add() all hists without worrying which hist is being processed output_hist.Reset() # NOTE: Sumw2 is kept even after resetting. output_hist.Add(input_hist) # Save the final result utils.recursive_setattr(output_analysis_object, hist_attribute_name, output_hist)
def test_recursive_setattr(setup_recursive_setattr: Any) -> None: """ Test setting an attribute with recursive setattr. """ # Setup obj, path = setup_recursive_setattr # Set the attribute and check the result new_value = "new value" utils.recursive_setattr(obj, path, new_value) assert utils.recursive_getattr(obj, path) == new_value
def _get_hists_from_analysis_objects(analyses: Mapping[str, analysis_objects.JetHBase], hist_attribute_name: str) -> Dict[str, Hist]: """ Retrieve histograms from an analysis object stored under specified attribute names. Args: analyses: Analysis objects to be processed according to values in this pt hard bin. hist_attribute_name: Names of the attributes to retrieve the histograms. Returns: Extracted histograms. """ hists: Dict[str, Hist] = {} for key, analysis in analyses.items(): hists[key] = utils.recursive_getattr(analysis, hist_attribute_name) return hists
def test_recursive_getattr(logging_mixin, mocker, path, expected): """ Tests for recursive getattr. """ # Setup mock objects from which we will recursively grab attributes mock_obj1 = mocker.MagicMock(spec=["standard_attr", "attr1"]) mock_obj2 = mocker.MagicMock(spec=["attr3"]) mock_obj3 = mocker.MagicMock(spec=["my_attr"]) mock_obj1.standard_attr = "standard_attr_value" mock_obj1.attr1 = mock_obj2 mock_obj2.attr3 = mock_obj3 mock_obj3.my_attr = "recursive_attr_value" # For convenience obj = mock_obj1 # Check the returned value assert expected == utils.recursive_getattr(obj, path)
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 test_recursive_getattr_defualt_value(logging_mixin: Any, mocker: Any) -> None: """ Test for retrieving a default value with getattr. """ obj = mocker.MagicMock(spec=["sole_attr"]) assert "default_value" == utils.recursive_getattr(obj, "nonexistent_attr", "default_value")