plothist 1.4.0__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/_version.py +2 -2
- plothist/comparison.py +111 -105
- 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 +60 -39
- plothist/plothist_style.py +54 -57
- plothist/plotters.py +207 -194
- plothist/test_helpers.py +43 -0
- plothist/variable_registry.py +46 -30
- {plothist-1.4.0.dist-info → plothist-1.5.0.dist-info}/METADATA +1 -1
- plothist-1.5.0.dist-info/RECORD +63 -0
- plothist/scripts/__init__.py +0 -3
- plothist/scripts/make_examples.py +0 -209
- plothist-1.4.0.dist-info/RECORD +0 -17
- plothist-1.4.0.dist-info/entry_points.txt +0 -2
- {plothist-1.4.0.dist-info → plothist-1.5.0.dist-info}/WHEEL +0 -0
- {plothist-1.4.0.dist-info → plothist-1.5.0.dist-info}/licenses/AUTHORS.md +0 -0
- {plothist-1.4.0.dist-info → plothist-1.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -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,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(
|
|
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
|
|
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 :
|
|
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
|
-
|
|
56
|
-
N = len(bins)
|
|
57
|
-
except TypeError:
|
|
58
|
-
N = 1
|
|
63
|
+
is_variable_bins = isinstance(bins, (list, np.ndarray))
|
|
59
64
|
|
|
60
|
-
if
|
|
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(
|
|
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 :
|
|
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
|
|
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
|
|
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
|
|
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 :
|
|
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(
|
|
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 :
|
|
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 :
|
|
173
|
-
Binning specification for each dimension of the histogram (
|
|
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
|
|
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 :
|
|
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 :
|
|
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(
|
|
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 :
|
|
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 :
|
|
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 :
|
|
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
|
|
320
|
+
hist : bh.Histogram
|
|
300
321
|
The 2D histogram to be flattened.
|
|
301
322
|
|
|
302
323
|
Returns
|
|
303
324
|
-------
|
|
304
|
-
Histogram
|
|
325
|
+
bh.Histogram
|
|
305
326
|
The flattened 1D histogram.
|
|
306
327
|
|
|
307
328
|
Raises
|
plothist/plothist_style.py
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from importlib.resources import files
|
|
4
|
-
|
|
5
3
|
import matplotlib as mpl
|
|
6
4
|
import matplotlib.pyplot as plt
|
|
7
5
|
import numpy as np
|
|
8
6
|
|
|
9
7
|
|
|
10
|
-
def set_style(style="default"):
|
|
8
|
+
def set_style(style: str = "default") -> None:
|
|
11
9
|
"""
|
|
12
10
|
Set the plothist style.
|
|
13
11
|
|
|
@@ -32,22 +30,21 @@ def set_style(style="default"):
|
|
|
32
30
|
available_styles = ["default"]
|
|
33
31
|
|
|
34
32
|
if style in available_styles:
|
|
35
|
-
|
|
36
|
-
plt.style.use(style_file)
|
|
33
|
+
plt.style.use(f"plothist.{style}_style")
|
|
37
34
|
else:
|
|
38
35
|
raise ValueError(f"{style} not in the available styles: {available_styles}")
|
|
39
36
|
|
|
40
37
|
|
|
41
38
|
def cubehelix_palette(
|
|
42
|
-
ncolors=7,
|
|
43
|
-
start=1.5,
|
|
44
|
-
rotation=1.5,
|
|
45
|
-
gamma=1.0,
|
|
46
|
-
hue=0.8,
|
|
47
|
-
lightest=0.8,
|
|
48
|
-
darkest=0.3,
|
|
49
|
-
reverse=True,
|
|
50
|
-
):
|
|
39
|
+
ncolors: int = 7,
|
|
40
|
+
start: float = 1.5,
|
|
41
|
+
rotation: float = 1.5,
|
|
42
|
+
gamma: float = 1.0,
|
|
43
|
+
hue: float = 0.8,
|
|
44
|
+
lightest: float = 0.8,
|
|
45
|
+
darkest: float = 0.3,
|
|
46
|
+
reverse: bool = True,
|
|
47
|
+
) -> list[tuple[float, float, float]]:
|
|
51
48
|
"""
|
|
52
49
|
Make a sequential palette from the cubehelix system, in which the perceived brightness is linearly increasing.
|
|
53
50
|
This code is adapted from seaborn, which implements equation (2) of reference [1] below.
|
|
@@ -75,10 +72,9 @@ def cubehelix_palette(
|
|
|
75
72
|
|
|
76
73
|
Returns
|
|
77
74
|
-------
|
|
78
|
-
list
|
|
75
|
+
list[tuple[float, float, float]]
|
|
79
76
|
The generated palette of colors represented as a list of RGB tuples.
|
|
80
77
|
|
|
81
|
-
|
|
82
78
|
References
|
|
83
79
|
----------
|
|
84
80
|
[1] Green, D. A. (2011). "A colour scheme for the display of astronomical
|
|
@@ -119,7 +115,9 @@ def cubehelix_palette(
|
|
|
119
115
|
return pal
|
|
120
116
|
|
|
121
117
|
|
|
122
|
-
def get_color_palette(
|
|
118
|
+
def get_color_palette(
|
|
119
|
+
cmap: str, N: int
|
|
120
|
+
) -> list[str] | list[tuple[float, float, float]]:
|
|
123
121
|
"""
|
|
124
122
|
Get N different colors from a chosen colormap.
|
|
125
123
|
|
|
@@ -132,8 +130,9 @@ def get_color_palette(cmap, N):
|
|
|
132
130
|
|
|
133
131
|
Returns
|
|
134
132
|
-------
|
|
135
|
-
list
|
|
136
|
-
A list of
|
|
133
|
+
list[str] or list[tuple[float, float, float]]
|
|
134
|
+
A list of colors. If "ggplot" is selected, returns a list of hex color strings.
|
|
135
|
+
Otherwise, returns a list of RGB color tuples.
|
|
137
136
|
|
|
138
137
|
References
|
|
139
138
|
----------
|
|
@@ -174,7 +173,7 @@ def get_color_palette(cmap, N):
|
|
|
174
173
|
return plt_cmap(np.linspace(0, 1, N))
|
|
175
174
|
|
|
176
175
|
|
|
177
|
-
def set_fitting_ylabel_fontsize(ax):
|
|
176
|
+
def set_fitting_ylabel_fontsize(ax: plt.Axes) -> float:
|
|
178
177
|
"""
|
|
179
178
|
Get the suitable font size for a ylabel text that fits within the plot's y-axis limits.
|
|
180
179
|
|
|
@@ -190,9 +189,8 @@ def set_fitting_ylabel_fontsize(ax):
|
|
|
190
189
|
"""
|
|
191
190
|
ylabel_fontsize = ax.yaxis.get_label().get_fontsize()
|
|
192
191
|
|
|
193
|
-
#
|
|
194
|
-
|
|
195
|
-
ax.figure.canvas.draw()
|
|
192
|
+
# Force renderer to be initialized
|
|
193
|
+
ax.figure.canvas.draw()
|
|
196
194
|
|
|
197
195
|
while (
|
|
198
196
|
ax.yaxis.get_label()
|
|
@@ -214,14 +212,14 @@ def set_fitting_ylabel_fontsize(ax):
|
|
|
214
212
|
|
|
215
213
|
|
|
216
214
|
def add_text(
|
|
217
|
-
text,
|
|
218
|
-
x="left",
|
|
219
|
-
y="top",
|
|
220
|
-
fontsize=12,
|
|
221
|
-
white_background=False,
|
|
222
|
-
ax=None,
|
|
215
|
+
text: str,
|
|
216
|
+
x: float | str = "left",
|
|
217
|
+
y: float | str = "top",
|
|
218
|
+
fontsize: int = 12,
|
|
219
|
+
white_background: bool = False,
|
|
220
|
+
ax: plt.Axes | None = None,
|
|
223
221
|
**kwargs,
|
|
224
|
-
):
|
|
222
|
+
) -> None:
|
|
225
223
|
"""
|
|
226
224
|
Add text to an axis.
|
|
227
225
|
|
|
@@ -229,9 +227,9 @@ def add_text(
|
|
|
229
227
|
----------
|
|
230
228
|
text : str
|
|
231
229
|
The text to add.
|
|
232
|
-
x : float, optional
|
|
230
|
+
x : float | str, optional
|
|
233
231
|
Horizontal position of the text in unit of the normalized x-axis length. The default is value "left", which is an alias for 0.0. Other aliases are "right", "left_in", "right_in", "right_out".
|
|
234
|
-
y : float, optional
|
|
232
|
+
y : float | str, optional
|
|
235
233
|
Vertical position of the text in unit of the normalized y-axis length. The default is value "top", which is an alias for 1.01. Other aliases are "top_in", "bottom_in", "top_out"="top", "bottom_out"="bottom".
|
|
236
234
|
fontsize : int, optional
|
|
237
235
|
Font size, by default 12.
|
|
@@ -279,14 +277,14 @@ def add_text(
|
|
|
279
277
|
}
|
|
280
278
|
|
|
281
279
|
if isinstance(x, str):
|
|
282
|
-
x
|
|
283
|
-
|
|
284
|
-
|
|
280
|
+
if x not in x_values:
|
|
281
|
+
raise ValueError(f"{x!r} is not a valid x position.")
|
|
282
|
+
x = x_values[x]
|
|
285
283
|
|
|
286
284
|
if isinstance(y, str):
|
|
287
|
-
y
|
|
288
|
-
|
|
289
|
-
|
|
285
|
+
if y not in y_values:
|
|
286
|
+
raise ValueError(f"{y!r} is not a valid y position.")
|
|
287
|
+
y = y_values[y]
|
|
290
288
|
|
|
291
289
|
t = ax.text(
|
|
292
290
|
x,
|
|
@@ -303,19 +301,19 @@ def add_text(
|
|
|
303
301
|
|
|
304
302
|
|
|
305
303
|
def add_luminosity(
|
|
306
|
-
collaboration,
|
|
307
|
-
x="right",
|
|
308
|
-
y="top",
|
|
309
|
-
fontsize=12,
|
|
310
|
-
is_data=True,
|
|
311
|
-
lumi="",
|
|
312
|
-
lumi_unit="fb",
|
|
313
|
-
preliminary=False,
|
|
314
|
-
two_lines=False,
|
|
315
|
-
white_background=False,
|
|
316
|
-
ax=None,
|
|
304
|
+
collaboration: str,
|
|
305
|
+
x: float | str = "right",
|
|
306
|
+
y: float | str = "top",
|
|
307
|
+
fontsize: int = 12,
|
|
308
|
+
is_data: bool = True,
|
|
309
|
+
lumi: int | str = "",
|
|
310
|
+
lumi_unit: str = "fb",
|
|
311
|
+
preliminary: bool = False,
|
|
312
|
+
two_lines: bool = False,
|
|
313
|
+
white_background: bool = False,
|
|
314
|
+
ax: plt.Axes | None = None,
|
|
317
315
|
**kwargs,
|
|
318
|
-
):
|
|
316
|
+
) -> None:
|
|
319
317
|
"""
|
|
320
318
|
Add the collaboration name and the integrated luminosity (or "Simulation").
|
|
321
319
|
|
|
@@ -323,17 +321,17 @@ def add_luminosity(
|
|
|
323
321
|
----------
|
|
324
322
|
collaboration : str
|
|
325
323
|
Collaboration name.
|
|
326
|
-
x : float, optional
|
|
324
|
+
x : float | str, optional
|
|
327
325
|
Horizontal position of the text in unit of the normalized x-axis length. The default is value "right", which is an alias for 1.0. Can take other aliases such as "left", "left_in", "right_in", "right_out".
|
|
328
|
-
y : float, optional
|
|
326
|
+
y : float | str, optional
|
|
329
327
|
Vertical position of the text in unit of the normalized y-axis length. The default is value "top", which is an alias for 1.01. Can take other aliases such as "top_in", "bottom_in", "top_out"="top", "bottom_out"="bottom".
|
|
330
328
|
fontsize : int, optional
|
|
331
329
|
Font size, by default 12.
|
|
332
330
|
is_data : bool, optional
|
|
333
331
|
If True, plot integrated luminosity. If False, plot "Simulation", by default True.
|
|
334
|
-
lumi : int
|
|
332
|
+
lumi : int | str, optional
|
|
335
333
|
Integrated luminosity. If empty, do not plot luminosity. Default value is empty.
|
|
336
|
-
lumi_unit :
|
|
334
|
+
lumi_unit : str, optional
|
|
337
335
|
Integrated luminosity unit. Default value is fb. The exponent is automatically -1.
|
|
338
336
|
preliminary : bool, optional
|
|
339
337
|
If True, print "preliminary", by default False.
|
|
@@ -383,7 +381,7 @@ def add_luminosity(
|
|
|
383
381
|
)
|
|
384
382
|
|
|
385
383
|
|
|
386
|
-
def plot_reordered_legend(ax, order, **kwargs):
|
|
384
|
+
def plot_reordered_legend(ax: plt.Axes, order: list[int], **kwargs) -> None:
|
|
387
385
|
"""
|
|
388
386
|
Reorder the legend handlers and labels on the given Matplotlib axis based
|
|
389
387
|
on the specified order and plot the reordered legend.
|
|
@@ -392,7 +390,7 @@ def plot_reordered_legend(ax, order, **kwargs):
|
|
|
392
390
|
----------
|
|
393
391
|
ax : matplotlib.axes.Axes
|
|
394
392
|
The Matplotlib Axes object on which the legend is to be reordered.
|
|
395
|
-
order : list
|
|
393
|
+
order : list[int]
|
|
396
394
|
A list of integers specifying the new order of the legend items.
|
|
397
395
|
The integers refer to the indices of the current legend items.
|
|
398
396
|
kwargs : dict, optional
|
|
@@ -418,7 +416,6 @@ def plot_reordered_legend(ax, order, **kwargs):
|
|
|
418
416
|
To reorder the legend so that 'Line 2' comes first, use:
|
|
419
417
|
|
|
420
418
|
>>> plot_reordered_legend(ax, [1, 0])
|
|
421
|
-
|
|
422
419
|
"""
|
|
423
420
|
|
|
424
421
|
# Extract the original handlers and labels
|