aptapy 0.3.1__py3-none-any.whl → 0.4.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.
aptapy/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.3.1"
1
+ __version__ = "0.4.0"
aptapy/hist.py CHANGED
@@ -17,13 +17,17 @@
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
 
24
24
  from .plotting import matplotlib, plt, setup_axes
25
25
  from .typing_ import ArrayLike
26
26
 
27
+ __all__ = [
28
+ "Histogram1d",
29
+ "Histogram2d",
30
+ ]
27
31
 
28
32
  class AbstractHistogram(ABC):
29
33
 
@@ -93,6 +97,43 @@ class AbstractHistogram(ABC):
93
97
  """
94
98
  return np.diff(self._edges[axis])
95
99
 
100
+ def binned_statistics(self, axis: int = 0) -> Tuple[float, float]:
101
+ """Return the mean and standard deviation along a specific axis, based
102
+ on the binned data.
103
+
104
+ .. note::
105
+
106
+ This is a crude estimate of the underlying statistics that might be
107
+ useful for monitoring purposes, but should not be relied upon for
108
+ quantitative analysis.
109
+
110
+ This is not the same as computing the mean and standard deviation of
111
+ the unbinned data that filled the histogram, as some information is
112
+ lost in the binning process.
113
+
114
+ In addition, note that we are not applying any bias correction to
115
+ the standard deviation, as we are assuming that the histogram is
116
+ filled with a sufficiently large number of entries. (In most circumstances
117
+ the effect should be smaller than that of the binning itself.)
118
+
119
+ Arguments
120
+ ---------
121
+ axis : int
122
+ the axis along which to compute the statistics.
123
+
124
+ Returns
125
+ -------
126
+ mean : float
127
+ the mean value along the specified axis.
128
+ stddev : float
129
+ the standard deviation along the specified axis.
130
+ """
131
+ values = self.bin_centers(axis)
132
+ weights = self.content.sum(axis=tuple(i for i in range(self.content.ndim) if i != axis))
133
+ mean = np.average(values, weights=weights)
134
+ variance = np.average((values - mean)**2, weights=weights)
135
+ return float(mean), float(np.sqrt(variance))
136
+
96
137
  def fill(self, *values: ArrayLike, weights: ArrayLike = None) -> "AbstractHistogram":
97
138
  """Fill the histogram from unbinned data.
98
139
 
@@ -229,10 +270,18 @@ class Histogram1d(AbstractHistogram):
229
270
  """
230
271
  # If we are not explicitly providing a label at plotting time, use
231
272
  # the one attached to the histogram, if any.
232
- kwargs.setdefault('label', self.label)
273
+ kwargs.setdefault("label", f"{self}")
233
274
  axes.hist(self.bin_centers(0), self._edges[0], weights=self.content, **kwargs)
234
275
  setup_axes(axes, xlabel=self.axis_labels[0], ylabel=self.axis_labels[1])
235
276
 
277
+ def __str__(self) -> str:
278
+ """String formatting.
279
+ """
280
+ mean, rms = self.binned_statistics()
281
+ text = self.label or self.__class__.__name__
282
+ text = f"{text}\nMean: {mean:g}\nRMS: {rms:g}"
283
+ return text
284
+
236
285
 
237
286
  class Histogram2d(AbstractHistogram):
238
287
 
@@ -259,10 +308,10 @@ class Histogram2d(AbstractHistogram):
259
308
  the text label for the z axis (default: "Entries/bin").
260
309
  """
261
310
 
262
- DEFAULT_PLOT_OPTIONS = dict(cmap=plt.get_cmap('hot'))
311
+ DEFAULT_PLOT_OPTIONS = dict(cmap=plt.get_cmap("hot"))
263
312
 
264
313
  def __init__(self, xedges, yedges, label: str = None, xlabel: str = None,
265
- ylabel: str = None, zlabel: str = 'Entries/bin') -> None:
314
+ ylabel: str = None, zlabel: str = "Entries/bin") -> None:
266
315
  """Constructor.
267
316
  """
268
317
  super().__init__((xedges, yedges), label, [xlabel, ylabel, zlabel])
