plothist 1.5.0__py3-none-any.whl → 1.7.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,22 +77,24 @@ __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
 
87
84
 
88
- # Get style file and use it
85
+ from importlib import resources
89
86
  from importlib.resources import files
90
87
 
88
+ import boost_histogram as bh
89
+ import matplotlib.font_manager as fm
91
90
  import matplotlib.pyplot as plt
92
91
 
92
+ # Get style file and use it
93
+
93
94
  style_file = files("plothist").joinpath("default_style.mplstyle")
94
95
  plt.style.use(style_file)
95
96
 
96
97
  # Install fonts
97
- from importlib import resources
98
-
99
- import matplotlib.font_manager as fm
100
98
 
101
99
  with resources.as_file(resources.files("plothist_utils") / "fonts") as font_path:
102
100
  font_files = fm.findSystemFonts(fontpaths=[str(font_path)])
@@ -104,7 +102,6 @@ with resources.as_file(resources.files("plothist_utils") / "fonts") as font_path
104
102
  fm.fontManager.addfont(font)
105
103
 
106
104
  # Check version of boost_histogram
107
- import boost_histogram as bh
108
105
 
109
106
  if tuple(int(part) for part in bh.__version__.split(".")) < (1, 4, 0):
110
107
  raise ImportError(
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.5.0'
21
- __version_tuple__ = version_tuple = (1, 5, 0)
31
+ __version__ = version = '1.7.0'
32
+ __version_tuple__ = version_tuple = (1, 7, 0)
33
+
34
+ __commit_id__ = commit_id = None
plothist/comparison.py CHANGED
@@ -22,9 +22,16 @@ def _check_uncertainty_type(uncertainty_type: str) -> None:
22
22
  If the uncertainty type is not valid.
23
23
 
24
24
  """
25
- if uncertainty_type not in ["symmetrical", "asymmetrical"]:
25
+ _valid_uncertainty_types = [
26
+ "symmetrical",
27
+ "asymmetrical",
28
+ "asymmetrical_double_sided_zeros",
29
+ "asymmetrical_one_sided_zeros",
30
+ ]
31
+
32
+ if uncertainty_type not in _valid_uncertainty_types:
26
33
  raise ValueError(
27
- f"Uncertainty type {uncertainty_type} not valid. Must be 'symmetrical' or 'asymmetrical'."
34
+ f"Uncertainty type {uncertainty_type} not valid. Must be in {_valid_uncertainty_types}."
28
35
  )
29
36
 
30
37
 
@@ -42,11 +49,12 @@ def _is_unweighted(hist: bh.Histogram) -> bool:
42
49
  bool
43
50
  True if the histogram is unweighted, False otherwise.
44
51
  """
45
- return np.allclose(hist.variances(), hist.values())
52
+ return np.allclose(hist.variances(), hist.values(), equal_nan=True)
46
53
 
47
54
 
48
55
  def get_asymmetrical_uncertainties(
49
56
  hist: bh.Histogram,
57
+ uncertainty_type: str = "asymmetrical",
50
58
  ) -> tuple[np.ndarray, np.ndarray]:
51
59
  """
52
60
  Get Poisson asymmetrical uncertainties for a histogram via a frequentist approach based on a confidence-interval computation.
@@ -57,6 +65,8 @@ def get_asymmetrical_uncertainties(
57
65
  ----------
58
66
  hist : bh.Histogram
59
67
  The histogram.
68
+ uncertainty_type : str, optional
69
+ The type of uncertainty to compute for bins with 0 entry. Default is "asymmetrical" (= "asymmetrical_one_sided_zeros"). Use "asymmetrical_double_sided_zeros" to have the double-sided definition. More information in :ref:`documentation-statistics-label`.
60
70
 
61
71
  Returns
62
72
  -------
@@ -72,16 +82,44 @@ def get_asymmetrical_uncertainties(
72
82
 
73
83
  """
74
84
  _check_counting_histogram(hist)
85
+ _check_uncertainty_type(uncertainty_type)
75
86
 
76
87
  if not _is_unweighted(hist):
77
88
  raise ValueError(
78
89
  "Asymmetrical uncertainties can only be computed for an unweighted histogram."
79
90
  )
80
- conf_level = 0.682689492
81
- alpha = 1.0 - conf_level
91
+
92
+ alpha = 1.0 - 0.682689492
93
+ tail_probability = alpha / 2
94
+
82
95
  n = hist.values()
83
- uncertainties_low = n - stats.gamma.ppf(alpha / 2, n, scale=1)
84
- uncertainties_high = stats.gamma.ppf(1 - alpha / 2, n + 1, scale=1) - n
96
+
97
+ lower_bound = np.zeros_like(n, dtype=float)
98
+ upper_bound = np.zeros_like(n, dtype=float)
99
+
100
+ # Two-sided Garwood intervals for n > 0
101
+ lower_bound[n > 0] = stats.gamma.ppf(q=tail_probability, a=n[n > 0], scale=1)
102
+ upper_bound[n > 0] = stats.gamma.ppf(
103
+ q=1 - tail_probability, a=n[n > 0] + 1, scale=1
104
+ )
105
+
106
+ if uncertainty_type == "asymmetrical_double_sided_zeros":
107
+ # Two-sided Garwood intervals for n == 0
108
+ upper_bound[n == 0] = stats.gamma.ppf(q=1 - tail_probability, a=1, scale=1)
109
+ elif uncertainty_type in ["asymmetrical_one_sided_zeros", "asymmetrical"]:
110
+ # One-sided upper limit for n == 0
111
+ upper_bound[n == 0] = stats.gamma.ppf(q=1 - 2 * tail_probability, a=1, scale=1)
112
+ else:
113
+ raise ValueError(
114
+ f"Invalid uncertainty type '{uncertainty_type}' for asymmetrical uncertainties."
115
+ )
116
+
117
+ # Compute asymmetric uncertainties
118
+ uncertainties_low = n - lower_bound
119
+ uncertainties_high = upper_bound - n
120
+
121
+ uncertainties_low = np.nan_to_num(uncertainties_low, nan=0.0)
122
+ uncertainties_high = np.nan_to_num(uncertainties_high, nan=0.0)
85
123
 
86
124
  return uncertainties_low, uncertainties_high
87
125
 
@@ -174,8 +212,10 @@ def get_pull(
174
212
  _check_counting_histogram(h1)
175
213
  _check_counting_histogram(h2)
176
214
 
177
- if h1_uncertainty_type == "asymmetrical":
178
- uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(h1)
215
+ if "asymmetrical" in h1_uncertainty_type:
216
+ uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(
217
+ h1, h1_uncertainty_type
218
+ )
179
219
  h1_variances = np.where(
180
220
  h1.values() >= h2.values(),
181
221
  uncertainties_low**2,
@@ -232,8 +272,10 @@ def get_difference(
232
272
 
233
273
  difference_values = h1.values() - h2.values()
234
274
 
235
- if h1_uncertainty_type == "asymmetrical":
236
- uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(h1)
275
+ if "asymmetrical" in h1_uncertainty_type:
276
+ uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(
277
+ h1, h1_uncertainty_type
278
+ )
237
279
 
238
280
  difference_uncertainties_low = np.sqrt(uncertainties_low**2 + h2.variances())
239
281
  difference_uncertainties_high = np.sqrt(uncertainties_high**2 + h2.variances())
@@ -390,11 +432,13 @@ def get_ratio(
390
432
 
391
433
  ratio_values = np.where(h2.values() != 0, h1.values() / h2.values(), np.nan)
392
434
 
393
- if h1_uncertainty_type == "asymmetrical":
394
- uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(h1)
435
+ if "asymmetrical" in h1_uncertainty_type:
436
+ uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(
437
+ h1, h1_uncertainty_type
438
+ )
395
439
 
396
440
  if ratio_uncertainty_type == "uncorrelated":
397
- if h1_uncertainty_type == "asymmetrical":
441
+ if "asymmetrical" in h1_uncertainty_type:
398
442
  h1_high = h1.copy()
399
443
  h1_high[:] = np.c_[h1_high.values(), uncertainties_high**2]
400
444
  h1_low = h1.copy()
@@ -405,7 +449,7 @@ def get_ratio(
405
449
  ratio_uncertainties_low = np.sqrt(get_ratio_variances(h1, h2))
406
450
  ratio_uncertainties_high = ratio_uncertainties_low
407
451
  elif ratio_uncertainty_type == "split":
408
- if h1_uncertainty_type == "asymmetrical":
452
+ if "asymmetrical" in h1_uncertainty_type:
409
453
  ratio_uncertainties_low = uncertainties_low / h2.values()
410
454
  ratio_uncertainties_high = uncertainties_high / h2.values()
411
455
  else:
@@ -493,7 +537,7 @@ def get_comparison(
493
537
  h1, h2, h1_uncertainty_type
494
538
  )
495
539
  elif comparison == "asymmetry":
496
- if h1_uncertainty_type == "asymmetrical":
540
+ if "asymmetrical" in h1_uncertainty_type:
497
541
  raise ValueError(
498
542
  "Asymmetrical uncertainties are not supported for the asymmetry comparison."
499
543
  )
@@ -501,7 +545,7 @@ def get_comparison(
501
545
  lower_uncertainties = uncertainties
502
546
  upper_uncertainties = uncertainties
503
547
  elif comparison == "efficiency":
504
- if h1_uncertainty_type == "asymmetrical":
548
+ if "asymmetrical" in h1_uncertainty_type:
505
549
  raise ValueError(
506
550
  "Asymmetrical uncertainties are not supported in an efficiency computation."
507
551
  )
@@ -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))
@@ -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
@@ -109,6 +109,7 @@ def make_hist(
109
109
  bins: int | list[float] | np.ndarray = 50,
110
110
  range: tuple[float | str, float | str] | None = None,
111
111
  weights: float | list[float] | np.ndarray = 1,
112
+ mute_warning: bool = False,
112
113
  ) -> bh.Histogram:
113
114
  """
114
115
  Create a histogram object and fill it with the provided data.
@@ -129,6 +130,8 @@ def make_hist(
129
130
  Weight(s) to apply to the data points (default is 1).
130
131
  If a float, a single weight is applied to all data points.
131
132
  If an array-like, weights are applied element-wise.
133
+ mute_warning : bool, optional
134
+ Whether to mute warnings about data outside the binning range (default is False).
132
135
 
133
136
  Returns
134
137
  -------
@@ -160,7 +163,7 @@ def make_hist(
160
163
  range_coverage = h.sum().value / n_data
161
164
 
162
165
  # Issue a warning if more than 1% of the data is outside of the binning range
163
- if range_coverage < 0.99:
166
+ if range_coverage < 0.99 and not mute_warning:
164
167
  warnings.warn(
165
168
  f"Only {100 * range_coverage:.2f}% of data contained in the binning range [{axis.edges[0]}, {axis.edges[-1]}].",
166
169
  category=RangeWarning,
@@ -177,6 +180,7 @@ def make_2d_hist(
177
180
  tuple[float | str, float | str] | None, tuple[float | str, float | str] | None
178
181
  ] = (None, None),
179
182
  weights: float | list[float] | np.ndarray = 1,
183
+ mute_warning: bool = False,
180
184
  ) -> bh.Histogram:
181
185
  """
182
186
  Create a 2D histogram object and fill it with the provided data.
@@ -198,6 +202,8 @@ def make_2d_hist(
198
202
  Weight(s) to apply to the data points (default is 1).
199
203
  If a float, a single weight is applied to all data points.
200
204
  If an array-like, weights are applied element-wise.
205
+ mute_warning : bool, optional
206
+ Whether to mute warnings about data outside the binning range (default is False).
201
207
 
202
208
  Returns
203
209
  -------
@@ -245,7 +251,7 @@ def make_2d_hist(
245
251
  range_coverage = h.sum().value / n_data
246
252
 
247
253
  # Issue a warning if more than 1% of the data is outside of the binning range
248
- if range_coverage < 0.99:
254
+ if range_coverage < 0.99 and not mute_warning:
249
255
  warnings.warn(
250
256
  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
257
  category=RangeWarning,
@@ -112,7 +112,7 @@ def cubehelix_palette(
112
112
  pal = cmap(x)[:, :3].tolist()
113
113
  if reverse:
114
114
  pal = pal[::-1]
115
- return pal
115
+ return [tuple(c) for c in pal]
116
116
 
117
117
 
118
118
  def get_color_palette(
@@ -170,7 +170,7 @@ def get_color_palette(
170
170
  )
171
171
 
172
172
  plt_cmap = plt.get_cmap(cmap)
173
- return plt_cmap(np.linspace(0, 1, N))
173
+ return [tuple(k) for k in plt_cmap(np.linspace(0, 1, N))]
174
174
 
175
175
 
176
176
  def set_fitting_ylabel_fontsize(ax: plt.Axes) -> float:
plothist/plotters.py CHANGED
@@ -406,7 +406,9 @@ def plot_error_hist(
406
406
  if uncertainty_type == "symmetrical":
407
407
  kwargs.setdefault("yerr", np.sqrt(hist.variances()))
408
408
  else:
409
- uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(hist)
409
+ uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(
410
+ hist, uncertainty_type
411
+ )
410
412
  kwargs.setdefault("yerr", [uncertainties_low, uncertainties_high])
411
413
 
412
414
  kwargs.setdefault("fmt", ".")
@@ -8,6 +8,7 @@ import os
8
8
  import warnings
9
9
 
10
10
  import boost_histogram as bh
11
+ import numpy as np
11
12
  import yaml
12
13
 
13
14
  from plothist.histogramming import create_axis
@@ -126,7 +127,7 @@ def create_variable_registry(
126
127
  {
127
128
  variable_key: {
128
129
  "name": variable_key,
129
- "bins": 50,
130
+ "bins": "auto",
130
131
  "range": ("min", "max"),
131
132
  "label": variable_key,
132
133
  "log": False,
@@ -259,25 +260,37 @@ def remove_variable_registry_parameters(
259
260
  _save_variable_registry(variable_registry, path=path)
260
261
 
261
262
 
262
- def update_variable_registry_ranges(
263
+ def update_variable_registry_ranges(*args, **kwargs):
264
+ warnings.warn(
265
+ "`update_variable_registry_ranges` is deprecated since v1.7.0 and will be removed in future versions. "
266
+ "Use `update_variable_registry_binning` instead.",
267
+ DeprecationWarning,
268
+ stacklevel=2,
269
+ )
270
+ return update_variable_registry_binning(*args, **kwargs)
271
+
272
+
273
+ def update_variable_registry_binning(
263
274
  data,
264
275
  variable_keys: list[str] | None = None,
265
276
  path: str = "./variable_registry.yaml",
266
277
  overwrite: bool = False,
267
278
  ) -> None:
268
279
  """
269
- Update the range parameters for multiple variables in the variable registry file.
280
+ Update both the bins and range parameters for multiple variables in the variable registry file.
270
281
 
271
282
  Parameters
272
283
  ----------
273
284
  data : numpy.ndarray or pandas.DataFrame
274
285
  A dataset containing the data for the variables.
275
286
  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.
287
+ A list of variable keys for which to update the parameters in the registry.
288
+ The variable needs to have a bin and range properties in the registry.
289
+ Default is None: all variables in the registry are updated.
277
290
  path : str, optional
278
291
  The path to the variable registry file (default is "./variable_registry.yaml").
279
292
  overwrite : bool, optional
280
- If True, the range parameters will be overwritten even if it's not equal to ("min", "max") (default is False).
293
+ If True, the bin and range parameters will be overwritten even if they differ from "auto" and ("min", "max") (default is False).
281
294
 
282
295
  Returns
283
296
  -------
@@ -302,13 +315,23 @@ def update_variable_registry_ranges(
302
315
  f"Variable {variable_key} does not have a name, bins or range property in the registry {path}."
303
316
  )
304
317
 
305
- range = ("min", "max") if overwrite else variable["range"]
318
+ bins = "auto" if overwrite else variable["bins"]
319
+ bin_number = len(np.histogram_bin_edges(data[variable["name"]], bins=bins)) - 1
306
320
 
307
- if tuple(range) == ("min", "max"):
308
- axis = create_axis(variable["bins"], tuple(range), data[variable["name"]])
321
+ range_val = ("min", "max") if overwrite else variable["range"]
322
+
323
+ if bins == "auto" or tuple(range_val) == ("min", "max"):
324
+ axis = create_axis(
325
+ bin_number,
326
+ tuple(range_val),
327
+ data[variable["name"]],
328
+ )
309
329
  if isinstance(axis, bh.axis.Regular):
310
330
  update_variable_registry(
311
- {"range": (float(axis.edges[0]), float(axis.edges[-1]))},
331
+ {
332
+ "bins": bin_number,
333
+ "range": (float(axis.edges[0]), float(axis.edges[-1])),
334
+ },
312
335
  [variable_key],
313
336
  path=path,
314
337
  overwrite=True,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plothist
3
- Version: 1.5.0
3
+ Version: 1.7.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/
@@ -1,13 +1,13 @@
1
- plothist/__init__.py,sha256=00yQZBIlyvZxdimTgPMHK_ZH5pNVadyi-fu6ezuXRQs,2760
2
- plothist/_version.py,sha256=qEW4HoWHYDkBguijNs9nZzHd38qlKSeRTDG2QQbYrGY,511
1
+ plothist/__init__.py,sha256=-cUpXXg2cCdfjcbYAQWHLUHq-5kLsxSWgEbgtZYjqBA,2817
2
+ plothist/_version.py,sha256=oGRWiKvEGHesjf5wCNHGVlYfAA3dInDJeL5EiMaru6A,704
3
3
  plothist/_version.pyi,sha256=o7uNL6MhuJoiqpEnriU7rBT6TmkJZA-i2qMoNz9YcgQ,82
4
- plothist/comparison.py,sha256=Lk5bTMHe93C_0eOfUJQaY8lHxykJIQBWMDDt-iOmR-E,17935
4
+ plothist/comparison.py,sha256=jkONOiCp8RNBk8V_VvwACdfJJqo89rK9NQW71XxJscc,19623
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=oPGt61GT6Hs_m6jRNlNDGCH1-5AJuMMUi7guw1vTGVo,13215
8
- plothist/plotters.py,sha256=hjoDKVTYfRXI1m0GxlkfPc2LnpQWH1aYC8GnsYEak9k,46296
6
+ plothist/histogramming.py,sha256=Q0KRQjdyZGXj7J-qlXgzUbb-s7duqZG4QD2BIuVNQes,11828
7
+ plothist/plothist_style.py,sha256=bbYFc-qsrTfdbacCBAAzmiHJoRIh3toBomFfxtTRNMs,13255
8
+ plothist/plotters.py,sha256=ncPZa34Fo1mbFxv0guFc2zEciX_JXGKJxeIfcUDaP6w,46336
9
9
  plothist/test_helpers.py,sha256=JXhxUdqMszkawxkU8cDPqipkSXNHfsKSfe3K-4frDrM,1379
10
- plothist/variable_registry.py,sha256=usVLoDLbIMzjeRDazIH0OIjQIUsh9RSJ9Ncnhn1V9qw,10783
10
+ plothist/variable_registry.py,sha256=lYQ1DxUXBtY_UlZcuvwf_XQllq5MdPFKBmIrnRTNauo,11536
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,7 +26,7 @@ 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
@@ -56,8 +56,9 @@ plothist/examples/utility/add_text_example.py,sha256=EB7ZUStt2E8GawjWNmVbSV34NIN
56
56
  plothist/examples/utility/color_palette_hists.py,sha256=uIc6TrmjTj8EUif1Yj1wq4nXoY1sgJpS15yPe3-FpTw,2383
57
57
  plothist/examples/utility/color_palette_squares.py,sha256=pNasgvZZApu-sCqhi5FTJAH3l6Px2cgB5RwJcQ1eF1U,2689
58
58
  plothist/examples/utility/matplotlib_vs_plothist_style.py,sha256=iEIfbFKmAN-PcDCzw_sBuhrfpes4I2wUVfC0r1vUHEw,2006
59
- plothist-1.5.0.dist-info/METADATA,sha256=0km7Qp4BxeY3aBXgC7EdkIShgSlNVo6yOnR6ehC16a0,4737
60
- plothist-1.5.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
61
- plothist-1.5.0.dist-info/licenses/AUTHORS.md,sha256=02x3_8PNyTsXcRs0IlJeCTOmpGNRqymcJ71-2QtR37E,111
62
- plothist-1.5.0.dist-info/licenses/LICENSE,sha256=bfaEdGehofQDaw-zDdVMHNUKo1FrOm6oGUEF-ltrp6w,1523
63
- plothist-1.5.0.dist-info/RECORD,,
59
+ plothist/examples/utility/uncertainty_types.py,sha256=r1yxzEvxn5Clv0ZIok9JjVh3RB-YQ_usWhFnpvl1els,3259
60
+ plothist-1.7.0.dist-info/METADATA,sha256=X_mWIcy0jZbKaLcNPGaoL2jR4y1RnBYcnpQw-FgqlqM,4737
61
+ plothist-1.7.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
62
+ plothist-1.7.0.dist-info/licenses/AUTHORS.md,sha256=-2hRQyzJdkGgYPu8J-xDAWCwiqomcR56uYuzlJ4yMJM,115
63
+ plothist-1.7.0.dist-info/licenses/LICENSE,sha256=bfaEdGehofQDaw-zDdVMHNUKo1FrOm6oGUEF-ltrp6w,1523
64
+ plothist-1.7.0.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ * Cyrille Praz ([@cyrraz](https://github.com/cyrraz))
2
+ * Tristan Fillinger ([@0ctagon](https://github.com/0ctagon))
@@ -1,2 +0,0 @@
1
- Cyrille Praz ([@cyrraz](https://github.com/cyrraz))
2
- Tristan Fillinger ([@0ctagon](https://github.com/0ctagon))