plothist 1.3.2__py3-none-any.whl → 1.5.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.
- plothist/__init__.py +66 -74
- plothist/_version.py +21 -0
- plothist/_version.pyi +2 -0
- plothist/comparison.py +115 -106
- plothist/examples/1d_hist/1d_comparison_asymmetry.py +37 -0
- plothist/examples/1d_hist/1d_comparison_difference.py +40 -0
- plothist/examples/1d_hist/1d_comparison_efficiency.py +37 -0
- plothist/examples/1d_hist/1d_comparison_only_efficiency.py +33 -0
- plothist/examples/1d_hist/1d_comparison_pull.py +37 -0
- plothist/examples/1d_hist/1d_comparison_ratio.py +37 -0
- plothist/examples/1d_hist/1d_comparison_relative_difference.py +37 -0
- plothist/examples/1d_hist/1d_comparison_split_ratio.py +37 -0
- plothist/examples/1d_hist/1d_elt1.py +38 -0
- plothist/examples/1d_hist/1d_elt1_stacked.py +45 -0
- plothist/examples/1d_hist/1d_elt2.py +33 -0
- plothist/examples/1d_hist/1d_hist_simple.py +28 -0
- plothist/examples/1d_hist/1d_int_category.py +41 -0
- plothist/examples/1d_hist/1d_profile.py +33 -0
- plothist/examples/1d_hist/1d_side_by_side.py +58 -0
- plothist/examples/1d_hist/1d_str_category.py +41 -0
- plothist/examples/1d_hist/README.rst +4 -0
- plothist/examples/2d_hist/2d_hist_correlations.py +65 -0
- plothist/examples/2d_hist/2d_hist_simple.py +28 -0
- plothist/examples/2d_hist/2d_hist_simple_discrete_colormap.py +42 -0
- plothist/examples/2d_hist/2d_hist_uneven.py +28 -0
- plothist/examples/2d_hist/2d_hist_with_projections.py +36 -0
- plothist/examples/2d_hist/README.rst +4 -0
- plothist/examples/README.rst +7 -0
- plothist/examples/advanced/1d_comparison_advanced.py +87 -0
- plothist/examples/advanced/1d_side_by_side_with_numbers.py +81 -0
- plothist/examples/advanced/README.rst +4 -0
- plothist/examples/advanced/asymmetry_comparison_advanced.py +133 -0
- plothist/examples/advanced/model_examples_flatten2D.py +86 -0
- plothist/examples/func_1d/README.rst +4 -0
- plothist/examples/func_1d/fct_1d.py +27 -0
- plothist/examples/func_1d/fct_1d_stacked.py +42 -0
- plothist/examples/model_ex/README.rst +4 -0
- plothist/examples/model_ex/model_all_comparisons.py +103 -0
- plothist/examples/model_ex/model_all_comparisons_no_model_unc.py +115 -0
- plothist/examples/model_ex/model_examples_pull.py +56 -0
- plothist/examples/model_ex/model_examples_pull_no_model_unc.py +59 -0
- plothist/examples/model_ex/model_examples_stacked.py +74 -0
- plothist/examples/model_ex/model_examples_stacked_unstacked.py +60 -0
- plothist/examples/model_ex/model_examples_unstacked.py +57 -0
- plothist/examples/model_ex/model_with_stacked_and_unstacked_function_components.py +50 -0
- plothist/examples/model_ex/model_with_stacked_and_unstacked_histograms_components.py +69 -0
- plothist/examples/model_ex/ratio_data_vs_model_with_stacked_and_unstacked_function_components.py +61 -0
- plothist/examples/utility/README.rst +4 -0
- plothist/examples/utility/add_text_example.py +39 -0
- plothist/examples/utility/color_palette_hists.py +94 -0
- plothist/examples/utility/color_palette_squares.py +100 -0
- plothist/examples/utility/matplotlib_vs_plothist_style.py +63 -0
- plothist/histogramming.py +77 -48
- plothist/plothist_style.py +61 -62
- plothist/plotters.py +280 -233
- plothist/test_helpers.py +43 -0
- plothist/variable_registry.py +62 -43
- {plothist-1.3.2.dist-info → plothist-1.5.0.dist-info}/METADATA +20 -12
- plothist-1.5.0.dist-info/RECORD +63 -0
- {plothist-1.3.2.dist-info → plothist-1.5.0.dist-info}/licenses/LICENSE +1 -1
- plothist/dummy_data.csv +0 -100001
- plothist/get_dummy_data.py +0 -17
- plothist/scripts/__init__.py +0 -2
- plothist/scripts/install_latin_modern_fonts.py +0 -145
- plothist/scripts/make_examples.py +0 -210
- plothist-1.3.2.dist-info/RECORD +0 -18
- plothist-1.3.2.dist-info/entry_points.txt +0 -3
- {plothist-1.3.2.dist-info → plothist-1.5.0.dist-info}/WHEEL +0 -0
- {plothist-1.3.2.dist-info → plothist-1.5.0.dist-info}/licenses/AUTHORS.md +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)
|
plothist/histogramming.py
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import warnings
|
|
4
|
+
from collections.abc import Sequence
|
|
5
|
+
from typing import Callable
|
|
6
|
+
|
|
1
7
|
import boost_histogram as bh
|
|
2
8
|
import numpy as np
|
|
3
|
-
import warnings
|
|
4
9
|
|
|
5
10
|
|
|
6
11
|
# Define a custom warning for range issues
|
|
@@ -12,18 +17,24 @@ class RangeWarning(Warning):
|
|
|
12
17
|
warnings.filterwarnings("always", category=RangeWarning)
|
|
13
18
|
|
|
14
19
|
|
|
15
|
-
def create_axis(
|
|
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:
|
|
16
27
|
"""
|
|
17
28
|
Create an axis object for histogram binning based on the input data and parameters.
|
|
18
29
|
|
|
19
30
|
Parameters
|
|
20
31
|
----------
|
|
21
|
-
bins : int or
|
|
32
|
+
bins : int or list[float]
|
|
22
33
|
The number of bins or bin edges for the axis.
|
|
23
|
-
range : None or tuple, optional
|
|
24
|
-
The range of the axis. If None, it will be determined based on the data.
|
|
25
|
-
data :
|
|
26
|
-
The input data for determining the axis range. Default is
|
|
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
|
|
37
|
+
The input data for determining the axis range. Default is None.
|
|
27
38
|
overflow : bool, optional
|
|
28
39
|
Whether to include an overflow bin. If False, the upper edge of the last bin is inclusive. Default is False.
|
|
29
40
|
underflow : bool, optional
|
|
@@ -46,20 +57,19 @@ def create_axis(bins, range=None, data=np.array([]), overflow=False, underflow=F
|
|
|
46
57
|
ValueError
|
|
47
58
|
If the range parameter contains "min" or "max" but the data is empty.
|
|
48
59
|
"""
|
|
60
|
+
if data is None:
|
|
61
|
+
data = np.array([])
|
|
49
62
|
|
|
50
|
-
|
|
51
|
-
N = len(bins)
|
|
52
|
-
except TypeError:
|
|
53
|
-
N = 1
|
|
63
|
+
is_variable_bins = isinstance(bins, (list, np.ndarray))
|
|
54
64
|
|
|
55
|
-
if
|
|
65
|
+
if is_variable_bins:
|
|
56
66
|
if range is not None:
|
|
57
67
|
warnings.warn(
|
|
58
68
|
f"Custom binning -> ignore supplied range ({range}).", stacklevel=2
|
|
59
69
|
)
|
|
60
70
|
return bh.axis.Variable(bins, underflow=underflow, overflow=overflow)
|
|
61
71
|
|
|
62
|
-
if bins <= 0:
|
|
72
|
+
if isinstance(bins, int) and bins <= 0:
|
|
63
73
|
raise ValueError(f"Number of bins must be positive, but got {bins}.")
|
|
64
74
|
|
|
65
75
|
# Inspired from np.histograms
|
|
@@ -69,8 +79,8 @@ def create_axis(bins, range=None, data=np.array([]), overflow=False, underflow=F
|
|
|
69
79
|
"Cannot use 'min'/'max' range values with empty data. "
|
|
70
80
|
"Please supply a range or provide data."
|
|
71
81
|
)
|
|
72
|
-
x_min = min(data) if range[0] == "min" else range[0]
|
|
73
|
-
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])
|
|
74
84
|
if x_min > x_max:
|
|
75
85
|
raise ValueError(
|
|
76
86
|
f"Range of [{x_min}, {x_max}] is not valid. Max must be larger than min."
|
|
@@ -79,10 +89,10 @@ def create_axis(bins, range=None, data=np.array([]), overflow=False, underflow=F
|
|
|
79
89
|
raise ValueError(f"Range of [{x_min}, {x_max}] is not finite.")
|
|
80
90
|
elif len(data) == 0:
|
|
81
91
|
# handle empty arrays. Can't determine range, so use 0-1.
|
|
82
|
-
x_min, x_max = 0, 1
|
|
92
|
+
x_min, x_max = 0.0, 1.0
|
|
83
93
|
else:
|
|
84
|
-
x_min = min(data)
|
|
85
|
-
x_max = max(data)
|
|
94
|
+
x_min = float(min(data))
|
|
95
|
+
x_max = float(max(data))
|
|
86
96
|
if not (np.isfinite(x_min) and np.isfinite(x_max)):
|
|
87
97
|
raise ValueError(f"Autodetected range of [{x_min}, {x_max}] is not finite.")
|
|
88
98
|
|
|
@@ -94,30 +104,35 @@ def create_axis(bins, range=None, data=np.array([]), overflow=False, underflow=F
|
|
|
94
104
|
return bh.axis.Regular(bins, x_min, x_max, underflow=underflow, overflow=overflow)
|
|
95
105
|
|
|
96
106
|
|
|
97
|
-
def make_hist(
|
|
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:
|
|
98
113
|
"""
|
|
99
114
|
Create a histogram object and fill it with the provided data.
|
|
100
115
|
|
|
101
116
|
Parameters
|
|
102
117
|
----------
|
|
103
|
-
data :
|
|
104
|
-
1D array-like data used to fill the histogram (default is
|
|
105
|
-
If
|
|
106
|
-
bins : int or
|
|
118
|
+
data : list[float] or np.ndarray, optional
|
|
119
|
+
1D array-like data used to fill the histogram (default is None).
|
|
120
|
+
If None is provided, an empty histogram is returned.
|
|
121
|
+
bins : int or list[float], optional
|
|
107
122
|
Binning specification for the histogram (default is 50).
|
|
108
123
|
If an integer, it represents the number of bins.
|
|
109
|
-
If a
|
|
110
|
-
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
|
|
111
126
|
The range of values to consider for the histogram bins (default is None).
|
|
112
127
|
If None, the range is determined from the data.
|
|
113
|
-
weights : float or
|
|
128
|
+
weights : float or list[float] or np.ndarray, optional
|
|
114
129
|
Weight(s) to apply to the data points (default is 1).
|
|
115
130
|
If a float, a single weight is applied to all data points.
|
|
116
131
|
If an array-like, weights are applied element-wise.
|
|
117
132
|
|
|
118
133
|
Returns
|
|
119
134
|
-------
|
|
120
|
-
histogram :
|
|
135
|
+
histogram : bh.Histogram
|
|
121
136
|
The filled histogram object.
|
|
122
137
|
|
|
123
138
|
Warns
|
|
@@ -125,6 +140,8 @@ def make_hist(data=np.array([]), bins=50, range=None, weights=1):
|
|
|
125
140
|
RangeWarning
|
|
126
141
|
If more than 1% of the data is outside of the binning range.
|
|
127
142
|
"""
|
|
143
|
+
if data is None:
|
|
144
|
+
data = np.array([])
|
|
128
145
|
|
|
129
146
|
axis = create_axis(bins, range, data)
|
|
130
147
|
|
|
@@ -145,7 +162,7 @@ def make_hist(data=np.array([]), bins=50, range=None, weights=1):
|
|
|
145
162
|
# Issue a warning if more than 1% of the data is outside of the binning range
|
|
146
163
|
if range_coverage < 0.99:
|
|
147
164
|
warnings.warn(
|
|
148
|
-
f"Only {100*range_coverage:.2f}% of data contained in the binning range [{axis.edges[0]}, {axis.edges[-1]}].",
|
|
165
|
+
f"Only {100 * range_coverage:.2f}% of data contained in the binning range [{axis.edges[0]}, {axis.edges[-1]}].",
|
|
149
166
|
category=RangeWarning,
|
|
150
167
|
stacklevel=2,
|
|
151
168
|
)
|
|
@@ -153,31 +170,38 @@ def make_hist(data=np.array([]), bins=50, range=None, weights=1):
|
|
|
153
170
|
return h
|
|
154
171
|
|
|
155
172
|
|
|
156
|
-
def make_2d_hist(
|
|
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:
|
|
157
181
|
"""
|
|
158
182
|
Create a 2D histogram object and fill it with the provided data.
|
|
159
183
|
|
|
160
184
|
Parameters
|
|
161
185
|
----------
|
|
162
|
-
data :
|
|
163
|
-
2D array-like data used to fill the histogram (default is
|
|
164
|
-
If
|
|
165
|
-
bins :
|
|
166
|
-
Binning specification for each dimension of the histogram (
|
|
186
|
+
data : list[np.ndarray] or np.ndarray, optional
|
|
187
|
+
2D array-like data used to fill the histogram (default is None).
|
|
188
|
+
If None is provided, an empty histogram is returned.
|
|
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]).
|
|
167
191
|
Each element of the tuple represents the number of bins for the corresponding dimension.
|
|
168
192
|
Also support explicit bin edges specification (for non-constant bin size).
|
|
169
|
-
range : tuple, optional
|
|
193
|
+
range : tuple[tuple[float | str, float | str] | None, tuple[float | str, float | str] | None], optional
|
|
170
194
|
The range of values to consider for each dimension of the histogram (default is (None, None)).
|
|
171
195
|
If None, the range is determined from the data for that dimension.
|
|
172
196
|
The tuple should have the same length as the data.
|
|
173
|
-
weights : float or
|
|
197
|
+
weights : float or list[float] or np.ndarray, optional
|
|
174
198
|
Weight(s) to apply to the data points (default is 1).
|
|
175
199
|
If a float, a single weight is applied to all data points.
|
|
176
200
|
If an array-like, weights are applied element-wise.
|
|
177
201
|
|
|
178
202
|
Returns
|
|
179
203
|
-------
|
|
180
|
-
histogram :
|
|
204
|
+
histogram : bh.Histogram
|
|
181
205
|
The filled 2D histogram object.
|
|
182
206
|
|
|
183
207
|
Raises
|
|
@@ -190,10 +214,14 @@ def make_2d_hist(data=np.array([[], []]), bins=(10, 10), range=(None, None), wei
|
|
|
190
214
|
RangeWarning
|
|
191
215
|
If more than 1% of the data is outside of the binning range.
|
|
192
216
|
"""
|
|
217
|
+
if data is None:
|
|
218
|
+
data = np.array([[], []])
|
|
193
219
|
if len(data) != 2:
|
|
194
220
|
raise ValueError("data should have two components, x and y")
|
|
195
221
|
if len(data[0]) != len(data[1]):
|
|
196
222
|
raise ValueError("x and y must have the same length.")
|
|
223
|
+
if bins is None:
|
|
224
|
+
bins = [50, 50]
|
|
197
225
|
|
|
198
226
|
x_axis = create_axis(bins[0], range[0], data[0])
|
|
199
227
|
y_axis = create_axis(bins[1], range[1], data[1])
|
|
@@ -219,7 +247,7 @@ def make_2d_hist(data=np.array([[], []]), bins=(10, 10), range=(None, None), wei
|
|
|
219
247
|
# Issue a warning if more than 1% of the data is outside of the binning range
|
|
220
248
|
if range_coverage < 0.99:
|
|
221
249
|
warnings.warn(
|
|
222
|
-
f"Only {100*range_coverage:.2f}% of data contained in the binning range ([{x_axis.edges[0]}, {x_axis.edges[-1]}], [{y_axis.edges[0]}, {y_axis.edges[-1]}]).",
|
|
250
|
+
f"Only {100 * range_coverage:.2f}% of data contained in the binning range ([{x_axis.edges[0]}, {x_axis.edges[-1]}], [{y_axis.edges[0]}, {y_axis.edges[-1]}]).",
|
|
223
251
|
category=RangeWarning,
|
|
224
252
|
stacklevel=2,
|
|
225
253
|
)
|
|
@@ -227,13 +255,13 @@ def make_2d_hist(data=np.array([[], []]), bins=(10, 10), range=(None, None), wei
|
|
|
227
255
|
return h
|
|
228
256
|
|
|
229
257
|
|
|
230
|
-
def _check_counting_histogram(hist):
|
|
258
|
+
def _check_counting_histogram(hist: bh.Histogram) -> None:
|
|
231
259
|
"""
|
|
232
260
|
Check that the histogram is a counting histogram.
|
|
233
261
|
|
|
234
262
|
Parameters
|
|
235
263
|
----------
|
|
236
|
-
hist :
|
|
264
|
+
hist : bh.Histogram
|
|
237
265
|
The histogram to check.
|
|
238
266
|
|
|
239
267
|
Raise
|
|
@@ -246,10 +274,11 @@ def _check_counting_histogram(hist):
|
|
|
246
274
|
raise ValueError(
|
|
247
275
|
f"The histogram must be a counting histogram, but the input histogram has kind {hist.kind}."
|
|
248
276
|
)
|
|
249
|
-
return
|
|
250
277
|
|
|
251
278
|
|
|
252
|
-
def _make_hist_from_function(
|
|
279
|
+
def _make_hist_from_function(
|
|
280
|
+
func: Callable[[np.ndarray], np.ndarray], ref_hist: bh.Histogram
|
|
281
|
+
) -> bh.Histogram:
|
|
253
282
|
"""
|
|
254
283
|
Create a histogram from a function and a reference histogram.
|
|
255
284
|
The returned histogram has the same binning as the reference histogram and
|
|
@@ -257,14 +286,14 @@ def _make_hist_from_function(func, ref_hist):
|
|
|
257
286
|
|
|
258
287
|
Parameters
|
|
259
288
|
----------
|
|
260
|
-
func :
|
|
289
|
+
func : Callable[[np.ndarray], np.ndarray]
|
|
261
290
|
1D function. The function should support vectorization (i.e. accept a numpy array as input).
|
|
262
|
-
ref_hist :
|
|
291
|
+
ref_hist : bh.Histogram
|
|
263
292
|
The reference 1D histogram to use for the binning.
|
|
264
293
|
|
|
265
294
|
Returns
|
|
266
295
|
-------
|
|
267
|
-
hist :
|
|
296
|
+
hist : bh.Histogram
|
|
268
297
|
The histogram filled with the function.
|
|
269
298
|
|
|
270
299
|
Raises
|
|
@@ -282,18 +311,18 @@ def _make_hist_from_function(func, ref_hist):
|
|
|
282
311
|
return hist
|
|
283
312
|
|
|
284
313
|
|
|
285
|
-
def flatten_2d_hist(hist):
|
|
314
|
+
def flatten_2d_hist(hist: bh.Histogram) -> bh.Histogram:
|
|
286
315
|
"""
|
|
287
316
|
Flatten a 2D histogram into a 1D histogram.
|
|
288
317
|
|
|
289
318
|
Parameters
|
|
290
319
|
----------
|
|
291
|
-
hist : Histogram
|
|
320
|
+
hist : bh.Histogram
|
|
292
321
|
The 2D histogram to be flattened.
|
|
293
322
|
|
|
294
323
|
Returns
|
|
295
324
|
-------
|
|
296
|
-
Histogram
|
|
325
|
+
bh.Histogram
|
|
297
326
|
The flattened 1D histogram.
|
|
298
327
|
|
|
299
328
|
Raises
|