@@ -272,9 +321,9 @@ class Histogram2d(AbstractHistogram):
272
321
  """
273
322
  # pylint: disable=arguments-differ
274
323
  if logz:
275
- vmin = kwargs.pop('vmin', None)
276
- vmax = kwargs.pop('vmax', None)
277
- kwargs.setdefault('norm', matplotlib.colors.LogNorm(vmin, vmax))
324
+ vmin = kwargs.pop("vmin", None)
325
+ vmax = kwargs.pop("vmax", None)
326
+ kwargs.setdefault("norm", matplotlib.colors.LogNorm(vmin, vmax))
278
327
  mappable = axes.pcolormesh(*self._edges, self.content.T, **kwargs)
279
328
  plt.colorbar(mappable, ax=axes, label=self.axis_labels[2])
280
329
  setup_axes(axes, xlabel=self.axis_labels[0], ylabel=self.axis_labels[1])
aptapy/modeling.py CHANGED
@@ -23,17 +23,31 @@ from abc import ABC, abstractmethod
23
23
  from dataclasses import dataclass
24
24
  from itertools import chain
25
25
  from numbers import Number
26
- from typing import Callable, Iterator, Sequence, Tuple
26
+ from typing import Callable, Dict, Iterator, Sequence, Tuple
27
27
 
28
28
  import matplotlib.pyplot as plt
29
29
  import numpy as np
30
30
  import uncertainties
31
+ from scipy.integrate import quad
31
32
  from scipy.optimize import curve_fit
33
+ from scipy.special import erf
32
34
  from scipy.stats import chi2
33
35
 
34
36
  from .hist import Histogram1d
35
37
  from .typing_ import ArrayLike
36
38
 
39
+ __all__ = [
40
+ "Constant",
41
+ "Line",
42
+ "Quadratic",
43
+ "PowerLaw",
44
+ "Exponential",
45
+ "Gaussian",
46
+ "Erf",
47
+ "ErfInverse",
48
+ ]
49
+
50
+ # pylint: disable=too-many-lines
37
51
 
38
52
  class Format(str, enum.Enum):
39
53
 
@@ -277,6 +291,17 @@ class FitStatus:
277
291
  self.pvalue = None
278
292
  self.fit_range = None
279
293
 
294
+ def valid(self) -> bool:
295
+ """Return True if the fit status is valid, i.e., if the chisquare,
296
+ dof, and pvalue are all set.
297
+
298
+ Returns
299
+ -------
300
+ valid : bool
301
+ True if the fit status is valid.
302
+ """
303
+ return self.chisquare is not None and self.dof is not None and self.pvalue is not None
304
+
280
305
  def update(self, chisquare: float, dof: int = None) -> None:
281
306
  """Update the fit status, i.e., set the chisquare and calculate the
282
307
  corresponding p-value.
@@ -316,10 +341,10 @@ class FitStatus:
316
341
  if self.chisquare is None:
317
342
  return "N/A"
318
343
  if spec.endswith(Format.LATEX):
319
- return f"$\\chi^2$ = {self.chisquare:.2f} / {self.dof} dof"
344
+ return f"$\\chi^2$: {self.chisquare:.2f} / {self.dof} dof"
320
345
  if spec.endswith(Format.PRETTY):
321
- return f"χ² = {self.chisquare:.2f} / {self.dof} dof"
322
- return f"chisquare = {self.chisquare:.2f} / {self.dof} dof"
346
+ return f"χ²: {self.chisquare:.2f} / {self.dof} dof"
347
+ return f"chisquare: {self.chisquare:.2f} / {self.dof} dof"
323
348
 
324
349
  def __str__(self) -> str:
325
350
  """String formatting.
@@ -776,7 +801,7 @@ class AbstractFitModelBase(ABC):
776
801
  The formatted string.
777
802
  """
778
803
  text = f"{self.name()}\n"
779
- if self.status is not None:
804
+ if self.status.valid():
780
805
  text = f"{text}{format(self.status, spec)}\n"
781
806
  for parameter in self:
782
807
  text = f"{text}{format(parameter, spec)}\n"
