richvalues 4.0.6__tar.gz → 4.1.0__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.
- {richvalues-4.0.6 → richvalues-4.1.0}/PKG-INFO +1 -1
- {richvalues-4.0.6 → richvalues-4.1.0}/pyproject.toml +1 -1
- {richvalues-4.0.6 → richvalues-4.1.0}/richvalues/__init__.py +208 -70
- {richvalues-4.0.6 → richvalues-4.1.0}/richvalues.egg-info/PKG-INFO +1 -1
- {richvalues-4.0.6 → richvalues-4.1.0}/setup.py +1 -1
- {richvalues-4.0.6 → richvalues-4.1.0}/LICENSE +0 -0
- {richvalues-4.0.6 → richvalues-4.1.0}/README.md +0 -0
- {richvalues-4.0.6 → richvalues-4.1.0}/richvalues.egg-info/SOURCES.txt +0 -0
- {richvalues-4.0.6 → richvalues-4.1.0}/richvalues.egg-info/dependency_links.txt +0 -0
- {richvalues-4.0.6 → richvalues-4.1.0}/richvalues.egg-info/requires.txt +0 -0
- {richvalues-4.0.6 → richvalues-4.1.0}/richvalues.egg-info/top_level.txt +0 -0
- {richvalues-4.0.6 → richvalues-4.1.0}/setup.cfg +0 -0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "richvalues"
|
7
|
-
version = "4.0
|
7
|
+
version = "4.1.0"
|
8
8
|
description = "Python library for working with uncertainties and upper/lower limits"
|
9
9
|
license = {file="LICENSE"}
|
10
10
|
authors = [{name="Andrés Megías Toledano"}]
|
@@ -4,7 +4,7 @@
|
|
4
4
|
"""
|
5
5
|
Rich Values Library
|
6
6
|
-------------------
|
7
|
-
Version 4.
|
7
|
+
Version 4.1
|
8
8
|
|
9
9
|
Copyright (C) 2024 - Andrés Megías Toledano
|
10
10
|
|
@@ -37,7 +37,7 @@ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
37
37
|
POSSIBILITY OF SUCH DAMAGE.
|
38
38
|
"""
|
39
39
|
|
40
|
-
__version__ = '4.0
|
40
|
+
__version__ = '4.1.0'
|
41
41
|
__author__ = 'Andrés Megías Toledano'
|
42
42
|
|
43
43
|
import copy
|
@@ -57,6 +57,7 @@ defaultparams = {
|
|
57
57
|
'size of samples': int(8e3),
|
58
58
|
'number of significant figures': 1,
|
59
59
|
'minimum exponent for scientific notation': 4,
|
60
|
+
'maximum number of decimals': 5,
|
60
61
|
'limit for extra significant figure': 2.5,
|
61
62
|
'use extra significant figure for exact values': True,
|
62
63
|
'use extra significant figure for finite intervals': True,
|
@@ -174,7 +175,7 @@ def round_sf(x, n=None, min_exp=None, extra_sf_lim=None):
|
|
174
175
|
y = y.replace('e+','e').replace('e00','e0')
|
175
176
|
return y
|
176
177
|
|
177
|
-
def round_sf_unc(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
178
|
+
def round_sf_unc(x, dx, n=None, min_exp=None, max_dec=None, extra_sf_lim=None):
|
178
179
|
"""
|
179
180
|
Round a value and its uncertainty depending on their significant figures.
|
180
181
|
|
@@ -189,6 +190,9 @@ def round_sf_unc(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
|
189
190
|
min_exp : int, optional
|
190
191
|
Minimum decimal exponent, in absolute value, to display the values in
|
191
192
|
scientific notation. The default is 4.
|
193
|
+
max_dec : int, optional
|
194
|
+
Maximum number of decimals, to use the notation with parenthesis.
|
195
|
+
The default is 5.
|
192
196
|
extra_sf_lim : float, optional
|
193
197
|
If the number expressed in scientific notation has a base that is lower
|
194
198
|
than this value, an additional significant figure will be used.
|
@@ -202,10 +206,9 @@ def round_sf_unc(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
|
202
206
|
Rounded uncertainty.
|
203
207
|
"""
|
204
208
|
n = set_default_value(n, 'number of significant figures')
|
205
|
-
min_exp = set_default_value(min_exp,
|
206
|
-
|
207
|
-
extra_sf_lim = set_default_value(extra_sf_lim,
|
208
|
-
'limit for extra significant figure')
|
209
|
+
min_exp = set_default_value(min_exp, 'minimum exponent for scientific notation')
|
210
|
+
max_dec = set_default_value(max_dec, 'maximum number of decimals')
|
211
|
+
extra_sf_lim = set_default_value(extra_sf_lim, 'limit for extra significant figure')
|
209
212
|
use_exp = True
|
210
213
|
if ((float(x) > float(dx)
|
211
214
|
and all(abs(np.floor(_log10(abs(np.array([x, dx]))))) < min_exp))
|
@@ -269,7 +272,7 @@ def round_sf_unc(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
|
269
272
|
y = '{}e{}'.format(base_y, exp_dy)
|
270
273
|
else:
|
271
274
|
f = 10**(-int(exp_y))
|
272
|
-
base_y, dy = round_sf_unc(x*f, dx*f, n, np.inf, extra_sf_lim)
|
275
|
+
base_y, dy = round_sf_unc(x*f, dx*f, n, np.inf, max_dec, extra_sf_lim)
|
273
276
|
y = '{}e{}'.format(base_y, exp_y)
|
274
277
|
elif dx == 0:
|
275
278
|
y = round_sf(x, n, min_exp, extra_sf_lim)
|
@@ -290,12 +293,24 @@ def round_sf_unc(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
|
290
293
|
if abs(exp) < min_exp:
|
291
294
|
x = float(sign + str(x))
|
292
295
|
min_exp = np.inf
|
293
|
-
y, dy = round_sf_unc(x, dx, n, min_exp, extra_sf_lim)
|
296
|
+
y, dy = round_sf_unc(x, dx, n, min_exp, max_dec, extra_sf_lim)
|
294
297
|
y = y.replace('e+', 'e').replace('e00', 'e0')
|
295
298
|
dy = dy.replace('e+','e').replace('e00', 'e0')
|
299
|
+
d = len(y.split('e')[0].split('.')[-1])
|
300
|
+
if d > max_dec and ')' not in dy:
|
301
|
+
if 'e' in y:
|
302
|
+
y, exp = y.split('e')
|
303
|
+
dy, _ = dy.split('e')
|
304
|
+
else:
|
305
|
+
exp = None
|
306
|
+
d = len(y.split('.')[-1])
|
307
|
+
dy_ = round_sf(float(dy)*10**d, n, min_exp=np.inf, extra_sf_lim=0.)
|
308
|
+
dy = '(' + dy_.split('e')[0] + ')'
|
309
|
+
if exp is not None:
|
310
|
+
y = '{}e{}'.format(y, exp)
|
296
311
|
return y, dy
|
297
312
|
|
298
|
-
def round_sf_uncs(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
313
|
+
def round_sf_uncs(x, dx, n=None, min_exp=None, max_dec=None, extra_sf_lim=None):
|
299
314
|
"""
|
300
315
|
Round a value and its uncertainties depending on their significant figures.
|
301
316
|
|
@@ -310,6 +325,9 @@ def round_sf_uncs(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
|
310
325
|
min_exp : int, optional
|
311
326
|
Minimum decimal exponent, in absolute value, to apply scientific
|
312
327
|
notation. The default is 4.
|
328
|
+
max_dec : int, optional
|
329
|
+
Maximum number of decimals, to apply notation with parenthesis.
|
330
|
+
The default is 5.
|
313
331
|
extra_sf_lim : float, optional
|
314
332
|
If the number expressed in scientific notation has a base that is lower
|
315
333
|
than this value, an additional significant figure will be used.
|
@@ -323,19 +341,18 @@ def round_sf_uncs(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
|
323
341
|
Rounded uncertainties.
|
324
342
|
"""
|
325
343
|
n = set_default_value(n, 'number of significant figures')
|
326
|
-
min_exp = set_default_value(min_exp,
|
327
|
-
|
328
|
-
extra_sf_lim = set_default_value(extra_sf_lim,
|
329
|
-
'limit for extra significant figure')
|
344
|
+
min_exp = set_default_value(min_exp, 'minimum exponent for scientific notation')
|
345
|
+
max_dec = set_default_value(max_dec, 'maximum number of decimals')
|
346
|
+
extra_sf_lim = set_default_value(extra_sf_lim, 'limit for extra significant figure')
|
330
347
|
dx1, dx2 = dx
|
331
|
-
y1, dy1 = round_sf_unc(x, dx1, n, min_exp, extra_sf_lim)
|
332
|
-
y2, dy2 = round_sf_unc(x, dx2, n, min_exp, extra_sf_lim)
|
348
|
+
y1, dy1 = round_sf_unc(x, dx1, n, min_exp, max_dec, extra_sf_lim)
|
349
|
+
y2, dy2 = round_sf_unc(x, dx2, n, min_exp, max_dec, extra_sf_lim)
|
333
350
|
num_dec_1 = len(y1.split('e')[0].split('.')[1]) if '.' in y1 else 0
|
334
351
|
num_dec_2 = len(y2.split('e')[0].split('.')[1]) if '.' in y2 else 0
|
335
352
|
if num_dec_2 > num_dec_1:
|
336
353
|
diff = num_dec_2 - num_dec_1
|
337
|
-
y1, dy1 = round_sf_unc(x, dx1, n+diff, min_exp, extra_sf_lim)
|
338
|
-
y2, dy2 = round_sf_unc(x, dx2, n, min_exp, extra_sf_lim)
|
354
|
+
y1, dy1 = round_sf_unc(x, dx1, n+diff, min_exp, max_dec, extra_sf_lim)
|
355
|
+
y2, dy2 = round_sf_unc(x, dx2, n, min_exp, max_dec, extra_sf_lim)
|
339
356
|
else:
|
340
357
|
diff = num_dec_1 - num_dec_2
|
341
358
|
off1, off2 = 0, 0
|
@@ -348,9 +365,23 @@ def round_sf_uncs(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
|
348
365
|
off2 = 1
|
349
366
|
if dx1 > dx2 and b2 <= extra_sf_lim and b1 > extra_sf_lim:
|
350
367
|
off1 = 1
|
351
|
-
y1, dy1 = round_sf_unc(x, dx1, n+off1, min_exp, extra_sf_lim)
|
352
|
-
y2, dy2 = round_sf_unc(x, dx2, n+diff+off2, min_exp, extra_sf_lim)
|
368
|
+
y1, dy1 = round_sf_unc(x, dx1, n+off1, min_exp, max_dec, extra_sf_lim)
|
369
|
+
y2, dy2 = round_sf_unc(x, dx2, n+diff+off2, min_exp, max_dec, extra_sf_lim)
|
353
370
|
y = y1 if dx2 > dx1 else y2
|
371
|
+
if dy1 != dy2 and (')' in dy1 or ')' in dy2):
|
372
|
+
dy1 = dy1.replace('(', '(-')
|
373
|
+
dy2 = dy2.replace('(', '(+')
|
374
|
+
if ')' in dy1 and ')' not in dy2 or ')' in dy2 and '.' in dy2:
|
375
|
+
_, dy2 = round_sf_unc(x, dx[1], n, min_exp, max_dec-1, extra_sf_lim)
|
376
|
+
dy2 = '(' + dy2[1:-1] + '0' + ')'
|
377
|
+
elif ')' in dy2 and ')' not in dy1 or ')' in dy1 and '.' in dy1:
|
378
|
+
_, dy1 = round_sf_unc(x, dx[0], n, min_exp, max_dec-1, extra_sf_lim)
|
379
|
+
dy1 = '(' + dy1[1:-1] + '0' + ')'
|
380
|
+
if ')' in dy1 or ')' in dy2:
|
381
|
+
if not dy1.startswith('(-'):
|
382
|
+
dy1 = '(-' + dy1[1:]
|
383
|
+
if not dy2.startswith('(+'):
|
384
|
+
dy2 = '(+' + dy2[1:]
|
354
385
|
dy = [dy1, dy2]
|
355
386
|
return y, dy
|
356
387
|
|
@@ -533,6 +564,7 @@ class RichValue():
|
|
533
564
|
self.domain = domain
|
534
565
|
self.num_sf = defaultparams['number of significant figures']
|
535
566
|
self.min_exp = defaultparams['minimum exponent for scientific notation']
|
567
|
+
self.max_dec = defaultparams['maximum number of decimals']
|
536
568
|
self.extra_sf_lim = defaultparams['limit for extra significant figure']
|
537
569
|
self.pdf_info = 'default'
|
538
570
|
self.variables = variables
|
@@ -719,10 +751,10 @@ class RichValue():
|
|
719
751
|
domain = copy.copy(self.domain)
|
720
752
|
is_int = self.is_int
|
721
753
|
min_exp = abs(self.min_exp)
|
754
|
+
max_dec = abs(self.max_dec)
|
722
755
|
extra_sf_lim = self.extra_sf_lim
|
723
756
|
show_domain = defaultparams['show domain']
|
724
|
-
show_asterisk = defaultparams['show asterisk for rich values with'
|
725
|
-
' custom PDF']
|
757
|
+
show_asterisk = defaultparams['show asterisk for rich values with custom PDF']
|
726
758
|
use_extra_sf_in_exacts = \
|
727
759
|
defaultparams['use extra significant figure for exact values']
|
728
760
|
use_extra_sf_in_ranges = \
|
@@ -739,7 +771,7 @@ class RichValue():
|
|
739
771
|
else False)
|
740
772
|
use_exp = True
|
741
773
|
if ((self.is_centr and 'e' not in
|
742
|
-
str(round_sf_uncs(x, dx, n, min_exp, extra_sf_lim)))
|
774
|
+
str(round_sf_uncs(x, dx, n, min_exp, max_dec, extra_sf_lim)))
|
743
775
|
or self.is_lim and abs(np.floor(_log10(abs(float(x))) < min_exp))
|
744
776
|
or np.isinf(min_exp)):
|
745
777
|
use_exp = False
|
@@ -750,8 +782,8 @@ class RichValue():
|
|
750
782
|
if (not range_bound and use_extra_sf_in_exacts
|
751
783
|
or range_bound and use_extra_sf_in_ranges):
|
752
784
|
n += 1
|
753
|
-
y, (dy1, dy2) = round_sf_uncs(x, [dx1, dx2], n,
|
754
|
-
|
785
|
+
y, (dy1, dy2) = round_sf_uncs(x, [dx1, dx2], n, min_exp,
|
786
|
+
max_dec, extra_sf_lim)
|
755
787
|
if 'e' in y:
|
756
788
|
y, a = y.split('e')
|
757
789
|
a = int(a)
|
@@ -761,14 +793,20 @@ class RichValue():
|
|
761
793
|
dy1, _ = dy1.split('e')
|
762
794
|
if 'e' in dy2:
|
763
795
|
dy2, _ = dy2.split('e')
|
764
|
-
if
|
765
|
-
if
|
766
|
-
|
796
|
+
if ')' not in dy1:
|
797
|
+
if dy1 == dy2:
|
798
|
+
if float(dy1) != 0:
|
799
|
+
text = '{}+/-{} e{}'.format(y, dy1, a)
|
800
|
+
else:
|
801
|
+
y = int(round(float(y))) if is_int else y
|
802
|
+
text = '{} e{}'.format(y, a)
|
767
803
|
else:
|
768
|
-
|
769
|
-
text = '{} e{}'.format(y, a)
|
804
|
+
text = '{}-{}+{} e{}'.format(y, dy1, dy2, a)
|
770
805
|
else:
|
771
|
-
|
806
|
+
if dy1 == dy2:
|
807
|
+
text = '{}{} e{}'.format(y, dy1, a)
|
808
|
+
else:
|
809
|
+
text = '{}{}{} e{}'.format(y, dy1, dy2, a)
|
772
810
|
if not use_exp:
|
773
811
|
text = text.replace(' e0','')
|
774
812
|
else:
|
@@ -851,6 +889,7 @@ class RichValue():
|
|
851
889
|
is_range = self.is_range
|
852
890
|
is_int = self.is_int
|
853
891
|
min_exp = abs(self.min_exp)
|
892
|
+
max_dec = abs(self.max_dec)
|
854
893
|
extra_sf_lim = self.extra_sf_lim
|
855
894
|
show_domain = defaultparams['show domain']
|
856
895
|
use_exp = True
|
@@ -874,7 +913,7 @@ class RichValue():
|
|
874
913
|
else False)
|
875
914
|
if is_numeric:
|
876
915
|
if not is_range:
|
877
|
-
_, unc_r = round_sf_uncs(x, dx, n, min_exp, extra_sf_lim)
|
916
|
+
_, unc_r = round_sf_uncs(x, dx, n, min_exp, np.inf, extra_sf_lim)
|
878
917
|
unc_r = np.array(unc_r, float)
|
879
918
|
if not is_range and not use_exp:
|
880
919
|
if not self.is_lim:
|
@@ -886,11 +925,11 @@ class RichValue():
|
|
886
925
|
round_sf(x, n, np.inf, extra_sf_lim))
|
887
926
|
text = '${}$'.format(y)
|
888
927
|
else:
|
889
|
-
y, dy = round_sf_unc(x, dx[0], n,
|
890
|
-
|
928
|
+
y, dy = round_sf_unc(x, dx[0], n, min_exp,
|
929
|
+
max_dec, extra_sf_lim)
|
891
930
|
text = '${} \pm {}$'.format(y, dy)
|
892
931
|
else:
|
893
|
-
y, dy = round_sf_uncs(x, dx, n, min_exp, extra_sf_lim)
|
932
|
+
y, dy = round_sf_uncs(x, dx, n, min_exp, max_dec, extra_sf_lim)
|
894
933
|
text = '$'+y + '_{-'+dy[0]+'}^{+'+dy[1]+'}$'
|
895
934
|
else:
|
896
935
|
if is_lolim:
|
@@ -918,8 +957,8 @@ class RichValue():
|
|
918
957
|
text = ('${} {}'.format(y, mult_symbol)
|
919
958
|
+ ' 10^{'+a+'}$')
|
920
959
|
else:
|
921
|
-
y, dy = round_sf_unc(x, dx[0], n,
|
922
|
-
|
960
|
+
y, dy = round_sf_unc(x, dx[0], n, min_exp,
|
961
|
+
max_dec, extra_sf_lim)
|
923
962
|
if 'e' in y:
|
924
963
|
y, a = y.split('e')
|
925
964
|
dy, a = dy.split('e')
|
@@ -929,8 +968,8 @@ class RichValue():
|
|
929
968
|
text = ('$({} \pm {}) '.format(y, dy)
|
930
969
|
+ mult_symbol + ' 10^{'+a+'}$')
|
931
970
|
else:
|
932
|
-
y, dy = round_sf_uncs(x, [dx[0], dx[1]], n,
|
933
|
-
|
971
|
+
y, dy = round_sf_uncs(x, [dx[0], dx[1]], n, min_exp,
|
972
|
+
max_dec, extra_sf_lim)
|
934
973
|
if 'e' in y:
|
935
974
|
y, a = y.split('e')
|
936
975
|
dy1, a = dy[0].split('e')
|
@@ -1456,6 +1495,11 @@ class RichValue():
|
|
1456
1495
|
@minimum_exponent_for_scientific_notation.setter
|
1457
1496
|
def minimum_exponent_for_scientific_notation(self, x): self.min_exp = x
|
1458
1497
|
|
1498
|
+
@property
|
1499
|
+
def maximum_number_of_decimals(self): return self.max_dec
|
1500
|
+
@maximum_number_of_decimals.setter
|
1501
|
+
def maximum_number_of_decimals(self, x): self.max_dec = x
|
1502
|
+
|
1459
1503
|
@property
|
1460
1504
|
def limit_for_extra_significant_figure(self): return self.extra_sf_lim
|
1461
1505
|
@limit_for_extra_significant_figure.setter
|
@@ -1646,6 +1690,9 @@ class RichArray(np.ndarray):
|
|
1646
1690
|
def min_exps(self):
|
1647
1691
|
return np.array([x.min_exp for x in self.flat]).reshape(self.shape)
|
1648
1692
|
@property
|
1693
|
+
def max_decs(self):
|
1694
|
+
return np.array([x.max_dec for x in self.flat]).reshape(self.shape)
|
1695
|
+
@property
|
1649
1696
|
def extra_sf_lims(self):
|
1650
1697
|
return np.array([x.extra_sf_lim for x in self.flat]).reshape(self.shape)
|
1651
1698
|
@property
|
@@ -1664,6 +1711,12 @@ class RichArray(np.ndarray):
|
|
1664
1711
|
def are_consts(self):
|
1665
1712
|
return np.array([x.is_const for x in self.flat]).reshape(self.shape)
|
1666
1713
|
@property
|
1714
|
+
def are_nans(self):
|
1715
|
+
return np.array([x.is_nan for x in self.flat]).reshape(self.shape)
|
1716
|
+
@property
|
1717
|
+
def are_infs(self):
|
1718
|
+
return np.array([x.is_inf for x in self.flat]).reshape(self.shape)
|
1719
|
+
@property
|
1667
1720
|
def centers(self):
|
1668
1721
|
return np.array([x.center for x in self.flat]).reshape(self.shape)
|
1669
1722
|
@property
|
@@ -1742,6 +1795,7 @@ class RichArray(np.ndarray):
|
|
1742
1795
|
abbreviations = {'is integer': 'is_int',
|
1743
1796
|
'number of significant figures': 'num_sf',
|
1744
1797
|
'minimum exponent for scientific notation': 'min_exp',
|
1798
|
+
'maximum number of decimals': 'max_dec',
|
1745
1799
|
'limit for extra significant figure': 'extra_sf_lim'}
|
1746
1800
|
attributes = ['domain'] + list(abbreviations.values())
|
1747
1801
|
for entry in abbreviations:
|
@@ -1761,6 +1815,8 @@ class RichArray(np.ndarray):
|
|
1761
1815
|
x.num_sf = params['num_sf']
|
1762
1816
|
if 'min_exp' in params:
|
1763
1817
|
x.min_exp = params['min_exp']
|
1818
|
+
if 'max_dec' in params:
|
1819
|
+
x.max_dec = params['max_dec']
|
1764
1820
|
if 'extra_sf_lim' in params:
|
1765
1821
|
x.extra_sf_lim = params['extra_sf_lim']
|
1766
1822
|
|
@@ -1803,8 +1859,7 @@ class RichArray(np.ndarray):
|
|
1803
1859
|
return np.array(self).mean()
|
1804
1860
|
|
1805
1861
|
def std(self):
|
1806
|
-
std_function = lambda u: (np.sum((u
|
1807
|
-
/ len(self - 1))**0.5
|
1862
|
+
std_function = lambda u: (np.sum((u-u.mean())**2)/(len(self)-1))**0.5
|
1808
1863
|
return self.function(std_function)
|
1809
1864
|
|
1810
1865
|
# Attribute acronyms.
|
@@ -1816,11 +1871,14 @@ class RichArray(np.ndarray):
|
|
1816
1871
|
are_integers = are_ints
|
1817
1872
|
numbers_of_significant_figures = nums_sf
|
1818
1873
|
minimum_exponents_for_scientific_notation = min_exps
|
1874
|
+
maximum_number_of_decimals = max_decs
|
1819
1875
|
limits_for_extra_significant_figure = extra_sf_lims
|
1820
1876
|
are_limits = are_lims
|
1821
1877
|
are_intervals = are_intervs
|
1822
1878
|
are_centereds = are_centrs
|
1823
1879
|
are_constants = are_consts
|
1880
|
+
are_not_a_number = are_nans
|
1881
|
+
are_infinites = are_infs
|
1824
1882
|
relative_uncertainties = rel_uncs
|
1825
1883
|
signals_to_noises = signals_noises
|
1826
1884
|
amplitudes = ampls
|
@@ -1909,6 +1967,8 @@ class RichDataFrame(pd.DataFrame):
|
|
1909
1967
|
@property
|
1910
1968
|
def min_exps(self): return self._property('min_exps')
|
1911
1969
|
@property
|
1970
|
+
def max_decs(self): return self._property('max_decs')
|
1971
|
+
@property
|
1912
1972
|
def extra_sf_lims(self): return self._property('extra_sf_lims')
|
1913
1973
|
@property
|
1914
1974
|
def are_lims(self): return self._property('are_lims')
|
@@ -1921,6 +1981,10 @@ class RichDataFrame(pd.DataFrame):
|
|
1921
1981
|
@property
|
1922
1982
|
def are_consts(self): return self._property('are_consts')
|
1923
1983
|
@property
|
1984
|
+
def are_nans(self): return self._property('are_nans')
|
1985
|
+
@property
|
1986
|
+
def are_infs(self): return self._property('are_infs')
|
1987
|
+
@property
|
1924
1988
|
def centers(self): return self._property('centers')
|
1925
1989
|
@property
|
1926
1990
|
def rel_uncs(self): return self._property2('rel_uncs')
|
@@ -1968,6 +2032,7 @@ class RichDataFrame(pd.DataFrame):
|
|
1968
2032
|
abbreviations = {'is integer': 'is_int',
|
1969
2033
|
'number of significant figures': 'num_sf',
|
1970
2034
|
'minimum exponent for scientific notation': 'min_exp',
|
2035
|
+
'maximum number of decimals': 'max_dec',
|
1971
2036
|
'limit for extra significant figure': 'extra_sf_lim'}
|
1972
2037
|
attributes = ['domain'] + list(abbreviations.values())
|
1973
2038
|
for entry in abbreviations:
|
@@ -1988,6 +2053,7 @@ class RichDataFrame(pd.DataFrame):
|
|
1988
2053
|
set_is_int = 'is_int' in params
|
1989
2054
|
set_num_sf = 'num_sf' in params
|
1990
2055
|
set_min_exp = 'min_exp' in params
|
2056
|
+
set_max_dec = 'max_dec' in params
|
1991
2057
|
set_extra_sf_lim = 'extra_sf_lim' in params
|
1992
2058
|
row_inds = self.index
|
1993
2059
|
for col in self:
|
@@ -2006,6 +2072,9 @@ class RichDataFrame(pd.DataFrame):
|
|
2006
2072
|
if set_min_exp and col in params['min_exp']:
|
2007
2073
|
for i in row_inds:
|
2008
2074
|
self[col][i].min_exp = params['min_exp'][col]
|
2075
|
+
if set_max_dec and col in params['max_dec']:
|
2076
|
+
for i in row_inds:
|
2077
|
+
self[col][i].max_dec = params['max_dec'][col]
|
2009
2078
|
if set_extra_sf_lim and col in params['extra_sf_lim']:
|
2010
2079
|
for i in row_inds:
|
2011
2080
|
self[col][i].extra_sf_lim = params['extra_sf_lim'][col]
|
@@ -2064,7 +2133,8 @@ class RichDataFrame(pd.DataFrame):
|
|
2064
2133
|
new_row = pd.DataFrame(new_row, idex=[0])
|
2065
2134
|
return new_row
|
2066
2135
|
|
2067
|
-
def latex(self, return_df=False,
|
2136
|
+
def latex(self, return_df=False, export_frame=True, export_index=True,
|
2137
|
+
row_sep='\\tabularnewline', **kwargs):
|
2068
2138
|
"""Return the content of the dataframe as a table in LaTeX format."""
|
2069
2139
|
row_sep = ' ' + row_sep + ' \n'
|
2070
2140
|
df = copy.copy(self)
|
@@ -2079,17 +2149,35 @@ class RichDataFrame(pd.DataFrame):
|
|
2079
2149
|
if return_df:
|
2080
2150
|
output = df
|
2081
2151
|
else:
|
2152
|
+
columns = list(df.columns)
|
2153
|
+
num_columns = len(columns)
|
2082
2154
|
text = ''
|
2155
|
+
if export_frame:
|
2156
|
+
text += '\\renewcommand*{\\arraystretch}{1.4}' + ' \n'
|
2157
|
+
text += ('\\begin{tabular}{' + 'l'*export_index
|
2158
|
+
+ num_columns*'c' + '}' + ' \n')
|
2159
|
+
text += '\\hline \n'
|
2160
|
+
columns = ['{\\bf ' + column + '}' for column in columns]
|
2161
|
+
index_name = df.index.name if df.index.name is not None else ' '
|
2162
|
+
if export_index:
|
2163
|
+
columns = ['{\\bf ' + index_name + '}'] + columns
|
2164
|
+
if export_frame:
|
2165
|
+
text += ' & '.join(columns) + row_sep + '\\hline \n'
|
2083
2166
|
rows = []
|
2084
|
-
for (
|
2085
|
-
cols = []
|
2167
|
+
for (ind,row) in df.iterrows():
|
2168
|
+
cols = [str(ind)] if export_index else []
|
2086
2169
|
for (j,column) in enumerate(df):
|
2087
2170
|
entry = str(row[column])
|
2088
2171
|
if entry == 'nan':
|
2089
2172
|
entry = '...'
|
2090
2173
|
cols += [entry]
|
2091
2174
|
rows += [' & '.join(cols)]
|
2092
|
-
text
|
2175
|
+
text += row_sep.join(rows)
|
2176
|
+
if export_frame:
|
2177
|
+
text += row_sep
|
2178
|
+
text += '\\hline \n'
|
2179
|
+
text += '\\end{tabular}' + ' \n'
|
2180
|
+
text += '\\renewcommand*{\\arraystretch}{1.0}' + ' \n'
|
2093
2181
|
output = text
|
2094
2182
|
return output
|
2095
2183
|
|
@@ -2122,6 +2210,8 @@ class RichDataFrame(pd.DataFrame):
|
|
2122
2210
|
are_intervals = are_intervs
|
2123
2211
|
are_centereds = are_centrs
|
2124
2212
|
are_constants = are_consts
|
2213
|
+
are_not_a_number = are_nans
|
2214
|
+
are_infinites = are_infs
|
2125
2215
|
relative_uncertainties = rel_uncs
|
2126
2216
|
signals_to_noises = signals_noises
|
2127
2217
|
amplitudes = ampls
|
@@ -2175,6 +2265,9 @@ class RichSeries(pd.Series):
|
|
2175
2265
|
def min_exps(self):
|
2176
2266
|
return pd.Series(self.values.view(RichArray).min_exps, self.index)
|
2177
2267
|
@property
|
2268
|
+
def max_decs(self):
|
2269
|
+
return pd.Series(self.values.view(RichArray).max_decs, self.index)
|
2270
|
+
@property
|
2178
2271
|
def extra_sf_lims(self):
|
2179
2272
|
return pd.Series(self.values.view(RichArray).extra_sf_lim, self.index)
|
2180
2273
|
@property
|
@@ -2193,6 +2286,12 @@ class RichSeries(pd.Series):
|
|
2193
2286
|
def are_consts(self):
|
2194
2287
|
return pd.Series(self.values.view(RichArray).are_consts, self.index)
|
2195
2288
|
@property
|
2289
|
+
def are_nans(self):
|
2290
|
+
return pd.Series(self.values.view(RichArray).are_nans, self.index)
|
2291
|
+
@property
|
2292
|
+
def are_infs(self):
|
2293
|
+
return pd.Series(self.values.view(RichArray).are_infs, self.index)
|
2294
|
+
@property
|
2196
2295
|
def centers(self):
|
2197
2296
|
return pd.Series(self.values.view(RichArray).centers, self.index)
|
2198
2297
|
@property
|
@@ -2254,10 +2353,13 @@ class RichSeries(pd.Series):
|
|
2254
2353
|
are_integers = are_ints
|
2255
2354
|
numbers_of_scientific_figures = nums_sf
|
2256
2355
|
minimum_exponents_for_scientific_notation = min_exps
|
2356
|
+
maximum_numbers_of_decimals = max_decs
|
2257
2357
|
are_limits = are_lims
|
2258
2358
|
are_intervals = are_intervs
|
2259
2359
|
are_centereds = are_centrs
|
2260
2360
|
are_constants = are_consts
|
2361
|
+
are_not_a_number = are_nans
|
2362
|
+
are_infinites = are_infs
|
2261
2363
|
relative_uncertainties = rel_uncs
|
2262
2364
|
signals_to_noises = signals_noises
|
2263
2365
|
amplitudes = ampls
|
@@ -2309,11 +2411,14 @@ class ComplexRichValue():
|
|
2309
2411
|
|
2310
2412
|
num_sf = min(real.num_sf, imag.num_sf)
|
2311
2413
|
min_exp = round(np.mean([real.min_exp, imag.min_exp]))
|
2414
|
+
max_dec = min(real.max_dec, imag.max_dec)
|
2312
2415
|
extra_sf_lim = min(real.extra_sf_lim, imag.extra_sf_lim)
|
2313
2416
|
real.num_sf = num_sf
|
2314
2417
|
imag.num_sf = num_sf
|
2315
2418
|
real.min_exp = min_exp
|
2316
2419
|
imag.min_exp = min_exp
|
2420
|
+
real.max_dec = max_dec
|
2421
|
+
real.max_dec = max_dec
|
2317
2422
|
real.extra_sf_lim = extra_sf_lim
|
2318
2423
|
imag.extra_sf_lim = extra_sf_lim
|
2319
2424
|
|
@@ -2356,16 +2461,21 @@ class ComplexRichValue():
|
|
2356
2461
|
self.imag.num_sf = x
|
2357
2462
|
|
2358
2463
|
@property
|
2359
|
-
def min_exp(self): return round(np.mean([self.real.min_exp,
|
2360
|
-
self.imag.min_exp]))
|
2464
|
+
def min_exp(self): return round(np.mean([self.real.min_exp, self.imag.min_exp]))
|
2361
2465
|
@min_exp.setter
|
2362
2466
|
def min_exp(self, x):
|
2363
2467
|
self.real.min_exp = x
|
2364
2468
|
self.imag.min_exp = x
|
2469
|
+
|
2470
|
+
@property
|
2471
|
+
def max_dec(self): return min(self.real.max_dec, self.imag.max_dec)
|
2472
|
+
@max_dec.setter
|
2473
|
+
def max_dec(self, x):
|
2474
|
+
self.real.max_dec = x
|
2475
|
+
self.imag.max_dec = x
|
2365
2476
|
|
2366
2477
|
@property
|
2367
|
-
def extra_sf_lim(self): return max(self.real.extra_sf_lim,
|
2368
|
-
self.imag.extra_sf_lim)
|
2478
|
+
def extra_sf_lim(self): return max(self.real.extra_sf_lim, self.imag.extra_sf_lim)
|
2369
2479
|
@extra_sf_lim.setter
|
2370
2480
|
def extra_sf_lim(self, x):
|
2371
2481
|
self.real.extra_sf_lim = x
|
@@ -2937,7 +3047,7 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
2937
3047
|
def parse_as_rich_value(text):
|
2938
3048
|
"""Obtain the properties of the input text as a rich value."""
|
2939
3049
|
def parse_value(text):
|
2940
|
-
"""Parse input text as a value."""
|
3050
|
+
"""Parse input text as a numeric value."""
|
2941
3051
|
text = str(text)
|
2942
3052
|
if any([char.isalpha() for char in text.replace(' e','')]):
|
2943
3053
|
for short_name in abbreviations:
|
@@ -2996,8 +3106,24 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
2996
3106
|
is_uplim, is_lolim = False, False
|
2997
3107
|
text = (text.replace('+-', '+/-').replace(' -', '-')
|
2998
3108
|
.replace(' +/-', '+/-').replace('+/- ', '+/-'))
|
2999
|
-
|
3000
|
-
|
3109
|
+
x_dx, e = text.split(' ')
|
3110
|
+
if ')' in text:
|
3111
|
+
if text.count(')') == 1:
|
3112
|
+
x, dx = x_dx.split('(')
|
3113
|
+
dx = dx[:-1]
|
3114
|
+
dx1, dx2 = dx
|
3115
|
+
else:
|
3116
|
+
x, dx1, dx2 = x_dx.split('(')
|
3117
|
+
dx1 = dx1[:-1]
|
3118
|
+
dx2 = dx2[:-1]
|
3119
|
+
if dx1.startswith('+'):
|
3120
|
+
dx1, dx2 = dx2, dx1
|
3121
|
+
dx1 = dx1[1:]
|
3122
|
+
dx2 = dx2[1:]
|
3123
|
+
d = len(x.split('.')[1]) if '.' in x else 0
|
3124
|
+
dx1 = '{:f}'.format(float(dx1)*10**(-d))
|
3125
|
+
dx2 = '{:f}'.format(float(dx2)*10**(-d))
|
3126
|
+
elif '+/-' in text:
|
3001
3127
|
x, dx = x_dx.split('+/-')
|
3002
3128
|
text = '{}-{}+{} {}'.format(x, dx, dx, e)
|
3003
3129
|
dx1, dx2 = dx, dx
|
@@ -3018,10 +3144,9 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
3018
3144
|
else:
|
3019
3145
|
x = text.split(' ')[0]
|
3020
3146
|
dx1, dx2 = '0', '0'
|
3021
|
-
|
3022
|
-
|
3023
|
-
|
3024
|
-
dx2 = '{} {}'.format(dx2 ,e)
|
3147
|
+
x = '{} {}'.format(x, e)
|
3148
|
+
dx1 = '{} {}'.format(dx1, e)
|
3149
|
+
dx2 = '{} {}'.format(dx2, e)
|
3025
3150
|
x = parse_value(x)
|
3026
3151
|
dx1 = parse_value(dx1)
|
3027
3152
|
dx2 = parse_value(dx2)
|
@@ -3276,8 +3401,10 @@ def rich_dataframe(df, domains=None, are_ints=None,
|
|
3276
3401
|
domain = defaultparams['domain']
|
3277
3402
|
if is_int is None:
|
3278
3403
|
is_int = defaultparams['assume integers']
|
3279
|
-
|
3280
|
-
|
3404
|
+
try:
|
3405
|
+
entry = rich_value(text, domain, is_int, use_default_extra_sf_lim)
|
3406
|
+
except:
|
3407
|
+
entry = text
|
3281
3408
|
if is_rich_value or is_number:
|
3282
3409
|
df.at[i,col] = entry
|
3283
3410
|
rdf = RichDataFrame(df)
|
@@ -3778,6 +3905,8 @@ def evaluate_distr(distr, domain=None, function=None, args=None,
|
|
3778
3905
|
return tuple(all_vars)
|
3779
3906
|
|
3780
3907
|
if args is not None:
|
3908
|
+
if type(args) is np.ndarray:
|
3909
|
+
args = [rich_value(arg) for arg in args]
|
3781
3910
|
if type(args) not in (tuple, list):
|
3782
3911
|
args = [args]
|
3783
3912
|
if type(args[0]) is not RichArray:
|
@@ -4357,13 +4486,19 @@ def function_with_rich_arrays(function, args, elementwise=False, **kwargs):
|
|
4357
4486
|
output = []
|
4358
4487
|
for k in range(output_size):
|
4359
4488
|
function_k = lambda *args: function(args)[k]
|
4360
|
-
rval_k = evaluate_distr(distr[:,k], domain, function_k,
|
4361
|
-
**kwargs)
|
4489
|
+
rval_k = evaluate_distr(distr[:,k], domain, function_k, **kwargs)
|
4362
4490
|
output += [rval_k]
|
4363
|
-
|
4364
|
-
|
4365
|
-
|
4366
|
-
|
4491
|
+
if type(args) not in (tuple, list):
|
4492
|
+
args = [args]
|
4493
|
+
for (i,arg) in enumerate(args):
|
4494
|
+
if type(arg) is not RichArray:
|
4495
|
+
args[i] = RichArray(arg)
|
4496
|
+
args_mains = [arg.mains for arg in args]
|
4497
|
+
if type(function) is not str:
|
4498
|
+
with np.errstate(divide='ignore', invalid='ignore'):
|
4499
|
+
main = function(*args_mains)
|
4500
|
+
else:
|
4501
|
+
main = distr[0,:]
|
4367
4502
|
output_type = RichArray if type(main) is np.ndarray else type(main)
|
4368
4503
|
if output_type is tuple and output_size > 1:
|
4369
4504
|
output = tuple(output)
|
@@ -4400,15 +4535,14 @@ def distr_with_rich_arrays(function, args, elementwise=False, **kwargs):
|
|
4400
4535
|
break
|
4401
4536
|
if not same_shapes:
|
4402
4537
|
raise Exception('Input arrays have different shapes.')
|
4403
|
-
|
4538
|
+
distr = []
|
4404
4539
|
args_flat = np.array([arg.flatten() for arg in args])
|
4405
4540
|
for i in range(args[0].size):
|
4406
4541
|
args_i = np.array(args_flat)[:,i].tolist()
|
4407
|
-
|
4408
|
-
|
4409
|
-
|
4410
|
-
|
4411
|
-
output = array
|
4542
|
+
distr_i = distr_with_rich_values(function, args_i, **kwargs)
|
4543
|
+
distr += [distr_i]
|
4544
|
+
distr = np.array(distr).T
|
4545
|
+
output = distr
|
4412
4546
|
else:
|
4413
4547
|
if type(function) is str:
|
4414
4548
|
variables = list(np.concatenate(tuple(arg.variables for arg in args)))
|
@@ -4924,6 +5058,10 @@ def _log10(x):
|
|
4924
5058
|
y = np.log10(x)
|
4925
5059
|
return y
|
4926
5060
|
|
5061
|
+
# Abbreviations from NumPy.
|
5062
|
+
inf = np.inf
|
5063
|
+
nan = np.nan
|
5064
|
+
|
4927
5065
|
# Functions for masking arrays.
|
4928
5066
|
def isnan(x):
|
4929
5067
|
x = rich_array(x) if type(x) is not RichArray else x
|
@@ -5,7 +5,7 @@ with open('README.md', 'r') as file:
|
|
5
5
|
|
6
6
|
setuptools.setup(
|
7
7
|
name = 'richvalues',
|
8
|
-
version = '4.0
|
8
|
+
version = '4.1.0',
|
9
9
|
license = 'BSD-3-Clause',
|
10
10
|
author = 'Andrés Megías Toledano',
|
11
11
|
description = 'Python library for working with uncertainties and upper/lower limits',
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|