plothist 1.4.0__py3-none-any.whl → 1.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. plothist/__init__.py +5 -5
  2. plothist/_version.py +2 -2
  3. plothist/comparison.py +170 -120
  4. plothist/examples/1d_hist/1d_comparison_asymmetry.py +37 -0
  5. plothist/examples/1d_hist/1d_comparison_difference.py +40 -0
  6. plothist/examples/1d_hist/1d_comparison_efficiency.py +37 -0
  7. plothist/examples/1d_hist/1d_comparison_only_efficiency.py +33 -0
  8. plothist/examples/1d_hist/1d_comparison_pull.py +37 -0
  9. plothist/examples/1d_hist/1d_comparison_ratio.py +37 -0
  10. plothist/examples/1d_hist/1d_comparison_relative_difference.py +37 -0
  11. plothist/examples/1d_hist/1d_comparison_split_ratio.py +37 -0
  12. plothist/examples/1d_hist/1d_elt1.py +38 -0
  13. plothist/examples/1d_hist/1d_elt1_stacked.py +45 -0
  14. plothist/examples/1d_hist/1d_elt2.py +33 -0
  15. plothist/examples/1d_hist/1d_hist_simple.py +28 -0
  16. plothist/examples/1d_hist/1d_int_category.py +41 -0
  17. plothist/examples/1d_hist/1d_profile.py +33 -0
  18. plothist/examples/1d_hist/1d_side_by_side.py +58 -0
  19. plothist/examples/1d_hist/1d_str_category.py +41 -0
  20. plothist/examples/1d_hist/README.rst +4 -0
  21. plothist/examples/2d_hist/2d_hist_correlations.py +65 -0
  22. plothist/examples/2d_hist/2d_hist_simple.py +28 -0
  23. plothist/examples/2d_hist/2d_hist_simple_discrete_colormap.py +42 -0
  24. plothist/examples/2d_hist/2d_hist_uneven.py +28 -0
  25. plothist/examples/2d_hist/2d_hist_with_projections.py +36 -0
  26. plothist/examples/2d_hist/README.rst +4 -0
  27. plothist/examples/README.rst +7 -0
  28. plothist/examples/advanced/1d_comparison_advanced.py +87 -0
  29. plothist/examples/advanced/1d_side_by_side_with_numbers.py +81 -0
  30. plothist/examples/advanced/README.rst +4 -0
  31. plothist/examples/advanced/asymmetry_comparison_advanced.py +133 -0
  32. plothist/examples/advanced/model_examples_flatten2D.py +86 -0
  33. plothist/examples/func_1d/README.rst +4 -0
  34. plothist/examples/func_1d/fct_1d.py +27 -0
  35. plothist/examples/func_1d/fct_1d_stacked.py +42 -0
  36. plothist/examples/model_ex/README.rst +4 -0
  37. plothist/examples/model_ex/model_all_comparisons.py +103 -0
  38. plothist/examples/model_ex/model_all_comparisons_no_model_unc.py +115 -0
  39. plothist/examples/model_ex/model_examples_pull.py +56 -0
  40. plothist/examples/model_ex/model_examples_pull_no_model_unc.py +59 -0
  41. plothist/examples/model_ex/model_examples_stacked.py +74 -0
  42. plothist/examples/model_ex/model_examples_stacked_unstacked.py +60 -0
  43. plothist/examples/model_ex/model_examples_unstacked.py +57 -0
  44. plothist/examples/model_ex/model_with_stacked_and_unstacked_function_components.py +50 -0
  45. plothist/examples/model_ex/model_with_stacked_and_unstacked_histograms_components.py +69 -0
  46. plothist/examples/model_ex/ratio_data_vs_model_with_stacked_and_unstacked_function_components.py +61 -0
  47. plothist/examples/utility/README.rst +4 -0
  48. plothist/examples/utility/add_text_example.py +39 -0
  49. plothist/examples/utility/color_palette_hists.py +94 -0
  50. plothist/examples/utility/color_palette_squares.py +100 -0
  51. plothist/examples/utility/matplotlib_vs_plothist_style.py +63 -0
  52. plothist/examples/utility/uncertainty_types.py +120 -0
  53. plothist/histogramming.py +60 -39
  54. plothist/plothist_style.py +56 -59
  55. plothist/plotters.py +210 -195
  56. plothist/test_helpers.py +43 -0
  57. plothist/variable_registry.py +46 -30
  58. {plothist-1.4.0.dist-info → plothist-1.6.0.dist-info}/METADATA +1 -1
  59. plothist-1.6.0.dist-info/RECORD +64 -0
  60. plothist/scripts/__init__.py +0 -3
  61. plothist/scripts/make_examples.py +0 -209
  62. plothist-1.4.0.dist-info/RECORD +0 -17
  63. plothist-1.4.0.dist-info/entry_points.txt +0 -2
  64. {plothist-1.4.0.dist-info → plothist-1.6.0.dist-info}/WHEEL +0 -0
  65. {plothist-1.4.0.dist-info → plothist-1.6.0.dist-info}/licenses/AUTHORS.md +0 -0
  66. {plothist-1.4.0.dist-info → plothist-1.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,94 @@
1
+ """
2
+ Color palettes in stacked histograms
3
+ ====================================
4
+
5
+ Examples of color palettes in stacked histograms.
6
+ """
7
+
8
+ from plothist_utils import get_dummy_data
9
+
10
+ df = get_dummy_data()
11
+
12
+ import matplotlib.pyplot as plt
13
+
14
+ from plothist import add_text, get_color_palette, make_hist, plot_error_hist, plot_model
15
+
16
+ # Define the histograms
17
+ key = "variable_1"
18
+ xrange = (-8, 10)
19
+ category = "category"
20
+
21
+ # Define masks
22
+ signal_mask = df[category] == 7
23
+ data_mask = df[category] == 8
24
+
25
+ background_categories = [0, 1, 2, 3, 4, 5]
26
+ background_categories_labels = [f"c{i}" for i in background_categories]
27
+ background_masks = [df[category] == p for p in background_categories]
28
+
29
+ # Make histograms
30
+ data_hist = make_hist(df[key][data_mask], bins=50, range=xrange, weights=1)
31
+ background_hists = [
32
+ make_hist(df[key][mask], bins=50, range=xrange, weights=1)
33
+ for mask in background_masks
34
+ ]
35
+ signal_hist = make_hist(df[key][signal_mask], bins=50, range=xrange, weights=1)
36
+
37
+ # Optional: scale to data
38
+ background_scaling_factor = data_hist.sum().value / sum(background_hists).sum().value
39
+ background_hists = [background_scaling_factor * h for h in background_hists]
40
+
41
+ signal_scaling_factor = data_hist.sum().value / signal_hist.sum().value
42
+ signal_hist *= signal_scaling_factor
43
+
44
+
45
+ # Plotting section
46
+ nrows, ncols = 2, 2
47
+
48
+ fig, axes = plt.subplots(
49
+ nrows=nrows,
50
+ ncols=ncols,
51
+ figsize=(12, 10),
52
+ )
53
+ fig.subplots_adjust(hspace=0.25)
54
+
55
+ cmap_list = ["viridis", "ggplot", "coolwarm", "YlGnBu_r"]
56
+ ax_coords = [(x, y) for x in range(nrows) for y in range(ncols)]
57
+
58
+ for k, cmap_name in enumerate(cmap_list):
59
+ background_categories_colors = get_color_palette(
60
+ cmap_name, len(background_categories)
61
+ )
62
+
63
+ ax = axes[ax_coords[k]]
64
+
65
+ plot_model(
66
+ stacked_components=background_hists,
67
+ stacked_labels=background_categories_labels,
68
+ stacked_colors=background_categories_colors,
69
+ xlabel=key,
70
+ ylabel="Entries",
71
+ model_uncertainty=False,
72
+ fig=fig,
73
+ ax=ax,
74
+ )
75
+
76
+ plot_error_hist(
77
+ data_hist,
78
+ color="black",
79
+ label="Data",
80
+ ax=ax,
81
+ )
82
+
83
+ ax.set_xlim(xrange)
84
+ ax.legend()
85
+
86
+ cmap_name = cmap_name.replace("_", r"\_")
87
+ add_text(
88
+ rf"$\mathrm{{\mathbf{{cmap = {cmap_name}}}}}$", x="right", fontsize=12, ax=ax
89
+ )
90
+
91
+ fig.savefig(
92
+ "color_palette_hists.svg",
93
+ bbox_inches="tight",
94
+ )
@@ -0,0 +1,100 @@
1
+ """
2
+ Color palettes
3
+ ==============
4
+
5
+ Examples of color palettes.
6
+ """
7
+
8
+ import matplotlib.colors as mcolors
9
+ import matplotlib.pyplot as plt
10
+ import numpy as np
11
+ from matplotlib import patches
12
+
13
+ from plothist import get_color_palette
14
+
15
+
16
+ def create_palette_plot(colors, fig_name, add_text=False, add_black_border=False):
17
+ ncolors = len(colors)
18
+
19
+ # Create a figure and axis
20
+ fig, ax = plt.subplots(figsize=(ncolors, 1))
21
+
22
+ # Plot the colored squares with small spacing
23
+ square_size = 1
24
+ spacing = 0.1
25
+ x = 0
26
+
27
+ for color in colors:
28
+ rect = patches.Rectangle((x, 0), square_size, square_size, color=color)
29
+ ax.add_patch(rect)
30
+ x += square_size + spacing
31
+
32
+ if add_text:
33
+ # Add text displaying the color value
34
+ ax.text(
35
+ x - (square_size + spacing) / 1.81,
36
+ -0.18,
37
+ mcolors.rgb2hex(color).upper(),
38
+ ha="center",
39
+ fontsize=10,
40
+ )
41
+
42
+ # Set the x-axis limits and show the ticks
43
+ ax.set_xlim(-0.5, x - spacing)
44
+ ax.set_xticks(np.arange(0, x, square_size + spacing))
45
+ ax.set_xticklabels(np.arange(1, ncolors + 1), fontsize=8)
46
+ ax.set_xticklabels([]) # Remove the x-tick labels
47
+
48
+ # Set the y-axis ticks and labels
49
+ ax.set_yticks([])
50
+ ax.set_yticklabels([])
51
+
52
+ # Remove the borders around the plot
53
+ ax.spines["top"].set_visible(False)
54
+ ax.spines["bottom"].set_visible(False)
55
+ ax.spines["left"].set_visible(False)
56
+ ax.spines["right"].set_visible(False)
57
+
58
+ # Remove the x-label and y-label
59
+ ax.set_xlabel("")
60
+ ax.set_ylabel("")
61
+
62
+ if add_black_border:
63
+ # Add a black border rectangle
64
+ border_rect = patches.Rectangle(
65
+ (0, 0),
66
+ x - spacing,
67
+ square_size,
68
+ edgecolor="black",
69
+ facecolor="none",
70
+ linewidth=1,
71
+ )
72
+ ax.add_patch(border_rect)
73
+
74
+ # Adjust the padding and remove extra whitespace
75
+ plt.margins(0)
76
+ plt.gca().set_axis_off()
77
+ plt.subplots_adjust(left=0.05, right=0.95)
78
+
79
+ plt.savefig(fig_name, bbox_inches="tight")
80
+
81
+ return fig
82
+
83
+
84
+ figs = []
85
+
86
+ ncolors = 7
87
+
88
+ ncolors_ggplot = 7 if ncolors > 7 else ncolors
89
+ colors = get_color_palette("ggplot", ncolors_ggplot)
90
+ figs.append(
91
+ create_palette_plot(colors, fig_name="usage_style_cycle.svg", add_text=True)
92
+ )
93
+
94
+ colors = get_color_palette("cubehelix", ncolors)
95
+ figs.append(create_palette_plot(colors, fig_name="usage_cubehelix.svg"))
96
+
97
+ cmap_list = ["viridis", "coolwarm", "YlGnBu_r"]
98
+ for cmap_name in cmap_list:
99
+ colors = get_color_palette(cmap_name, ncolors)
100
+ figs.append(create_palette_plot(colors, fig_name=f"usage_{cmap_name}_palette.svg"))
@@ -0,0 +1,63 @@
1
+ """
2
+ Default style: matplotlib vs plothist
3
+ =====================================
4
+
5
+ Illustration of the difference between matplotlib and plothist default styles.
6
+ """
7
+
8
+ import matplotlib.pyplot as plt
9
+ import numpy as np
10
+ from plothist_utils import get_dummy_data
11
+
12
+ df = get_dummy_data()
13
+
14
+ figs = []
15
+
16
+ for style in ["matplotlib", "plothist"]:
17
+ if style == "matplotlib":
18
+ plt.style.use("default")
19
+ plt.rcParams["font.family"] = "DejaVu Sans"
20
+ else:
21
+ # No need to set the style if we use plothist, just importing it is enough
22
+ # Here we set the style because the matplotlib style was set before
23
+ from plothist import set_style
24
+
25
+ set_style("default")
26
+
27
+ # Create a figure with subplots
28
+ fig, (ax1, ax2) = plt.subplots(
29
+ 2, 1, figsize=(6, 5.4), sharex=True, gridspec_kw={"height_ratios": [4, 1]}
30
+ )
31
+
32
+ # Plot histograms in the first subplot (ax1)
33
+ hist_0, bins, _ = ax1.hist(
34
+ df["variable_0"], bins=20, histtype="step", linewidth=1.2, label="h1"
35
+ )
36
+ h1 = ax1.hist(
37
+ df["variable_1"], bins=bins, histtype="step", linewidth=1.2, label="h2"
38
+ )
39
+ ax1.set_ylabel("Entries")
40
+ ax1.legend()
41
+
42
+ # Calculate the ratio of histogram values and plot in the second subplot (ax2)
43
+ with np.errstate(divide="ignore", invalid="ignore"):
44
+ ratio = hist_0 / h1[0] # Divide bin values of variable_0 by variable_1
45
+ bin_centers = 0.5 * (bins[:-1] + bins[1:]) # Calculate bin centers
46
+
47
+ # Create fake error bars for the ratio
48
+ ax2.plot(bin_centers, ratio, marker="|", linestyle="", markersize=15, color="black")
49
+ ax2.plot(bin_centers, ratio, marker="o", linestyle="", markersize=4, color="black")
50
+
51
+ ax2.axhline(y=1, color="black", linestyle="--", linewidth=0.8)
52
+ ax2.set_xlabel("Variable")
53
+ ax2.set_ylabel("Ratio")
54
+
55
+ ax1.set_xlim(-10, 10)
56
+ ax2.set_xlim(-10, 10)
57
+ ax2.set_ylim(0, 2)
58
+
59
+ fig.subplots_adjust(hspace=0.15)
60
+
61
+ fig.savefig(f"{style}_example.svg", bbox_inches="tight")
62
+
63
+ figs.append(fig)
@@ -0,0 +1,120 @@
1
+ """
2
+ Representation of different uncertainty types.
3
+ ==============================================
4
+
5
+ This example demonstrates how to use the `plot_error_hist` function with different uncertainty types
6
+ """
7
+
8
+ import boost_histogram as bh
9
+ import matplotlib.pyplot as plt
10
+ import numpy as np
11
+
12
+ from plothist import add_text, plot_error_hist
13
+
14
+
15
+ def shifted_array(values, offset: int, size: int = 15) -> np.ndarray:
16
+ """
17
+ Create an array of a given size with NaNs and fill it with values at specified offsets.
18
+ The values are inserted at every offset starting from the given offset.
19
+ """
20
+
21
+ arr = np.full(size, np.nan)
22
+ indices = range(offset, size, len(values))
23
+
24
+ for i, idx in enumerate(indices):
25
+ if i >= len(values):
26
+ break
27
+ arr[idx] = values[i]
28
+
29
+ return arr
30
+
31
+
32
+ def make_grouped_edges(
33
+ n_groups, group_size=4, inner_spacing=0.1, inter_spacing=0.2
34
+ ) -> np.ndarray:
35
+ """
36
+ Create a set of edges for a histogram with grouped categories.
37
+ """
38
+
39
+ edges = [
40
+ group_start + i * inner_spacing
41
+ for group in range(n_groups)
42
+ for i in range(group_size)
43
+ for group_start in [
44
+ group * (group_size * inner_spacing + inter_spacing - inner_spacing)
45
+ ]
46
+ ]
47
+ return np.array(edges)
48
+
49
+
50
+ # Create a category axis with explicit locations
51
+ edges = make_grouped_edges(4)
52
+ axis = bh.axis.Variable(edges)
53
+
54
+ hists = []
55
+ entries = [0, 0.5, 3, 500]
56
+
57
+ for k in range(3):
58
+ hist = bh.Histogram(axis, storage=bh.storage.Weight())
59
+ values = shifted_array(entries, k)
60
+ hist[:] = np.c_[values, values]
61
+ hists.append(hist)
62
+
63
+
64
+ fig, (ax_top, ax_bot) = plt.subplots(
65
+ 2, 1, gridspec_kw={"height_ratios": [1, 3], "hspace": 0.05}
66
+ )
67
+
68
+ for ax in (ax_top, ax_bot):
69
+ plot_error_hist(
70
+ hists[0], ax=ax, label="symmetrical", uncertainty_type="symmetrical"
71
+ )
72
+ plot_error_hist(
73
+ hists[1], ax=ax, label="asymmetrical", uncertainty_type="asymmetrical"
74
+ )
75
+ plot_error_hist(
76
+ hists[2],
77
+ ax=ax,
78
+ label="asymmetrical_double_sided_zeros",
79
+ uncertainty_type="asymmetrical_double_sided_zeros",
80
+ )
81
+
82
+ add_text("plot_error_hist() with different uncertainty type", ax=ax_top, x="right")
83
+
84
+ # Set axis limits
85
+ ax_top.set_ylim(465, 530)
86
+ ax_bot.set_ylim(-0.5, 6.9)
87
+ ax_bot.set_xlim(xmin=-0.05)
88
+
89
+ # Format bottom ticks and labels
90
+ ax_bot.set_xticks(edges[1::4] + 0.05)
91
+ ax_bot.set_xlabel("Entry category")
92
+ ax_bot.set_xticklabels(entries)
93
+ ax_bot.set_ylabel("Entries")
94
+ ax_bot.yaxis.label.set_horizontalalignment("left")
95
+ ax_bot.spines.top.set_visible(False)
96
+ ax_bot.xaxis.set_minor_locator(plt.NullLocator()) # Hide x-axis minor ticks
97
+
98
+ # Format top ticks and labels
99
+ ax_top.xaxis.tick_top()
100
+ ax_top.spines.bottom.set_visible(False)
101
+ ax_top.set_xticklabels([])
102
+ ax_top.set_xticks([])
103
+
104
+ # Draw break marks
105
+ d = 0.5 # proportion of vertical to horizontal extent of the slanted line
106
+ kwargs = {
107
+ "marker": [(-1, -d), (1, d)],
108
+ "markersize": 12,
109
+ "linestyle": "none",
110
+ "color": "k",
111
+ "mec": "k",
112
+ "mew": 1,
113
+ "clip_on": False,
114
+ }
115
+ ax_top.plot([0, 1], [0, 0], transform=ax_top.transAxes, **kwargs)
116
+ ax_bot.plot([0, 1], [1, 1], transform=ax_bot.transAxes, **kwargs)
117
+
118
+ ax_top.legend(loc="upper left")
119
+
120
+ fig.savefig("uncertainty_types.svg", bbox_inches="tight")
plothist/histogramming.py CHANGED
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import warnings
4
+ from collections.abc import Sequence
5
+ from typing import Callable
4
6
 
5
7
  import boost_histogram as bh
6
8
  import numpy as np
@@ -15,17 +17,23 @@ class RangeWarning(Warning):
15
17
  warnings.filterwarnings("always", category=RangeWarning)
16
18
 
17
19
 
18
- def create_axis(bins, range=None, data=None, overflow=False, underflow=False):
20
+ def create_axis(
21
+ bins: int | list[float] | np.ndarray,
22
+ range: tuple[float | str, float | str] | None = None,
23
+ data: list[float] | np.ndarray | None = None,
24
+ overflow: bool = False,
25
+ underflow: bool = False,
26
+ ) -> bh.axis.Regular | bh.axis.Variable:
19
27
  """
20
28
  Create an axis object for histogram binning based on the input data and parameters.
21
29
 
22
30
  Parameters
23
31
  ----------
24
- bins : int or array-like
32
+ bins : int or list[float]
25
33
  The number of bins or bin edges for the axis.
26
- range : None or tuple, optional
27
- The range of the axis. If None, it will be determined based on the data.
28
- data : array-like, optional
34
+ range : None or tuple[float | str, float | str], optional
35
+ The range of the axis. If None, it will be determined based on the data. Default is None.
36
+ data : list[float] or np.ndarray, optional
29
37
  The input data for determining the axis range. Default is None.
30
38
  overflow : bool, optional
31
39
  Whether to include an overflow bin. If False, the upper edge of the last bin is inclusive. Default is False.
@@ -52,19 +60,16 @@ def create_axis(bins, range=None, data=None, overflow=False, underflow=False):
52
60
  if data is None:
53
61
  data = np.array([])
54
62
 
55
- try:
56
- N = len(bins)
57
- except TypeError:
58
- N = 1
63
+ is_variable_bins = isinstance(bins, (list, np.ndarray))
59
64
 
60
- if N > 1:
65
+ if is_variable_bins:
61
66
  if range is not None:
62
67
  warnings.warn(
63
68
  f"Custom binning -> ignore supplied range ({range}).", stacklevel=2
64
69
  )
65
70
  return bh.axis.Variable(bins, underflow=underflow, overflow=overflow)
66
71
 
67
- if bins <= 0:
72
+ if isinstance(bins, int) and bins <= 0:
68
73
  raise ValueError(f"Number of bins must be positive, but got {bins}.")
69
74
 
70
75
  # Inspired from np.histograms
@@ -74,8 +79,8 @@ def create_axis(bins, range=None, data=None, overflow=False, underflow=False):
74
79
  "Cannot use 'min'/'max' range values with empty data. "
75
80
  "Please supply a range or provide data."
76
81
  )
77
- x_min = min(data) if range[0] == "min" else range[0]
78
- x_max = max(data) if range[1] == "max" else range[1]
82
+ x_min = min(data) if range[0] == "min" else float(range[0])
83
+ x_max = max(data) if range[1] == "max" else float(range[1])
79
84
  if x_min > x_max:
80
85
  raise ValueError(
81
86
  f"Range of [{x_min}, {x_max}] is not valid. Max must be larger than min."
@@ -84,10 +89,10 @@ def create_axis(bins, range=None, data=None, overflow=False, underflow=False):
84
89
  raise ValueError(f"Range of [{x_min}, {x_max}] is not finite.")
85
90
  elif len(data) == 0:
86
91
  # handle empty arrays. Can't determine range, so use 0-1.
87
- x_min, x_max = 0, 1
92
+ x_min, x_max = 0.0, 1.0
88
93
  else:
89
- x_min = min(data)
90
- x_max = max(data)
94
+ x_min = float(min(data))
95
+ x_max = float(max(data))
91
96
  if not (np.isfinite(x_min) and np.isfinite(x_max)):
92
97
  raise ValueError(f"Autodetected range of [{x_min}, {x_max}] is not finite.")
93
98
 
@@ -99,30 +104,35 @@ def create_axis(bins, range=None, data=None, overflow=False, underflow=False):
99
104
  return bh.axis.Regular(bins, x_min, x_max, underflow=underflow, overflow=overflow)
100
105
 
101
106
 
102
- def make_hist(data=None, bins=50, range=None, weights=1):
107
+ def make_hist(
108
+ data: list[float] | np.ndarray | None = None,
109
+ bins: int | list[float] | np.ndarray = 50,
110
+ range: tuple[float | str, float | str] | None = None,
111
+ weights: float | list[float] | np.ndarray = 1,
112
+ ) -> bh.Histogram:
103
113
  """
104
114
  Create a histogram object and fill it with the provided data.
105
115
 
106
116
  Parameters
107
117
  ----------
108
- data : array-like, optional
118
+ data : list[float] or np.ndarray, optional
109
119
  1D array-like data used to fill the histogram (default is None).
110
120
  If None is provided, an empty histogram is returned.
111
- bins : int or tuple, optional
121
+ bins : int or list[float], optional
112
122
  Binning specification for the histogram (default is 50).
113
123
  If an integer, it represents the number of bins.
114
- If a tuple, it should be the explicit list of all bin edges.
115
- range : tuple, optional
124
+ If a list, it should be the explicit list of all bin edges.
125
+ range : tuple[float | str, float | str], optional
116
126
  The range of values to consider for the histogram bins (default is None).
117
127
  If None, the range is determined from the data.
118
- weights : float or array-like, optional
128
+ weights : float or list[float] or np.ndarray, optional
119
129
  Weight(s) to apply to the data points (default is 1).
120
130
  If a float, a single weight is applied to all data points.
121
131
  If an array-like, weights are applied element-wise.
122
132
 
123
133
  Returns
124
134
  -------
125
- histogram : boost_histogram.Histogram
135
+ histogram : bh.Histogram
126
136
  The filled histogram object.
127
137
 
128
138
  Warns
@@ -160,31 +170,38 @@ def make_hist(data=None, bins=50, range=None, weights=1):
160
170
  return h
161
171
 
162
172
 
163
- def make_2d_hist(data=None, bins=(10, 10), range=(None, None), weights=1):
173
+ def make_2d_hist(
174
+ data: list[np.ndarray] | np.ndarray | None = None,
175
+ bins: Sequence[int | Sequence[float]] | None = None,
176
+ range: tuple[
177
+ tuple[float | str, float | str] | None, tuple[float | str, float | str] | None
178
+ ] = (None, None),
179
+ weights: float | list[float] | np.ndarray = 1,
180
+ ) -> bh.Histogram:
164
181
  """
165
182
  Create a 2D histogram object and fill it with the provided data.
166
183
 
167
184
  Parameters
168
185
  ----------
169
- data : array-like, optional
186
+ data : list[np.ndarray] or np.ndarray, optional
170
187
  2D array-like data used to fill the histogram (default is None).
171
188
  If None is provided, an empty histogram is returned.
172
- bins : tuple, optional
173
- Binning specification for each dimension of the histogram (default is (10, 10)).
189
+ bins : Sequence[int | Sequence[float]], optional
190
+ Binning specification for each dimension of the histogram (if None, it will be set to [50, 50]).
174
191
  Each element of the tuple represents the number of bins for the corresponding dimension.
175
192
  Also support explicit bin edges specification (for non-constant bin size).
176
- range : tuple, optional
193
+ range : tuple[tuple[float | str, float | str] | None, tuple[float | str, float | str] | None], optional
177
194
  The range of values to consider for each dimension of the histogram (default is (None, None)).
178
195
  If None, the range is determined from the data for that dimension.
179
196
  The tuple should have the same length as the data.
180
- weights : float or array-like, optional
197
+ weights : float or list[float] or np.ndarray, optional
181
198
  Weight(s) to apply to the data points (default is 1).
182
199
  If a float, a single weight is applied to all data points.
183
200
  If an array-like, weights are applied element-wise.
184
201
 
185
202
  Returns
186
203
  -------
187
- histogram : boost_histogram.Histogram
204
+ histogram : bh.Histogram
188
205
  The filled 2D histogram object.
189
206
 
190
207
  Raises
@@ -203,6 +220,8 @@ def make_2d_hist(data=None, bins=(10, 10), range=(None, None), weights=1):
203
220
  raise ValueError("data should have two components, x and y")
204
221
  if len(data[0]) != len(data[1]):
205
222
  raise ValueError("x and y must have the same length.")
223
+ if bins is None:
224
+ bins = [50, 50]
206
225
 
207
226
  x_axis = create_axis(bins[0], range[0], data[0])
208
227
  y_axis = create_axis(bins[1], range[1], data[1])
@@ -236,13 +255,13 @@ def make_2d_hist(data=None, bins=(10, 10), range=(None, None), weights=1):
236
255
  return h
237
256
 
238
257
 
239
- def _check_counting_histogram(hist):
258
+ def _check_counting_histogram(hist: bh.Histogram) -> None:
240
259
  """
241
260
  Check that the histogram is a counting histogram.
242
261
 
243
262
  Parameters
244
263
  ----------
245
- hist : boost_histogram.Histogram
264
+ hist : bh.Histogram
246
265
  The histogram to check.
247
266
 
248
267
  Raise
@@ -257,7 +276,9 @@ def _check_counting_histogram(hist):
257
276
  )