@@ -807,13 +832,47 @@ class AbstractFitModel(AbstractFitModelBase):
807
832
  """
808
833
  super().__init__()
809
834
  self._parameters = []
810
- for name, value in self.__class__.__dict__.items():
811
- if isinstance(value, FitParameter):
812
- parameter = value.copy(name)
813
- # Note we also set one instance attribute for each parameter so
814
- # that we can use the notation model.parameter
815
- setattr(self, name, parameter)
816
- self._parameters.append(parameter)
835
+ # Note we cannot loop over self.__dict__.items() here, as that would
836
+ # only return the members defined in the actual class, and not the
837
+ # inherited ones.
838
+ for name, value in self.__class__._parameter_dict().items():
839
+ parameter = value.copy(name)
840
+ # Note we also set one instance attribute for each parameter so
841
+ # that we can use the notation model.parameter
842
+ setattr(self, name, parameter)
843
+ self._parameters.append(parameter)
844
+
845
+ @classmethod
846
+ def _parameter_dict(cls) -> Dict[str, FitParameter]:
847
+ """Return a dictionary of all the FitParameter objects defined in the class
848
+ and its base classes.
849
+
850
+ This is a subtle one, as what we really want, here, is all members of a class
851
+ (including inherited ones) that are of a specific type (FitParameter), in the
852
+ order they were defined. All of these thing are instrumental to make the
853
+ fit model work, so we need to be careful.
854
+
855
+ Also note the we are looping over the MRO in reverse order, so that we
856
+ preserve the order of definition of the parameters, even when they are
857
+ inherited from base classes. If a parameter is re-defined in a derived class,
858
+ the derived class definition takes precedence, as we are using a dictionary
859
+ to collect the parameters.
860
+
861
+ Arguments
862
+ ---------
863
+ cls : type
864
+ The class to inspect.
865
+
866
+ Returns
867
+ -------
868
+ param_dict : dict
869
+ A dictionary mapping parameter names to their FitParameter objects.
870
+ """
871
+ param_dict = {}
872
+ for base in reversed(cls.__mro__):
873
+ param_dict.update({name: value for name, value in base.__dict__.items() if
874
+ isinstance(value, FitParameter)})
875
+ return param_dict
817
876
 
818
877
  def __len__(self) -> int:
819
878
  """Return the `total` number of fit parameters in the model.
@@ -832,6 +891,46 @@ class AbstractFitModel(AbstractFitModelBase):
832
891
  raise TypeError(f"{other} is not a fit model")
833
892
  return FitModelSum(self, other)
834
893
 
894
+ def quadrature(self, xmin: float, xmax: float) -> float:
895
+ """Calculate the integral of the model between xmin and xmax using
896
+ numerical integration.
897
+
898
+ Arguments
899
+ ---------
900
+ xmin : float
901
+ The minimum value of the independent variable to integrate over.
902
+
903
+ xmax : float
904
+ The maximum value of the independent variable to integrate over.
905
+
906
+ Returns
907
+ -------
908
+ integral : float
909
+ The integral of the model between xmin and xmax.
910
+ """
911
+ value, _ = quad(self, xmin, xmax)
912
+ return value
913
+
914
+ def integral(self, xmin: float, xmax: float) -> float:
915
+ """Default implementation of the integral of the model between xmin and xmax.
916
+ Subclasses can (and are encouraged to) overload this method with an
917
+ analytical implementation, when available.
918
+
919
+ Arguments
920
+ ---------
921
+ xmin : float
922
+ The minimum value of the independent variable to integrate over.
923
+
924
+ xmax : float
925
+ The maximum value of the independent variable to integrate over.
926
+
927
+ Returns
928
+ -------
929
+ integral : float
930
+ The integral of the model between xmin and xmax.
931
+ """
932
+ return self.quadrature(xmin, xmax)
933
+
835
934
 
836
935
  class FitModelSum(AbstractFitModelBase):
837
936
 
@@ -878,6 +977,26 @@ class FitModelSum(AbstractFitModelBase):
878
977
  cursor += len(component)
879
978
  return value
880
979
 
980
+ def integral(self, xmin: float, xmax: float) -> float:
981
+ """Calculate the integral of the model between xmin and xmax.
982
+
983
+ This is implemented as the sum of the integrals of the components.
984
+
985
+ Arguments
986
+ ---------
987
+ xmin : float
988
+ The minimum value of the independent variable to integrate over.
989
+
990
+ xmax : float
991
+ The maximum value of the independent variable to integrate over.
992
+
993
+ Returns
994
+ -------
995
+ integral : float
996
+ The integral of the model between xmin and xmax.
997
+ """
998
+ return sum(component.integral(xmin, xmax) for component in self._components)
999
+
881
1000
  def plot(self, xmin: float = None, xmax: float = None, num_points: int = 200) -> None:
