aptapy 0.3.1__tar.gz → 0.3.2__tar.gz
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.
- {aptapy-0.3.1 → aptapy-0.3.2}/PKG-INFO +1 -1
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/release_notes.rst +15 -0
- aptapy-0.3.2/src/aptapy/_version.py +1 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/src/aptapy/hist.py +52 -7
- {aptapy-0.3.1 → aptapy-0.3.2}/src/aptapy/modeling.py +3 -3
- {aptapy-0.3.1 → aptapy-0.3.2}/tests/test_hist.py +32 -5
- {aptapy-0.3.1 → aptapy-0.3.2}/tests/test_modeling.py +1 -1
- aptapy-0.3.1/src/aptapy/_version.py +0 -1
- {aptapy-0.3.1 → aptapy-0.3.2}/.github/workflows/ci.yml +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/.github/workflows/docs.yml +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/.github/workflows/pypi.yml +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/.gitignore +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/CODE_OF_CONDUCT.md +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/CONTRIBUTING.md +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/LICENSE +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/README.md +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/Makefile +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/_static/favicon.ico +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/_static/logo.png +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/_static/logo_small.png +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/conf.py +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/examples/GALLERY_HEADER.rst +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/examples/composite_fit.py +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/examples/constrained_fit.py +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/examples/simple_fit.py +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/examples/simple_hist1d.py +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/examples/weighted_hist1d.py +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/hist.rst +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/index.rst +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/make.bat +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/modeling.rst +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/docs/strip.rst +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/noxfile.py +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/pyproject.toml +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/src/aptapy/__init__.py +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/src/aptapy/plotting.py +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/src/aptapy/py.typed +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/src/aptapy/strip.py +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/src/aptapy/typing_.py +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/tests/test_strip.py +0 -0
- {aptapy-0.3.1 → aptapy-0.3.2}/tools/release.py +0 -0
@@ -4,9 +4,24 @@ Release notes
|
|
4
4
|
=============
|
5
5
|
|
6
6
|
|
7
|
+
Version 0.3.2 (2025-10-09)
|
8
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
9
|
+
|
10
|
+
* Adding binned_statistics method in AbstractHistogram base class to calculate
|
11
|
+
statistics from histogram bins
|
12
|
+
* Adds extensive test coverage in both 1D and 2D histogram test functions with
|
13
|
+
statistical validation
|
14
|
+
|
15
|
+
* Pull requests merged:
|
16
|
+
|
17
|
+
- https://github.com/lucabaldini/aptapy/pull/6
|
18
|
+
|
19
|
+
|
7
20
|
Version 0.3.1 (2025-10-09)
|
8
21
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
9
22
|
|
23
|
+
* Minor changes.
|
24
|
+
|
10
25
|
|
11
26
|
Version 0.3.0 (2025-10-08)
|
12
27
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.3.2"
|
@@ -17,7 +17,7 @@
|
|
17
17
|
"""
|
18
18
|
|
19
19
|
from abc import ABC, abstractmethod
|
20
|
-
from typing import List, Sequence
|
20
|
+
from typing import List, Sequence, Tuple
|
21
21
|
|
22
22
|
import numpy as np
|
23
23
|
|
@@ -93,6 +93,43 @@ class AbstractHistogram(ABC):
|
|
93
93
|
"""
|
94
94
|
return np.diff(self._edges[axis])
|
95
95
|
|
96
|
+
def binned_statistics(self, axis: int = 0) -> Tuple[float, float]:
|
97
|
+
"""Return the mean and standard deviation along a specific axis, based
|
98
|
+
on the binned data.
|
99
|
+
|
100
|
+
.. note::
|
101
|
+
|
102
|
+
This is a crude estimate of the underlying statistics that might be
|
103
|
+
useful for monitoring purposes, but should not be relied upon for
|
104
|
+
quantitative analysis.
|
105
|
+
|
106
|
+
This is not the same as computing the mean and standard deviation of
|
107
|
+
the unbinned data that filled the histogram, as some information is
|
108
|
+
lost in the binning process.
|
109
|
+
|
110
|
+
In addition, note that we are not applying any bias correction to
|
111
|
+
the standard deviation, as we are assuming that the histogram is
|
112
|
+
filled with a sufficiently large number of entries. (In most circumstances
|
113
|
+
the effect should be smaller than that of the binning itself.)
|
114
|
+
|
115
|
+
Arguments
|
116
|
+
---------
|
117
|
+
axis : int
|
118
|
+
the axis along which to compute the statistics.
|
119
|
+
|
120
|
+
Returns
|
121
|
+
-------
|
122
|
+
mean : float
|
123
|
+
the mean value along the specified axis.
|
124
|
+
stddev : float
|
125
|
+
the standard deviation along the specified axis.
|
126
|
+
"""
|
127
|
+
values = self.bin_centers(axis)
|
128
|
+
weights = self.content.sum(axis=tuple(i for i in range(self.content.ndim) if i != axis))
|
129
|
+
mean = np.average(values, weights=weights)
|
130
|
+
variance = np.average((values - mean)**2, weights=weights)
|
131
|
+
return float(mean), float(np.sqrt(variance))
|
132
|
+
|
96
133
|
def fill(self, *values: ArrayLike, weights: ArrayLike = None) -> "AbstractHistogram":
|
97
134
|
"""Fill the histogram from unbinned data.
|
98
135
|
|
@@ -229,10 +266,18 @@ class Histogram1d(AbstractHistogram):
|
|
229
266
|
"""
|
230
267
|
# If we are not explicitly providing a label at plotting time, use
|
231
268
|
# the one attached to the histogram, if any.
|
232
|
-
kwargs.setdefault(
|
269
|
+
kwargs.setdefault("label", f"{self}")
|
233
270
|
axes.hist(self.bin_centers(0), self._edges[0], weights=self.content, **kwargs)
|
234
271
|
setup_axes(axes, xlabel=self.axis_labels[0], ylabel=self.axis_labels[1])
|
235
272
|
|
273
|
+
def __str__(self) -> str:
|
274
|
+
"""String formatting.
|
275
|
+
"""
|
276
|
+
mean, rms = self.binned_statistics()
|
277
|
+
text = self.label or self.__class__.__name__
|
278
|
+
text = f"{text}\nMean: {mean:g}\nRMS: {rms:g}"
|
279
|
+
return text
|
280
|
+
|
236
281
|
|
237
282
|
class Histogram2d(AbstractHistogram):
|
238
283
|
|
@@ -259,10 +304,10 @@ class Histogram2d(AbstractHistogram):
|
|
259
304
|
the text label for the z axis (default: "Entries/bin").
|
260
305
|
"""
|
261
306
|
|
262
|
-
DEFAULT_PLOT_OPTIONS = dict(cmap=plt.get_cmap(
|
307
|
+
DEFAULT_PLOT_OPTIONS = dict(cmap=plt.get_cmap("hot"))
|
263
308
|
|
264
309
|
def __init__(self, xedges, yedges, label: str = None, xlabel: str = None,
|
265
|
-
ylabel: str = None, zlabel: str =
|
310
|
+
ylabel: str = None, zlabel: str = "Entries/bin") -> None:
|
266
311
|
"""Constructor.
|
267
312
|
"""
|
268
313
|
super().__init__((xedges, yedges), label, [xlabel, ylabel, zlabel])
|
@@ -272,9 +317,9 @@ class Histogram2d(AbstractHistogram):
|
|
272
317
|
"""
|
273
318
|
# pylint: disable=arguments-differ
|
274
319
|
if logz:
|
275
|
-
vmin = kwargs.pop(
|
276
|
-
vmax = kwargs.pop(
|
277
|
-
kwargs.setdefault(
|
320
|
+
vmin = kwargs.pop("vmin", None)
|
321
|
+
vmax = kwargs.pop("vmax", None)
|
322
|
+
kwargs.setdefault("norm", matplotlib.colors.LogNorm(vmin, vmax))
|
278
323
|
mappable = axes.pcolormesh(*self._edges, self.content.T, **kwargs)
|
279
324
|
plt.colorbar(mappable, ax=axes, label=self.axis_labels[2])
|
280
325
|
setup_axes(axes, xlabel=self.axis_labels[0], ylabel=self.axis_labels[1])
|
@@ -316,10 +316,10 @@ class FitStatus:
|
|
316
316
|
if self.chisquare is None:
|
317
317
|
return "N/A"
|
318
318
|
if spec.endswith(Format.LATEX):
|
319
|
-
return f"$\\chi^2
|
319
|
+
return f"$\\chi^2$: {self.chisquare:.2f} / {self.dof} dof"
|
320
320
|
if spec.endswith(Format.PRETTY):
|
321
|
-
return f"
|
322
|
-
return f"chisquare
|
321
|
+
return f"χ²: {self.chisquare:.2f} / {self.dof} dof"
|
322
|
+
return f"chisquare: {self.chisquare:.2f} / {self.dof} dof"
|
323
323
|
|
324
324
|
def __str__(self) -> str:
|
325
325
|
"""String formatting.
|
@@ -101,22 +101,43 @@ def test_plotting1d(size: int = 100000):
|
|
101
101
|
plt.figure(inspect.currentframe().f_code.co_name)
|
102
102
|
# Create the first histogram. This has no label attached, so we will have to
|
103
103
|
# provide one at plotting time, if we want to have a corresponding legend entry.
|
104
|
+
mean = 0.
|
105
|
+
sigma = 1.
|
104
106
|
hist1 = Histogram1d(np.linspace(-5., 5., 100), xlabel='x')
|
105
|
-
hist1.fill(_RNG.normal(size=size))
|
107
|
+
hist1.fill(_RNG.normal(size=size, loc=mean, scale=sigma))
|
106
108
|
hist1.plot(label='Standard histogram')
|
109
|
+
m, s = hist1.binned_statistics()
|
110
|
+
# Rough checks on the binned statistics---we want the mean to be within 10
|
111
|
+
# sigma/sqrt(N) and the stddev to be within 2% of the true value.
|
112
|
+
# (Note the binning has an effect on the actual values, so we cannot
|
113
|
+
# expect perfect agreement.)
|
114
|
+
assert abs((m - mean) / sigma * np.sqrt(size)) < 10.
|
115
|
+
assert abs(s / sigma - 1.) < 0.02
|
116
|
+
|
107
117
|
# Create a second histogram, this time with a label---this should have a
|
108
118
|
# proper entry in the legend automatically.
|
119
|
+
mean = 1.
|
120
|
+
sigma = 1.5
|
109
121
|
hist2 = Histogram1d(np.linspace(-5., 5., 100), label='Offset histogram')
|
110
|
-
hist2.fill(_RNG.normal(size=size, loc=
|
122
|
+
hist2.fill(_RNG.normal(size=size, loc=mean, scale=sigma))
|
111
123
|
hist2.plot()
|
124
|
+
m, s = hist2.binned_statistics()
|
125
|
+
assert abs((m - mean) / sigma * np.sqrt(size)) < 10.
|
126
|
+
assert abs(s / sigma - 1.) < 0.02
|
127
|
+
|
112
128
|
# And this one should end up with no legend entry, as it has no label
|
129
|
+
mean = -1.
|
130
|
+
sigma = 0.5
|
113
131
|
hist3 = Histogram1d(np.linspace(-5., 5., 100))
|
114
|
-
hist3.fill(_RNG.normal(size=size
|
132
|
+
hist3.fill(_RNG.normal(size=size, loc=mean, scale=sigma))
|
115
133
|
hist3.plot()
|
134
|
+
m, s = hist3.binned_statistics()
|
135
|
+
assert abs((m - mean) / sigma * np.sqrt(size)) < 10.
|
136
|
+
assert abs(s / sigma - 1.) < 0.02
|
116
137
|
plt.legend()
|
117
138
|
|
118
139
|
|
119
|
-
def test_plotting2d(size: int = 100000):
|
140
|
+
def test_plotting2d(size: int = 100000, x0: float = 1., y0: float = -1.):
|
120
141
|
"""Test plotting.
|
121
142
|
"""
|
122
143
|
plt.figure(inspect.currentframe().f_code.co_name)
|
@@ -124,8 +145,14 @@ def test_plotting2d(size: int = 100000):
|
|
124
145
|
hist = Histogram2d(edges, edges, 'x', 'y')
|
125
146
|
# Note we are adding different offsets to x and y so that we can see
|
126
147
|
# the effect on the plot.
|
127
|
-
hist.fill(_RNG.normal(size=size)
|
148
|
+
hist.fill(_RNG.normal(size=size, loc=x0), _RNG.normal(size=size, loc=y0))
|
128
149
|
hist.plot()
|
150
|
+
mx, sx = hist.binned_statistics(0)
|
151
|
+
my, sy = hist.binned_statistics(1)
|
152
|
+
assert abs((mx - x0) * np.sqrt(size)) < 10.
|
153
|
+
assert abs((my - y0) * np.sqrt(size)) < 10.
|
154
|
+
assert abs(sx - 1.) < 0.02
|
155
|
+
assert abs(sy - 1.) < 0.02
|
129
156
|
plt.gca().set_aspect('equal')
|
130
157
|
|
131
158
|
|
@@ -26,7 +26,7 @@ from aptapy.plotting import plt
|
|
26
26
|
|
27
27
|
_RNG = np.random.default_rng(313)
|
28
28
|
|
29
|
-
TEST_HISTOGRAM = Histogram1d(np.linspace(-5., 5., 100), label="
|
29
|
+
TEST_HISTOGRAM = Histogram1d(np.linspace(-5., 5., 100), label="Random data")
|
30
30
|
TEST_HISTOGRAM.fill(_RNG.normal(size=100000))
|
31
31
|
NUM_SIGMA = 4.
|
32
32
|
|
@@ -1 +0,0 @@
|
|
1
|
-
__version__ = "0.3.1"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|