plothist 1.6.0__py3-none-any.whl → 1.8.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 CHANGED
@@ -9,12 +9,7 @@ from .comparison import (
9
9
  get_ratio,
10
10
  get_ratio_variances,
11
11
  )
12
- from .histogramming import (
13
- create_axis,
14
- flatten_2d_hist,
15
- make_2d_hist,
16
- make_hist,
17
- )
12
+ from .histogramming import create_axis, flatten_2d_hist, make_2d_hist, make_hist
18
13
  from .plothist_style import (
19
14
  add_luminosity,
20
15
  add_text,
@@ -43,6 +38,7 @@ from .variable_registry import (
43
38
  get_variable_from_registry,
44
39
  remove_variable_registry_parameters,
45
40
  update_variable_registry,
41
+ update_variable_registry_binning,
46
42
  update_variable_registry_ranges,
47
43
  )
48
44
 
@@ -81,6 +77,7 @@ __all__ = [
81
77
  "set_fitting_ylabel_fontsize",
82
78
  "set_style",
83
79
  "update_variable_registry",
80
+ "update_variable_registry_binning",
84
81
  "update_variable_registry_ranges",
85
82
  ]
86
83
 
plothist/_version.py CHANGED
@@ -1,7 +1,14 @@
1
1
  # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
3
 
4
- __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
5
12
 
6
13
  TYPE_CHECKING = False
7
14
  if TYPE_CHECKING:
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
9
16
  from typing import Union
10
17
 
11
18
  VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
12
20
  else:
13
21
  VERSION_TUPLE = object
22
+ COMMIT_ID = object
14
23
 
15
24
  version: str
16
25
  __version__: str
17
26
  __version_tuple__: VERSION_TUPLE
18
27
  version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
19
30
 
20
- __version__ = version = '1.6.0'
21
- __version_tuple__ = version_tuple = (1, 6, 0)
31
+ __version__ = version = '1.8.0'
32
+ __version_tuple__ = version_tuple = (1, 8, 0)
33
+
34
+ __commit_id__ = commit_id = None
plothist/comparison.py CHANGED
@@ -49,7 +49,7 @@ def _is_unweighted(hist: bh.Histogram) -> bool:
49
49
  bool
50
50
  True if the histogram is unweighted, False otherwise.
51
51
  """
52
- return np.allclose(hist.variances(), hist.values(), equal_nan=True)
52
+ return bool(np.allclose(hist.variances(), hist.values(), equal_nan=True))
53
53
 
54
54
 
55
55
  def get_asymmetrical_uncertainties(
@@ -20,7 +20,7 @@ from plothist import (
20
20
  get_variable_from_registry,
21
21
  make_2d_hist,
22
22
  plot_2d_hist,
23
- update_variable_registry_ranges,
23
+ update_variable_registry_binning,
24
24
  )
25
25
 
26
26
  # No need to redo this step if the registry was already created before
@@ -28,7 +28,7 @@ variable_keys = ["variable_0", "variable_1", "variable_2"]
28
28
  unique_id = str(int(time.time() * 1000))[-8:] # unique ID based on current time
29
29
  temporary_registry_path = f"./_temporary_variable_registry_{unique_id}.yaml"
30
30
  create_variable_registry(variable_keys, path=temporary_registry_path)
31
- update_variable_registry_ranges(df, variable_keys, path=temporary_registry_path)
31
+ update_variable_registry_binning(df, variable_keys, path=temporary_registry_path)
32
32
 
33
33
  # Get all the correlation plot between the variables
34
34
  variable_keys_combinations = list(combinations(variable_keys, 2))
@@ -42,7 +42,7 @@ plot_hist(histos, ax=ax, label=labels, color=colors)
42
42
 
43
43
  # Add the number of entries on top of each bar
44
44
  # Get the correct shift in x-axis for each bar
45
- def calculate_shifts(width, n_bars):
45
+ def calculate_shifts(width: float, n_bars: int) -> np.ndarray:
46
46
  half_width = width / 2
47
47
  shift = np.linspace(-half_width, half_width, n_bars, endpoint=False)
48
48
  shift += width / (2 * n_bars)
@@ -11,6 +11,7 @@ from plothist_utils import get_dummy_data
11
11
  df = get_dummy_data()
12
12
 
13
13
  ###
14
+ import numpy as np
14
15
  from scipy.stats import norm
15
16
 
16
17
  from plothist import (
@@ -25,11 +26,11 @@ from plothist import (
25
26
 
26
27
 
27
28
  # Define some random functions that will be used as Data fit functions
28
- def f1(x):
29
+ def f1(x: np.ndarray) -> np.ndarray:
29
30
  return 4000 * norm.pdf(x, loc=-0.5, scale=1.6)
30
31
 
31
32
 
32
- def f2(x):
33
+ def f2(x: np.ndarray) -> np.ndarray:
33
34
  return 4000 * norm.pdf(x, loc=0.5, scale=1.6)
34
35
 
35
36
 
@@ -13,16 +13,21 @@ from matplotlib import patches
13
13
  from plothist import get_color_palette
14
14
 
15
15
 
16
- def create_palette_plot(colors, fig_name, add_text=False, add_black_border=False):
16
+ def create_palette_plot(
17
+ colors: list[str] | list[tuple[float, float, float]],
18
+ fig_name: str,
19
+ add_text: bool = False,
20
+ add_black_border: bool = False,
21
+ ):
17
22
  ncolors = len(colors)
18
23
 
19
24
  # Create a figure and axis
20
25
  fig, ax = plt.subplots(figsize=(ncolors, 1))
21
26
 
22
27
  # Plot the colored squares with small spacing
23
- square_size = 1
28
+ square_size = 1.0
24
29
  spacing = 0.1
25
- x = 0
30
+ x = 0.0
26
31
 
27
32
  for color in colors:
28
33
  rect = patches.Rectangle((x, 0), square_size, square_size, color=color)
plothist/histogramming.py CHANGED
@@ -1,8 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import warnings
4
- from collections.abc import Sequence
5
- from typing import Callable
4
+ from collections.abc import Callable, Sequence
6
5
 
7
6
  import boost_histogram as bh
8
7
  import numpy as np
@@ -109,6 +108,7 @@ def make_hist(
109
108
  bins: int | list[float] | np.ndarray = 50,
110
109
  range: tuple[float | str, float | str] | None = None,
111
110
  weights: float | list[float] | np.ndarray = 1,
111
+ mute_warning: bool = False,
112
112
  ) -> bh.Histogram:
113
113
  """
114
114
  Create a histogram object and fill it with the provided data.
@@ -129,6 +129,8 @@ def make_hist(
129
129
  Weight(s) to apply to the data points (default is 1).
130
130
  If a float, a single weight is applied to all data points.
131
131
  If an array-like, weights are applied element-wise.
132
+ mute_warning : bool, optional
133
+ Whether to mute warnings about data outside the binning range (default is False).
132
134
 
133
135
  Returns
134
136
  -------
@@ -160,7 +162,7 @@ def make_hist(
160
162
  range_coverage = h.sum().value / n_data
161
163
 
162
164
  # Issue a warning if more than 1% of the data is outside of the binning range
163
- if range_coverage < 0.99:
165
+ if range_coverage < 0.99 and not mute_warning:
164
166
  warnings.warn(
165
167
  f"Only {100 * range_coverage:.2f}% of data contained in the binning range [{axis.edges[0]}, {axis.edges[-1]}].",
166
168
  category=RangeWarning,
@@ -177,6 +179,7 @@ def make_2d_hist(
177
179
  tuple[float | str, float | str] | None, tuple[float | str, float | str] | None
178
180
  ] = (None, None),
179
181
  weights: float | list[float] | np.ndarray = 1,
182
+ mute_warning: bool = False,
180
183
  ) -> bh.Histogram:
181
184
  """
182
185
  Create a 2D histogram object and fill it with the provided data.
@@ -198,6 +201,8 @@ def make_2d_hist(
198
201
  Weight(s) to apply to the data points (default is 1).
199
202
  If a float, a single weight is applied to all data points.
200
203
  If an array-like, weights are applied element-wise.
204
+ mute_warning : bool, optional
205
+ Whether to mute warnings about data outside the binning range (default is False).
201
206
 
202
207
  Returns
203
208
  -------
@@ -245,7 +250,7 @@ def make_2d_hist(
245
250
  range_coverage = h.sum().value / n_data
246
251
 
247
252
  # Issue a warning if more than 1% of the data is outside of the binning range
248
- if range_coverage < 0.99:
253
+ if range_coverage < 0.99 and not mute_warning:
249
254
  warnings.warn(
250
255
  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]}]).",
251
256
  category=RangeWarning,
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from collections.abc import Callable
4
+
3
5
  import matplotlib as mpl
4
6
  import matplotlib.pyplot as plt
5
7
  import numpy as np
@@ -82,9 +84,9 @@ def cubehelix_palette(
82
84
  p. 289-295.
83
85
  """
84
86
 
85
- def f(x0, x1):
87
+ def f(x0: float, x1: float) -> Callable[[float], np.ndarray]:
86
88
  # Adapted from matplotlib
87
- def color(lambda_):
89
+ def color(lambda_: float) -> np.ndarray:
88
90
  # emphasise either low intensity values (gamma < 1),
89
91
  # or high intensity values (gamma > 1)
90
92
  lambda_gamma = lambda_**gamma
@@ -187,27 +189,36 @@ def set_fitting_ylabel_fontsize(ax: plt.Axes) -> float:
187
189
  float
188
190
  The adjusted font size for the ylabel text.
189
191
  """
190
- ylabel_fontsize = ax.yaxis.get_label().get_fontsize()
192
+ ylabel_fontsize = float(ax.yaxis.get_label().get_fontsize())
191
193
 
192
194
  # Force renderer to be initialized
193
195
  ax.figure.canvas.draw()
194
196
 
195
- while (
197
+ current_extent = (
196
198
  ax.yaxis.get_label()
197
199
  .get_window_extent(renderer=ax.figure.canvas.get_renderer())
198
200
  .transformed(ax.transData.inverted())
199
- .y1
200
- > ax.get_ylim()[1]
201
- ):
201
+ )
202
+
203
+ y_alignment = plt.rcParams["yaxis.labellocation"]
204
+
205
+ while (
206
+ y_alignment in ["center", "bottom"] and current_extent.y1 > ax.get_ylim()[1]
207
+ ) or (y_alignment == "top" and current_extent.y0 < ax.get_ylim()[0]):
202
208
  ylabel_fontsize -= 0.1
203
209
 
204
210
  if ylabel_fontsize <= 0:
205
- raise ValueError(
206
- "Only a y-label with a negative font size would fit on the y-axis."
207
- )
211
+ msg = "Only a y-label with a negative font size would fit on the y-axis."
212
+ raise ValueError(msg)
208
213
 
209
214
  ax.get_yaxis().get_label().set_size(ylabel_fontsize)
210
215
 
216
+ current_extent = (
217
+ ax.yaxis.get_label()
218
+ .get_window_extent(renderer=ax.figure.canvas.get_renderer())
219
+ .transformed(ax.transData.inverted())
220
+ )
221
+
211
222
  return ylabel_fontsize
212
223
 
213
224
 
@@ -237,7 +248,7 @@ def add_text(
237
248
  Draw a white rectangle under the text, by default False.
238
249
  ax : matplotlib.axes.Axes, optional
239
250
  Figure axis, by default None.
240
- kwargs : dict
251
+ kwargs : dict[str, Any]
241
252
  Keyword arguments to be passed to the ax.text() function.
242
253
  In particular, the keyword arguments ha and va, which are set by default to accommodate to the x and y aliases, can be used to change the text alignment.
243
254
 
@@ -341,7 +352,7 @@ def add_luminosity(
341
352
  Draw a white rectangle under the text, by default False.
342
353
  ax : matplotlib.axes.Axes, optional
343
354
  Figure axis, by default None.
344
- kwargs : dict
355
+ kwargs : dict[str, Any]
345
356
  Keyword arguments to be passed to the ax.text() function.
346
357
  In particular, the keyword arguments ha and va, which are set to "left" (or "right" if x="right") and "bottom" by default, can be used to change the text alignment.
347
358
 
@@ -393,7 +404,7 @@ def plot_reordered_legend(ax: plt.Axes, order: list[int], **kwargs) -> None:
393
404
  order : list[int]
394
405
  A list of integers specifying the new order of the legend items.
395
406
  The integers refer to the indices of the current legend items.
396
- kwargs : dict, optional
407
+ kwargs : dict[str, Any], optional
397
408
  Keyword arguments to be passed to the ax.legend() function, such as the legend location (loc).
398
409
 
399
410
  Returns
plothist/plotters.py CHANGED
@@ -5,7 +5,8 @@ Collection of functions to plot histograms
5
5
  from __future__ import annotations
6
6
 
7
7
  import re
8
- from typing import Callable
8
+ from collections.abc import Callable
9
+ from typing import Any
9
10
 
10
11
  import boost_histogram as bh
11
12
  import matplotlib.pyplot as plt
@@ -23,9 +24,9 @@ from plothist.plothist_style import set_fitting_ylabel_fontsize
23
24
 
24
25
 
25
26
  def create_comparison_figure(
26
- figsize: tuple[float, float] = (6, 5),
27
+ figsize: tuple[float, float] | None = (6, 5),
27
28
  nrows: int = 2,
28
- gridspec_kw: dict | None = None,
29
+ gridspec_kw: dict[str, Any] | None = None,
29
30
  hspace: float = 0.15,
30
31
  ) -> tuple[plt.Figure, np.ndarray]:
31
32
  """
@@ -35,9 +36,10 @@ def create_comparison_figure(
35
36
  ----------
36
37
  figsize : tuple[float, float], optional
37
38
  Figure size in inches. Default is (6, 5).
39
+ If None is provided, the default matplotlib figure size from rcParams["figure.figsize"] is used.
38
40
  nrows : int, optional
39
41
  Number of rows in the subplot grid. Default is 2.
40
- gridspec_kw : dict | None, optional
42
+ gridspec_kw : dict[str, Any] | None, optional
41
43
  Additional keyword arguments for the GridSpec. Default is None.
42
44
  If None is provided, this is set to {"height_ratios": [4, 1]}.
43
45
  hspace : float, optional
@@ -104,8 +106,8 @@ def plot_2d_hist(
104
106
  fig: plt.Figure | None = None,
105
107
  ax: plt.Axes | None = None,
106
108
  ax_colorbar: plt.Axes | None = None,
107
- pcolormesh_kwargs: dict | None = None,
108
- colorbar_kwargs: dict | None = None,
109
+ pcolormesh_kwargs: dict[str, Any] | None = None,
110
+ colorbar_kwargs: dict[str, Any] | None = None,
109
111
  square_ax: bool = True,
110
112
  ) -> tuple[plt.Figure, plt.Axes, plt.Axes]:
111
113
  """
@@ -121,9 +123,9 @@ def plot_2d_hist(
121
123
  The Axes instance for plotting. If fig, ax and ax_colorbar are all None, a new figure will be created. Default is None.
122
124
  ax_colorbar : matplotlib.axes.Axes | None, optional
123
125
  The Axes instance for the colorbar. If fig, ax and ax_colorbar are all None, a new figure will be created. Default is None.
124
- pcolormesh_kwargs : dict | None, optional
126
+ pcolormesh_kwargs : dict[str, Any] | None, optional
125
127
  Additional keyword arguments forwarded to ax.pcolormesh(). Default is None.
126
- colorbar_kwargs : dict | None, optional
128
+ colorbar_kwargs : dict[str, Any] | None, optional
127
129
  Additional keyword arguments forwarded to ax.get_figure().colorbar(). Default is None.
128
130
  square_ax : bool, optional
129
131
  Whether to make the main ax square. Default is True.
@@ -242,9 +244,9 @@ def plot_2d_hist_with_projections(
242
244
  xlabel_y_projection: str | None = None,
243
245
  colorbar_label: str | None = None,
244
246
  offset_x_labels: bool = False,
245
- pcolormesh_kwargs: dict | None = None,
246
- colorbar_kwargs: dict | None = None,
247
- plot_hist_kwargs: dict | None = None,
247
+ pcolormesh_kwargs: dict[str, Any] | None = None,
248
+ colorbar_kwargs: dict[str, Any] | None = None,
249
+ plot_hist_kwargs: dict[str, Any] | None = None,
248
250
  figsize: tuple[float, float] = (6, 6),
249
251
  ) -> tuple[plt.Figure, plt.Axes, plt.Axes, plt.Axes, plt.Axes]:
250
252
  """
@@ -266,11 +268,11 @@ def plot_2d_hist_with_projections(
266
268
  Label for the colorbar. Default is None.
267
269
  offset_x_labels : bool, optional
268
270
  Whether to offset the x labels to avoid overlapping with the exponent label (i.e. "10^X") of the axis. Default is False.
269
- pcolormesh_kwargs : dict | None, optional
271
+ pcolormesh_kwargs : dict[str, Any] | None, optional
270
272
  Keyword arguments for the pcolormesh call. Default is None.
271
- colorbar_kwargs : dict | None, optional
273
+ colorbar_kwargs : dict[str, Any] | None, optional
272
274
  Keyword arguments for the colorbar call. Default is None.
273
- plot_hist_kwargs : dict | None, optional
275
+ plot_hist_kwargs : dict[str, Any] | None, optional
274
276
  Keyword arguments for the plot_hist call (x and y projections). Default is None.
275
277
  figsize : tuple[float, float], optional
276
278
  Figure size in inches. Default is (6, 6). To get square bins if the figure is not square shaped, be sure to set the bins and the ranges of the histogram according to the ratio of the figure width and height.
@@ -767,7 +769,7 @@ def _get_math_text(text: str) -> str:
767
769
  return text
768
770
 
769
771
 
770
- def _get_model_type(components: list) -> str:
772
+ def _get_model_type(components: list[bh.Histogram | Callable[[Any], Any]]) -> str:
771
773
  """
772
774
  Check that all components of a model are either all histograms or all functions
773
775
  and return the type of the model components.
@@ -805,9 +807,9 @@ def plot_model(
805
807
  ) = None,
806
808
  xlabel: str | None = None,
807
809
  ylabel: str | None = None,
808
- stacked_kwargs: dict | None = None,
809
- unstacked_kwargs_list: list[dict] | None = None,
810
- model_sum_kwargs: dict | None = None,
810
+ stacked_kwargs: dict[str, Any] | None = None,
811
+ unstacked_kwargs_list: list[dict[str, Any]] | None = None,
812
+ model_sum_kwargs: dict[str, Any] | None = None,
811
813
  function_range: tuple[float, float] | None = None,
812
814
  model_uncertainty: bool = True,
813
815
  model_uncertainty_label: str = "Model stat. unc.",
@@ -835,11 +837,11 @@ def plot_model(
835
837
  The label for the x-axis. Default is None.
836
838
  ylabel : str | None, optional
837
839
  The label for the y-axis. Default is None.
838
- stacked_kwargs : dict | None, optional
840
+ stacked_kwargs : dict[str, Any] | None, optional
839
841
  The keyword arguments used when plotting the stacked components in plot_hist() or plot_function(), one of which is called only once. Default is None.
840
- unstacked_kwargs_list : list[dict] | None, optional
842
+ unstacked_kwargs_list : list[dict[str, Any]] | None, optional
841
843
  The list of keyword arguments used when plotting the unstacked components in plot_hist() or plot_function(), one of which is called once for each unstacked component. Default is None.
842
- model_sum_kwargs : dict | None, optional
844
+ model_sum_kwargs : dict[str, Any] | None, optional
843
845
  The keyword arguments for the plot_hist() function for the sum of the model components.
844
846
  Has no effect if all the model components are stacked or if the model is one unstacked element.
845
847
  The special keyword "show" can be used with a boolean to specify whether to show or not the sum of the model components.
@@ -947,6 +949,7 @@ def plot_model(
947
949
  unstacked_colors,
948
950
  unstacked_labels,
949
951
  unstacked_kwargs_list,
952
+ strict=True,
950
953
  ):
951
954
  if model_type == "histograms":
952
955
  unstacked_kwargs.setdefault("histtype", "step")
@@ -1024,9 +1027,9 @@ def plot_data_model_comparison(
1024
1027
  xlabel: str | None = None,
1025
1028
  ylabel: str | None = None,
1026
1029
  data_label: str = "Data",
1027
- stacked_kwargs: dict | None = None,
1028
- unstacked_kwargs_list: list[dict] | None = None,
1029
- model_sum_kwargs: dict | None = None,
1030
+ stacked_kwargs: dict[str, Any] | None = None,
1031
+ unstacked_kwargs_list: list[dict[str, Any]] | None = None,
1032
+ model_sum_kwargs: dict[str, Any] | None = None,
1030
1033
  model_uncertainty: bool = True,
1031
1034
  model_uncertainty_label: str = "Model stat. unc.",
1032
1035
  data_uncertainty_type: str = "asymmetrical",
@@ -1061,11 +1064,11 @@ def plot_data_model_comparison(
1061
1064
  The label for the y-axis. Default is None.
1062
1065
  data_label : str, optional
1063
1066
  The label for the data. Default is "Data".
1064
- stacked_kwargs : dict | None, optional
1067
+ stacked_kwargs : dict[str, Any] | None, optional
1065
1068
  The keyword arguments used when plotting the stacked components in plot_hist() or plot_function(), one of which is called only once. Default is None.
1066
- unstacked_kwargs_list : list[dict] | None, optional
1069
+ unstacked_kwargs_list : list[dict[str, Any]] | None, optional
1067
1070
  The list of keyword arguments used when plotting the unstacked components in plot_hist() or plot_function(), one of which is called once for each unstacked component. Default is None.
1068
- model_sum_kwargs : dict | None, optional
1071
+ model_sum_kwargs : dict[str, Any] | None, optional
1069
1072
  The keyword arguments for the plot_hist() function for the sum of the model components.
1070
1073
  Has no effect if all the model components are stacked or if the model is one unstacked element.
1071
1074
  The special keyword "show" can be used with a boolean to specify whether to show or not the sum of the model components.
@@ -1138,11 +1141,11 @@ def plot_data_model_comparison(
1138
1141
  if plot_only is None:
1139
1142
  fig, (ax_main, ax_comparison) = create_comparison_figure()
1140
1143
  elif plot_only == "ax_main":
1141
- fig, ax_main = plt.subplots()
1142
1144
  _, ax_comparison = plt.subplots()
1145
+ fig, ax_main = plt.subplots()
1143
1146
  elif plot_only == "ax_comparison":
1144
- fig, ax_comparison = plt.subplots()
1145
1147
  _, ax_main = plt.subplots()
1148
+ fig, ax_comparison = plt.subplots()
1146
1149
  else:
1147
1150
  raise ValueError("plot_only must be 'ax_main', 'ax_comparison' or None.")
1148
1151
  elif fig is None or ax_main is None or ax_comparison is None:
@@ -6,8 +6,10 @@ from __future__ import annotations
6
6
 
7
7
  import os
8
8
  import warnings
9
+ from typing import Any
9
10
 
10
11
  import boost_histogram as bh
12
+ import numpy as np
11
13
  import yaml
12
14
 
13
15
  from plothist.histogramming import create_axis
@@ -36,14 +38,14 @@ def _check_if_variable_registry_exists(path: str) -> None:
36
38
 
37
39
 
38
40
  def _save_variable_registry(
39
- variable_registry: dict[str, dict], path: str = "./variable_registry.yaml"
41
+ variable_registry: dict[str, dict[str, Any]], path: str = "./variable_registry.yaml"
40
42
  ) -> None:
41
43
  """
42
44
  Save the variable registry to a yaml file.
43
45
 
44
46
  Parameters
45
47
  ----------
46
- variable_registry : dict[str, dict]
48
+ variable_registry : dict[str, dict[str, Any]]
47
49
  The variable registry to save.
48
50
  path : str, optional
49
51
  The path to the variable registry file (default is "./variable_registry.yaml").
@@ -62,7 +64,7 @@ def _save_variable_registry(
62
64
  def create_variable_registry(
63
65
  variable_keys: list[str],
64
66
  path: str = "./variable_registry.yaml",
65
- custom_dict: dict | None = None,
67
+ custom_dict: dict[str, Any] | None = None,
66
68
  reset: bool = False,
67
69
  ) -> None:
68
70
  """
@@ -102,7 +104,7 @@ def create_variable_registry(
102
104
  A list of variable keys to be registered.
103
105
  path : str, optional
104
106
  The path to the variable registry file (default is "./variable_registry.yaml").
105
- custom_dict : dict, optional
107
+ custom_dict : dict[str, Any], optional
106
108
  A dictionary containing the plotting information for the variables. Default dictionary is the one described above.
107
109
  reset : bool, optional
108
110
  If True, the registry will be reset to default values for all variable keys (default is False).
@@ -126,7 +128,7 @@ def create_variable_registry(
126
128
  {
127
129
  variable_key: {
128
130
  "name": variable_key,
129
- "bins": 50,
131
+ "bins": "auto",
130
132
  "range": ("min", "max"),
131
133
  "label": variable_key,
132
134
  "log": False,
@@ -142,7 +144,7 @@ def create_variable_registry(
142
144
 
143
145
  def get_variable_from_registry(
144
146
  variable_key: str, path: str = "./variable_registry.yaml"
145
- ) -> dict:
147
+ ) -> dict[str, Any]:
146
148
  """
147
149
  This function retrieves the parameter information for a variable from the variable registry file specified by the 'path' parameter.
148
150
  It loads the variable registry file and returns the dictionary entry corresponding to the specified variable name.
@@ -156,7 +158,7 @@ def get_variable_from_registry(
156
158
 
157
159
  Returns
158
160
  -------
159
- dict
161
+ dict[str, Any]
160
162
  A dictionary containing the parameter information for the specified variable.
161
163
 
162
164
  See also
@@ -168,17 +170,26 @@ def get_variable_from_registry(
168
170
 
169
171
  with open(path) as f:
170
172
  variable_registry = yaml.safe_load(f)
171
- if "range" in variable_registry[variable_key] and isinstance(
172
- variable_registry[variable_key]["range"], list
173
- ):
174
- variable_registry[variable_key]["range"] = tuple(
175
- variable_registry[variable_key]["range"]
176
- )
177
- return variable_registry[variable_key]
173
+
174
+ if not isinstance(variable_registry, dict):
175
+ raise RuntimeError(
176
+ f"Invalid registry format in {path}. Got {type(variable_registry)} instead of dict."
177
+ )
178
+
179
+ variable = variable_registry.get(variable_key)
180
+ if not isinstance(variable, dict):
181
+ raise RuntimeError(
182
+ f"Variable {variable_key} in {path} is not found or is not properly formatted."
183
+ )
184
+
185
+ if "range" in variable and isinstance(variable["range"], list):
186
+ variable["range"] = tuple(variable["range"])
187
+
188
+ return variable
178
189
 
179
190
 
180
191
  def update_variable_registry(
181
- dictionary: dict,
192
+ dictionary: dict[str, Any],
182
193
  variable_keys: list[str] | None = None,
183
194
  path: str = "./variable_registry.yaml",
184
195
  overwrite: bool = False,
@@ -188,7 +199,7 @@ def update_variable_registry(
188
199
 
189
200
  Parameters
190
201
  ----------
191
- dictionary : dict
202
+ dictionary : dict[str, Any]
192
203
  A dictionary containing the information to update the registry with.
193
204
  variable_keys : list[str]
194
205
  A list of variable keys for which to update the registry. Default is None: all variables in the registry are updated.
@@ -259,25 +270,37 @@ def remove_variable_registry_parameters(
259
270
  _save_variable_registry(variable_registry, path=path)
260
271
 
261
272
 
262
- def update_variable_registry_ranges(
273
+ def update_variable_registry_ranges(*args, **kwargs):
274
+ warnings.warn(
275
+ "`update_variable_registry_ranges` is deprecated since v1.7.0 and will be removed in future versions. "
276
+ "Use `update_variable_registry_binning` instead.",
277
+ DeprecationWarning,
278
+ stacklevel=2,
279
+ )
280
+ return update_variable_registry_binning(*args, **kwargs)
281
+
282
+
283
+ def update_variable_registry_binning(
263
284
  data,
264
285
  variable_keys: list[str] | None = None,
265
286
  path: str = "./variable_registry.yaml",
266
287
  overwrite: bool = False,
267
288
  ) -> None:
268
289
  """
269
- Update the range parameters for multiple variables in the variable registry file.
290
+ Update both the bins and range parameters for multiple variables in the variable registry file.
270
291
 
271
292
  Parameters
272
293
  ----------
273
294
  data : numpy.ndarray or pandas.DataFrame
274
295
  A dataset containing the data for the variables.
275
296
  variable_keys : list[str]
276
- A list of variable keys for which to update the range parameters in the registry. The variable needs to have a bin and range properties in the registry. Default is None: all variables in the registry are updated.
297
+ A list of variable keys for which to update the parameters in the registry.
298
+ The variable needs to have a bin and range properties in the registry.
299
+ Default is None: all variables in the registry are updated.
277
300
  path : str, optional
278
301
  The path to the variable registry file (default is "./variable_registry.yaml").
279
302
  overwrite : bool, optional
280
- If True, the range parameters will be overwritten even if it's not equal to ("min", "max") (default is False).
303
+ If True, the bin and range parameters will be overwritten even if they differ from "auto" and ("min", "max") (default is False).
281
304
 
282
305
  Returns
283
306
  -------
@@ -302,13 +325,23 @@ def update_variable_registry_ranges(
302
325
  f"Variable {variable_key} does not have a name, bins or range property in the registry {path}."
303
326
  )
304
327
 
305
- range = ("min", "max") if overwrite else variable["range"]
328
+ bins = "auto" if overwrite else variable["bins"]
329
+ bin_number = len(np.histogram_bin_edges(data[variable["name"]], bins=bins)) - 1
306
330
 
307
- if tuple(range) == ("min", "max"):
308
- axis = create_axis(variable["bins"], tuple(range), data[variable["name"]])
331
+ range_val = ("min", "max") if overwrite else variable["range"]
332
+
333
+ if bins == "auto" or tuple(range_val) == ("min", "max"):
334
+ axis = create_axis(
335
+ bin_number,
336
+ tuple(range_val),
337
+ data[variable["name"]],
338
+ )
309
339
  if isinstance(axis, bh.axis.Regular):
310
340
  update_variable_registry(
311
- {"range": (float(axis.edges[0]), float(axis.edges[-1]))},
341
+ {
342
+ "bins": bin_number,
343
+ "range": (float(axis.edges[0]), float(axis.edges[-1])),
344
+ },
312
345
  [variable_key],
313
346
  path=path,
314
347
  overwrite=True,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plothist
3
- Version: 1.6.0
3
+ Version: 1.8.0
4
4
  Summary: Plot histograms in a scalable way and a beautiful style.
5
5
  Project-URL: Homepage, https://github.com/cyrraz/plothist
6
6
  Project-URL: Documentation, https://plothist.readthedocs.io/
@@ -14,14 +14,19 @@ Classifier: Intended Audience :: Science/Research
14
14
  Classifier: License :: OSI Approved :: BSD License
15
15
  Classifier: Operating System :: OS Independent
16
16
  Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
17
23
  Classifier: Topic :: Scientific/Engineering
18
- Requires-Python: >=3.9
24
+ Requires-Python: >=3.10
19
25
  Requires-Dist: boost-histogram>=1.4.0
20
- Requires-Dist: matplotlib>=3.0
26
+ Requires-Dist: matplotlib>=3.10.8
21
27
  Requires-Dist: numpy>=1.14.5
22
28
  Requires-Dist: plothist-utils>=0.0.1
23
- Requires-Dist: pyyaml>=5.3.1
24
- Requires-Dist: requests>=2.25.0
29
+ Requires-Dist: pyyaml>=6.0.3
25
30
  Requires-Dist: scipy>=1.6.0
26
31
  Description-Content-Type: text/x-rst
27
32
 
@@ -46,9 +51,9 @@ plothist
46
51
  :width: 320
47
52
 
48
53
 
49
- |GitHub Project| |PyPI version| |Docs from main| |Discussion| |DOI| |Linter|
54
+ |GitHub Project| |PyPI version| |conda version| |Docs from main| |Discussion| |DOI|
50
55
 
51
- |GitHub Actions Status: CI| |GitHub Actions Status: CD| |pre-commit.ci Status| |Code Coverage|
56
+ |GitHub Actions Status: CI| |GitHub Actions Status: CD| |pre-commit.ci Status| |Linter| |Code Coverage|
52
57
 
53
58
  This package is a wrapper around `matplotlib <https://matplotlib.org/>`_.
54
59
 
@@ -75,6 +80,8 @@ This package is a wrapper around `matplotlib <https://matplotlib.org/>`_.
75
80
  :target: https://github.com/cyrraz/plothist
76
81
  .. |PyPI version| image:: https://badge.fury.io/py/plothist.svg?style=flat-square
77
82
  :target: https://badge.fury.io/py/plothist
83
+ .. |conda version| image:: https://img.shields.io/conda/vn/conda-forge/plothist?style=platic
84
+ :target: https://anaconda.org/conda-forge/plothist
78
85
  .. |Docs from main| image:: https://img.shields.io/badge/docs-main-blue.svg?style=platic
79
86
  :target: https://plothist.readthedocs.io/en/main/
80
87
  .. |Discussion| image:: https://img.shields.io/static/v1?label=Discussions&message=Ask&color=blue&logo=github?style=flat-square
@@ -1,13 +1,13 @@
1
- plothist/__init__.py,sha256=ikcYOZqMs4WKAJ2rM-3BnHu_CQxLlQCuc-iFo_a-Mns,2760
2
- plothist/_version.py,sha256=5FGJNp9Lkk9uOxeCjXpoCGBF79Ar6LGPOR7-atBqb_4,511
1
+ plothist/__init__.py,sha256=-cUpXXg2cCdfjcbYAQWHLUHq-5kLsxSWgEbgtZYjqBA,2817
2
+ plothist/_version.py,sha256=phQCmpksYlbZjXJhFI2j2KILuWjD0mXWO3Hg8g_EC8c,704
3
3
  plothist/_version.pyi,sha256=o7uNL6MhuJoiqpEnriU7rBT6TmkJZA-i2qMoNz9YcgQ,82
4
- plothist/comparison.py,sha256=jkONOiCp8RNBk8V_VvwACdfJJqo89rK9NQW71XxJscc,19623
4
+ plothist/comparison.py,sha256=AUYvJBnG9ifUtxC-1N5JwzR7AX3MFTX2bCfuVCqkciM,19629
5
5
  plothist/default_style.mplstyle,sha256=7MmB2uiXmD_DSqFHeH1xxC-lTctBD_EASxMdSOsPep0,1574
6
- plothist/histogramming.py,sha256=o0RLdoEhxHA7Ws0bvK3DewsbQEu-QOtJNw5Md5AckHM,11474
7
- plothist/plothist_style.py,sha256=bbYFc-qsrTfdbacCBAAzmiHJoRIh3toBomFfxtTRNMs,13255
8
- plothist/plotters.py,sha256=ncPZa34Fo1mbFxv0guFc2zEciX_JXGKJxeIfcUDaP6w,46336
6
+ plothist/histogramming.py,sha256=DJ9pl4i5cbvvkIsWs6MO6mMi_rAh_G94A1Nz8-v8zEs,11810
7
+ plothist/plothist_style.py,sha256=u3hA1SAE9UebEnzluEn_xcs81hjYLlNDXS1OvkIm110,13782
8
+ plothist/plotters.py,sha256=olfZOVMiuYGLnGOGnj0GxlI-Mufafwl_WvUNL-vZHxs,46782
9
9
  plothist/test_helpers.py,sha256=JXhxUdqMszkawxkU8cDPqipkSXNHfsKSfe3K-4frDrM,1379
10
- plothist/variable_registry.py,sha256=usVLoDLbIMzjeRDazIH0OIjQIUsh9RSJ9Ncnhn1V9qw,10783
10
+ plothist/variable_registry.py,sha256=eOK_Df8vkwlj91J2YbRF3_7jB1NEGwlux8kOZULStkw,11867
11
11
  plothist/examples/README.rst,sha256=PVzkOQzVnNeWORxEv3NNv5XoSN2Y71D7SYzRkCqirfA,151
12
12
  plothist/examples/1d_hist/1d_comparison_asymmetry.py,sha256=Rp9gv6E5z9KgIhnraS9AjGSMgHLhSHd_u5L-vG0w-gU,757
13
13
  plothist/examples/1d_hist/1d_comparison_difference.py,sha256=FMKoTjMIQp6VsFXspVBy2AdxHPDnxhMfj9PCvE4qVjk,877
@@ -26,16 +26,16 @@ plothist/examples/1d_hist/1d_profile.py,sha256=otmerm64DNAYnRWaablQkQDgUVOvjLNDc
26
26
  plothist/examples/1d_hist/1d_side_by_side.py,sha256=sAHhBVnopINQscFaUpVI4KNs18e_1laHyrYBOlmU_fQ,1557
27
27
  plothist/examples/1d_hist/1d_str_category.py,sha256=2DtxfNMAlcZ6pYx44lP0-sgY4M73-R0aBH61uEJmKA0,880
28
28
  plothist/examples/1d_hist/README.rst,sha256=GT4-w9W-TDtjOqibOPcd6vYzAGO8bDsgxBRp3fD1uTw,100
29
- plothist/examples/2d_hist/2d_hist_correlations.py,sha256=OroqVDKjNlAiMVXZ1AvFarV3qESiFkL0dnnb_NFkI70,1834
29
+ plothist/examples/2d_hist/2d_hist_correlations.py,sha256=c9PMymxNn9Kz0STvDQ3Pro4ndv-1PVG5RZsJCS9gobA,1836
30
30
  plothist/examples/2d_hist/2d_hist_simple.py,sha256=1n5yqOJxHzD31njOk85dTjuXhkogCDIS4-EG63XcnQ0,521
31
31
  plothist/examples/2d_hist/2d_hist_simple_discrete_colormap.py,sha256=E1zeMIDP25R_ppkB-wDz7TxaLsxf7dCs87FrPTPWTAc,1000
32
32
  plothist/examples/2d_hist/2d_hist_uneven.py,sha256=kR53XrSx38efG1wHEI69BIcPKVQzJygkr7ax_CFzBIA,646
33
33
  plothist/examples/2d_hist/2d_hist_with_projections.py,sha256=EPGNoXQu7Oa0xS_fDc21_0dCVPLeKpSyv3dylfwXIDs,725
34
34
  plothist/examples/2d_hist/README.rst,sha256=SCD39UgHb8vat63gNkOlDWPjwZj9INUS516D5DxW0Vk,116
35
35
  plothist/examples/advanced/1d_comparison_advanced.py,sha256=RHWejmv8OQcgZ2R9yfAehv8cc8vQ5qr5gcVApGWdQhI,2668
36
- plothist/examples/advanced/1d_side_by_side_with_numbers.py,sha256=46k1RXFPQ9x2yfeWQdAh5sz4I9C0SnYtQgqeL29_oQY,2437
36
+ plothist/examples/advanced/1d_side_by_side_with_numbers.py,sha256=-6KGJ48S6CT1ZM-krROUtAWZDrLqDhuQ6Ue5lRMeWBo,2463
37
37
  plothist/examples/advanced/README.rst,sha256=ulygCIs7LUaViLpeTCIG2qcG9FEohccrlR2nXYLnkO4,112
38
- plothist/examples/advanced/asymmetry_comparison_advanced.py,sha256=fteFmenSzhhZxgz4OU3fL8ejZKGnGpbNz-Zmt4M6g2c,2670
38
+ plothist/examples/advanced/asymmetry_comparison_advanced.py,sha256=9VvYvCkc7smjyuEQazxqo25xl0P5wzAugbW5ATjXDto,2741
39
39
  plothist/examples/advanced/model_examples_flatten2D.py,sha256=b4Rl6ItrsaddVL5uC9Gr3ccgSyhjW1RAtxSQgcCs_JA,2233
40
40
  plothist/examples/func_1d/README.rst,sha256=tez3Jpva9yv7T7bDfXE9dCdmThJ1ALZRiEHOfFkrCNk,108
41
41
  plothist/examples/func_1d/fct_1d.py,sha256=DRbKnImIqVYVXqH79X54YnxyGLu914fEmxry3fLBDsM,455
@@ -54,11 +54,11 @@ plothist/examples/model_ex/ratio_data_vs_model_with_stacked_and_unstacked_functi
54
54
  plothist/examples/utility/README.rst,sha256=8qQeSXjzdPDlp58cbaHnAq5O55BSp8V-Umr9wmouwJ8,77
55
55
  plothist/examples/utility/add_text_example.py,sha256=EB7ZUStt2E8GawjWNmVbSV34NINZ8v-4-rQBw1_gFD4,811
56
56
  plothist/examples/utility/color_palette_hists.py,sha256=uIc6TrmjTj8EUif1Yj1wq4nXoY1sgJpS15yPe3-FpTw,2383
57
- plothist/examples/utility/color_palette_squares.py,sha256=pNasgvZZApu-sCqhi5FTJAH3l6Px2cgB5RwJcQ1eF1U,2689
57
+ plothist/examples/utility/color_palette_squares.py,sha256=kBUhoEa0TM5dzDEhUiPkVrOmcZFmts4NqA5ow_4yyZ0,2779
58
58
  plothist/examples/utility/matplotlib_vs_plothist_style.py,sha256=iEIfbFKmAN-PcDCzw_sBuhrfpes4I2wUVfC0r1vUHEw,2006
59
59
  plothist/examples/utility/uncertainty_types.py,sha256=r1yxzEvxn5Clv0ZIok9JjVh3RB-YQ_usWhFnpvl1els,3259
60
- plothist-1.6.0.dist-info/METADATA,sha256=WsoMGQrcmUasAx0UxEP9aGEw7LAk1eHQCrjUz6228fY,4737
61
- plothist-1.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
62
- plothist-1.6.0.dist-info/licenses/AUTHORS.md,sha256=02x3_8PNyTsXcRs0IlJeCTOmpGNRqymcJ71-2QtR37E,111
63
- plothist-1.6.0.dist-info/licenses/LICENSE,sha256=bfaEdGehofQDaw-zDdVMHNUKo1FrOm6oGUEF-ltrp6w,1523
64
- plothist-1.6.0.dist-info/RECORD,,
60
+ plothist-1.8.0.dist-info/METADATA,sha256=jhJb4Vi2o11WwUbWdVoFjaDHLmYwDUuq8I525gQKwH8,5175
61
+ plothist-1.8.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
62
+ plothist-1.8.0.dist-info/licenses/AUTHORS.md,sha256=ngUOEAYO6Ed-wWStDZDemPZGRian7rVpTIqGUt_ECkE,115
63
+ plothist-1.8.0.dist-info/licenses/LICENSE,sha256=uiArTxl1M6mNZcA2HV7Dhd06--H5C3kz0_qIa2oQXkU,1523
64
+ plothist-1.8.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ - Cyrille Praz ([@cyrraz](https://github.com/cyrraz))
2
+ - Tristan Fillinger ([@0ctagon](https://github.com/0ctagon))
@@ -1,6 +1,6 @@
1
1
  BSD 3-Clause License
2
2
 
3
- Copyright (c) 2023-2025, Cyrille Praz, Tristan Fillinger
3
+ Copyright (c) 2023-2026, Cyrille Praz, Tristan Fillinger
4
4
 
5
5
  Redistribution and use in source and binary forms, with or without
6
6
  modification, are permitted provided that the following conditions are met:
@@ -1,2 +0,0 @@
1
- Cyrille Praz ([@cyrraz](https://github.com/cyrraz))
2
- Tristan Fillinger ([@0ctagon](https://github.com/0ctagon))