882
1001
  """Overloaded method for plotting the model.
883
1002
  """
@@ -931,8 +1050,13 @@ class Constant(AbstractFitModel):
931
1050
  @staticmethod
932
1051
  def evaluate(x: ArrayLike, value: float) -> ArrayLike:
933
1052
  # pylint: disable=arguments-differ
1053
+ if isinstance(x, Number):
1054
+ return value
934
1055
  return np.full(x.shape, value)
935
1056
 
1057
+ def integral(self, xmin: float, xmax: float) -> float:
1058
+ return self.value.value * (xmax - xmin)
1059
+
936
1060
 
937
1061
  class Line(AbstractFitModel):
938
1062
 
@@ -947,6 +1071,29 @@ class Line(AbstractFitModel):
947
1071
  # pylint: disable=arguments-differ
948
1072
  return slope * x + intercept
949
1073
 
1074
+ def integral(self, xmin: float, xmax: float) -> float:
1075
+ slope, intercept = self.parameter_values()
1076
+ return 0.5 * slope * (xmax**2 - xmin**2) + intercept * (xmax - xmin)
1077
+
1078
+
1079
+ class Quadratic(AbstractFitModel):
1080
+
1081
+ """Quadratic model.
1082
+ """
1083
+
1084
+ a = FitParameter(1.)
1085
+ b = FitParameter(1.)
1086
+ c = FitParameter(0.)
1087
+
1088
+ @staticmethod
1089
+ def evaluate(x: ArrayLike, a: float, b: float, c: float) -> ArrayLike:
1090
+ # pylint: disable=arguments-differ
1091
+ return a * x**2 + b * x + c
1092
+
1093
+ def integral(self, xmin: float, xmax: float) -> float:
1094
+ a, b, c = self.parameter_values()
1095
+ return a * (xmax**3 - xmin**3) / 3. + b * (xmax**2 - xmin**2) / 2. + c * (xmax - xmin)
1096
+
950
1097
 
951
1098
  class PowerLaw(AbstractFitModel):
952
1099
 
@@ -954,33 +1101,88 @@ class PowerLaw(AbstractFitModel):
954
1101
  """
955
1102
 
956
1103
  prefactor = FitParameter(1.)
957
- index = FitParameter(-1.)
1104
+ index = FitParameter(-2.)
958
1105
 
959
1106
  @staticmethod
960
1107
  def evaluate(x: ArrayLike, prefactor: float, index: float) -> ArrayLike:
961
1108
  # pylint: disable=arguments-differ
962
1109
  return prefactor * x**index
963
1110
 
1111
+ def integral(self, xmin: float, xmax: float) -> float:
1112
+ prefactor, index = self.parameter_values()
1113
+ if index == -1.:
1114
+ return prefactor * np.log(xmax / xmin)
1115
+ return prefactor / (index + 1.) * (xmax**(index + 1.) - xmin**(index + 1.))
964
1116
 
965
- class Gaussian(AbstractFitModel):
1117
+ def default_plotting_range(self) -> Tuple[float, float]:
1118
+ return (0.1, 10.)
966
1119
 
967
- """Gaussian model.
1120
+ def plot(self, xmin: float = None, xmax: float = None, num_points: int = 200) -> None:
1121
+ super().plot(xmin, xmax, num_points)
1122
+ plt.xscale("log")
1123
+ plt.yscale("log")
1124
+
1125
+
1126
+ class Exponential(AbstractFitModel):
1127
+
1128
+ """Exponential model.
1129
+ """
1130
+
1131
+ prefactor = FitParameter(1.)
1132
+ scale = FitParameter(1.)
1133
+
1134
+ @staticmethod
1135
+ def evaluate(x: ArrayLike, prefactor: float, scale: float) -> ArrayLike:
1136
+ # pylint: disable=arguments-differ
1137
+ return prefactor * np.exp(-x / scale)
1138
+
1139
+ def integral(self, xmin: float, xmax: float) -> float:
1140
+ prefactor, scale = self.parameter_values()
1141
+ return prefactor * scale * (np.exp(-xmin / scale) - np.exp(-xmax / scale))
1142
+
1143
+ def default_plotting_range(self, scale_factor: int = 5) -> Tuple[float, float]:
1144
+ return (0., scale_factor * self.scale.value)
1145
+
1146
+
1147
+ class _GaussianBase(AbstractFitModel):
1148
+
1149
+ """Common base class for Gaussian-like models.
1150
+
1151
+ This provides a couple of convenience methods that are useful for all the
1152
+ models derived from a gaussian (e.g., the gaussian itself, the error function,
1153
+ and its inverse). Note that, for the right method to be picked up,
1154
+ subclasses should derive from this class *before* deriving from
1155
+ AbstractFitModel, so that the method resolution order (MRO) works as expected.
1156
+
1157
+ Note the evaluate() method is not implemented here, which means that the class
1158
+ cannot be instantiated directly.
968
1159
  """