258
277
 
259
278
 
260
- def _make_hist_from_function(func, ref_hist):
279
+ def _make_hist_from_function(
280
+ func: Callable[[np.ndarray], np.ndarray], ref_hist: bh.Histogram
281
+ ) -> bh.Histogram:
261
282
  """
262
283
  Create a histogram from a function and a reference histogram.
263
284
  The returned histogram has the same binning as the reference histogram and
@@ -265,14 +286,14 @@ def _make_hist_from_function(func, ref_hist):
265
286
 
266
287
  Parameters
267
288
  ----------
268
- func : function
289
+ func : Callable[[np.ndarray], np.ndarray]
269
290
  1D function. The function should support vectorization (i.e. accept a numpy array as input).
270
- ref_hist : boost_histogram.Histogram
291
+ ref_hist : bh.Histogram
271
292
  The reference 1D histogram to use for the binning.
272
293
 
273
294
  Returns
274
295
  -------
275
- hist : boost_histogram.Histogram
296
+ hist : bh.Histogram
276
297
  The histogram filled with the function.
277
298
 
278
299
  Raises
@@ -290,18 +311,18 @@ def _make_hist_from_function(func, ref_hist):
290
311
  return hist
291
312
 
292
313
 
293
- def flatten_2d_hist(hist):
314
+ def flatten_2d_hist(hist: bh.Histogram) -> bh.Histogram:
294
315
  """
295
316
  Flatten a 2D histogram into a 1D histogram.
296
317
 
297
318
  Parameters
298
319
  ----------
299
- hist : Histogram object
320
+ hist : bh.Histogram
300
321
  The 2D histogram to be flattened.
301
322
 
302
323
  Returns
303
324
  -------
304
- Histogram object
325
+ bh.Histogram
305
326
  The flattened 1D histogram.
306
327
 
307
328
  Raises