969
1160
 
970
1161
  prefactor = FitParameter(1.)
971
1162
  mean = FitParameter(0.)
972
1163
  sigma = FitParameter(1., minimum=0.)
973
1164
 
1165
+ # A few useful constants.
1166
+ _SQRT2 = np.sqrt(2.)
974
1167
  _NORM_CONSTANT = 1. / np.sqrt(2. * np.pi)
975
1168
  _SIGMA_TO_FWHM = 2. * np.sqrt(2. * np.log(2.))
976
1169
 
977
- @staticmethod
978
- def evaluate(x: ArrayLike, prefactor: float, mean: float, sigma: float) -> ArrayLike:
979
- # pylint: disable=arguments-differ
980
- z = (x - mean) / sigma
981
- return prefactor * Gaussian._NORM_CONSTANT / sigma * np.exp(-0.5 * z**2.)
982
-
983
1170
  def default_plotting_range(self, num_sigma: int = 5) -> Tuple[float, float]:
1171
+ """Convenience function to return a default plotting range for all the
1172
+ models derived from a gaussian (e.g., the gaussian itself, the error
1173
+ function, and its inverse).
1174
+
1175
+ Arguments
1176
+ ---------
1177
+ num_sigma : int, optional
1178
+ The number of sigmas to use for the plotting range (default 5).
1179
+
1180
+ Returns
1181
+ -------
1182
+ Tuple[float, float]
1183
+ The default plotting range for the model.
1184
+ """
1185
+ # pylint: disable=no-member
984
1186
  mean, half_width = self.mean.value, num_sigma * self.sigma.value
985
1187
  return (mean - half_width, mean + half_width)
986
1188
 
@@ -992,4 +1194,46 @@ class Gaussian(AbstractFitModel):
992
1194
  fwhm : uncertainties.ufloat
993
1195
  The FWHM of the gaussian.
994
1196
  """
1197
+ # pylint: disable=no-member
995
1198
  return self.sigma.ufloat() * self._SIGMA_TO_FWHM
1199
+
1200
+
1201
+ class Gaussian(_GaussianBase):
1202
+
1203
+ """Gaussian model.
1204
+ """
1205
+
1206
+ @staticmethod
1207
+ def evaluate(x: ArrayLike, prefactor: float, mean: float, sigma: float) -> ArrayLike:
1208
+ # pylint: disable=arguments-differ
1209
+ z = (x - mean) / sigma
1210
+ return prefactor * _GaussianBase._NORM_CONSTANT / sigma * np.exp(-0.5 * z**2.)
1211
+
1212
+ def integral(self, xmin: float, xmax: float) -> float:
1213
+ prefactor, mean, sigma = self.parameter_values()
1214
+ zmin = (xmin - mean) / (sigma * self._SQRT2)
1215
+ zmax = (xmax - mean) / (sigma * self._SQRT2)
1216
+ return prefactor * 0.5 * (erf(zmax) - erf(zmin))
1217
+
1218
+
1219
+ class Erf(_GaussianBase):
1220
+
1221
+ """Error function model.
1222
+ """
1223
+
1224
+ @staticmethod
1225
+ def evaluate(x: ArrayLike, prefactor: float, mean: float, sigma: float) -> ArrayLike:
1226
+ # pylint: disable=arguments-differ
1227
+ z = (x - mean) / sigma
1228
+ return prefactor * 0.5 * (1. + erf(z / _GaussianBase._SQRT2))
1229
+
1230
+
1231
+ class ErfInverse(_GaussianBase):
1232
+
1233
+ """Inverse error function model.
1234
+ """
1235
+
1236
+ @staticmethod
1237
+ def evaluate(x: ArrayLike, prefactor: float, mean: float, sigma: float) -> ArrayLike:
1238
+ # pylint: disable=arguments-differ
1239
+ return prefactor - Erf.evaluate(x, prefactor, mean, sigma)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aptapy
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: Statistical tools for online monitoring and analysis
5
5
  Project-URL: Homepage, https://github.com/lucabaldini/aptapy
6
6
  Project-URL: Issues, https://github.com/lucabaldini/aptapy/issues
@@ -713,7 +713,6 @@ Description-Content-Type: text/markdown
713
713
  ![License](https://img.shields.io/github/license/lucabaldini/aptapy.svg)
714
714
  [![CI](https://github.com/lucabaldini/aptapy/actions/workflows/ci.yml/badge.svg)](https://github.com/lucabaldini/aptapy/actions/workflows/ci.yml)
715
715
  [![Docs](https://github.com/lucabaldini/aptapy/actions/workflows/docs.yml/badge.svg)](https://github.com/lucabaldini/aptapy/actions/workflows/docs.yml)
716
- [![Docs](https://img.shields.io/badge/docs-latest-blue.svg)](https://lucabaldini.github.io/aptapy/)
717
716
  ![GitHub last commit](https://img.shields.io/github/last-commit/lucabaldini/aptapy)
718
717
 
719
718
  [![Ceasefire Now](https://badge.techforpalestine.org/default)](https://techforpalestine.org/learn-more)
@@ -0,0 +1,12 @@
1
+ aptapy/__init__.py,sha256=a7Au1ukdeJbjiIZ-UL-qZE1xk-d2WnKKkoqjg_0SzqA,1707
2
+ aptapy/_version.py,sha256=42STGor_9nKYXumfeV5tiyD_M8VdcddX7CEexmibPBk,22
3
+ aptapy/hist.py,sha256=pUiXtBGKrFo38ZgoiZ1WQSZSSatQb62RJw83mI9i05k,11586
4
+ aptapy/modeling.py,sha256=-6t9H3nNsxiEQwW40_yXFVj8oGlsdN6DsEkJa19Rtus,40717
5
+ aptapy/plotting.py,sha256=p9YNdrcFcTimRCtoXcV3zORaEd4EfMtsDd4ETxGKKHM,27483
6
+ aptapy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ aptapy/strip.py,sha256=qGsVXWp-Dz-lz7KQxktMifUTNkSxh8ZQwYme8_bealQ,3026
8
+ aptapy/typing_.py,sha256=JIbEqKI8kn_fd90yDt0JmI1AojjmLhAEB_1RfMFxLx4,807
9
+ aptapy-0.4.0.dist-info/METADATA,sha256=eHypCTZ4_IBaHkepwTUOgNhVMrJP5Rj_MNsQ1ibGtnM,42696
10
+ aptapy-0.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
11
+ aptapy-0.4.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
12
+ aptapy-0.4.0.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- aptapy/__init__.py,sha256=a7Au1ukdeJbjiIZ-UL-qZE1xk-d2WnKKkoqjg_0SzqA,1707
2
- aptapy/_version.py,sha256=r4xAFihOf72W9TD-lpMi6ntWSTKTP2SlzKP1ytkjRbI,22
3
- aptapy/hist.py,sha256=jvHULR2lW_gyoemNaRI-vpqhFqmLLCB319CaKjwU69E,9752
4
- aptapy/modeling.py,sha256=mHHHFMYmMuXTRQD2yR1XLM6E4KaBk8md7Z7dDp5ReD8,32566
5
- aptapy/plotting.py,sha256=p9YNdrcFcTimRCtoXcV3zORaEd4EfMtsDd4ETxGKKHM,27483
6
- aptapy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- aptapy/strip.py,sha256=qGsVXWp-Dz-lz7KQxktMifUTNkSxh8ZQwYme8_bealQ,3026
8
- aptapy/typing_.py,sha256=JIbEqKI8kn_fd90yDt0JmI1AojjmLhAEB_1RfMFxLx4,807
9
- aptapy-0.3.1.dist-info/METADATA,sha256=KZP-aljwTsIKUi-1nE-X9ZfIxc44ijFhKCkoyK0EXjY,42796
10
- aptapy-0.3.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
11
- aptapy-0.3.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
12
- aptapy-0.3.1.dist-info/RECORD,,
File without changes