richvalues 4.0.5__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.5 → richvalues-4.1.0}/PKG-INFO +2 -2
- {richvalues-4.0.5 → richvalues-4.1.0}/README.md +1 -1
- {richvalues-4.0.5 → richvalues-4.1.0}/pyproject.toml +1 -1
- {richvalues-4.0.5 → richvalues-4.1.0}/richvalues/__init__.py +277 -98
- {richvalues-4.0.5 → richvalues-4.1.0}/richvalues.egg-info/PKG-INFO +2 -2
- {richvalues-4.0.5 → richvalues-4.1.0}/richvalues.egg-info/SOURCES.txt +0 -1
- {richvalues-4.0.5 → richvalues-4.1.0}/setup.py +1 -1
- richvalues-4.0.5/richvalues.egg-info/.DS_Store +0 -0
- {richvalues-4.0.5 → richvalues-4.1.0}/LICENSE +0 -0
- {richvalues-4.0.5 → richvalues-4.1.0}/richvalues.egg-info/dependency_links.txt +0 -0
- {richvalues-4.0.5 → richvalues-4.1.0}/richvalues.egg-info/requires.txt +0 -0
- {richvalues-4.0.5 → richvalues-4.1.0}/richvalues.egg-info/top_level.txt +0 -0
- {richvalues-4.0.5 → richvalues-4.1.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: richvalues
|
3
|
-
Version: 4.0
|
3
|
+
Version: 4.1.0
|
4
4
|
Summary: Python library for working with uncertainties and upper/lower limits
|
5
5
|
Home-page: https://github.com/andresmegias/richvalues/
|
6
6
|
Author: Andrés Megías Toledano
|
@@ -15,7 +15,7 @@ License-File: LICENSE
|
|
15
15
|
|
16
16
|
RichValues is a Python 3 library for working with numeric values with uncertainties, upper/lower limits and finite intervals, which may be called _rich values_.
|
17
17
|
|
18
|
-
With it, one can import rich values written in plain text documents in an easily readable format, operate with them propagating the uncertainties automatically, and export them in the same formatting style as the import. It also allows to easily plot rich values and to make fits to any function, taking into account the uncertainties and the upper/limits or finite intervals. Moreover, correlations between variables are taken into account when performing calculations with rich values.
|
18
|
+
With it, one can import rich values written in plain text documents in an easily readable format, operate with them propagating the uncertainties automatically, and export them in the same formatting style as the import. It also allows to easily plot rich values and to make fits to any function, taking into account the uncertainties and the upper/lower limits or finite intervals. Moreover, correlations between variables are taken into account when performing calculations with rich values.
|
19
19
|
|
20
20
|
The libraries NumPy, Pandas, SciPy and Matplotlib are required by RichValues. A user guide and a quick tutorial are available on GitHub: https://github.com/andresmegias/richvalues/.
|
21
21
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
RichValues is a Python 3 library for working with numeric values with uncertainties, upper/lower limits and finite intervals, which may be called _rich values_.
|
2
2
|
|
3
|
-
With it, one can import rich values written in plain text documents in an easily readable format, operate with them propagating the uncertainties automatically, and export them in the same formatting style as the import. It also allows to easily plot rich values and to make fits to any function, taking into account the uncertainties and the upper/limits or finite intervals. Moreover, correlations between variables are taken into account when performing calculations with rich values.
|
3
|
+
With it, one can import rich values written in plain text documents in an easily readable format, operate with them propagating the uncertainties automatically, and export them in the same formatting style as the import. It also allows to easily plot rich values and to make fits to any function, taking into account the uncertainties and the upper/lower limits or finite intervals. Moreover, correlations between variables are taken into account when performing calculations with rich values.
|
4
4
|
|
5
5
|
The libraries NumPy, Pandas, SciPy and Matplotlib are required by RichValues. A user guide and a quick tutorial are available on GitHub: https://github.com/andresmegias/richvalues/.
|
@@ -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))
|
@@ -238,7 +241,8 @@ def round_sf_unc(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
|
238
241
|
num_digits_x = len(str(x).split('.')[0])
|
239
242
|
if num_digits_y > num_digits_x:
|
240
243
|
m -= 1
|
241
|
-
|
244
|
+
base_dy = '{:e}'.format(float(dy)).split('e')[0]
|
245
|
+
if float(base_dy) <= extra_sf_lim:
|
242
246
|
m += 1
|
243
247
|
y = round_sf(x, m, min_exp, extra_sf_lim=1-1e-8)
|
244
248
|
else:
|
@@ -268,7 +272,7 @@ def round_sf_unc(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
|
268
272
|
y = '{}e{}'.format(base_y, exp_dy)
|
269
273
|
else:
|
270
274
|
f = 10**(-int(exp_y))
|
271
|
-
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)
|
272
276
|
y = '{}e{}'.format(base_y, exp_y)
|
273
277
|
elif dx == 0:
|
274
278
|
y = round_sf(x, n, min_exp, extra_sf_lim)
|
@@ -289,12 +293,24 @@ def round_sf_unc(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
|
289
293
|
if abs(exp) < min_exp:
|
290
294
|
x = float(sign + str(x))
|
291
295
|
min_exp = np.inf
|
292
|
-
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)
|
293
297
|
y = y.replace('e+', 'e').replace('e00', 'e0')
|
294
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)
|
295
311
|
return y, dy
|
296
312
|
|
297
|
-
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):
|
298
314
|
"""
|
299
315
|
Round a value and its uncertainties depending on their significant figures.
|
300
316
|
|
@@ -309,6 +325,9 @@ def round_sf_uncs(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
|
309
325
|
min_exp : int, optional
|
310
326
|
Minimum decimal exponent, in absolute value, to apply scientific
|
311
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.
|
312
331
|
extra_sf_lim : float, optional
|
313
332
|
If the number expressed in scientific notation has a base that is lower
|
314
333
|
than this value, an additional significant figure will be used.
|
@@ -322,32 +341,47 @@ def round_sf_uncs(x, dx, n=None, min_exp=None, extra_sf_lim=None):
|
|
322
341
|
Rounded uncertainties.
|
323
342
|
"""
|
324
343
|
n = set_default_value(n, 'number of significant figures')
|
325
|
-
min_exp = set_default_value(min_exp,
|
326
|
-
|
327
|
-
extra_sf_lim = set_default_value(extra_sf_lim,
|
328
|
-
'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')
|
329
347
|
dx1, dx2 = dx
|
330
|
-
y1, dy1 = round_sf_unc(x, dx1, n, min_exp, extra_sf_lim)
|
331
|
-
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)
|
332
350
|
num_dec_1 = len(y1.split('e')[0].split('.')[1]) if '.' in y1 else 0
|
333
351
|
num_dec_2 = len(y2.split('e')[0].split('.')[1]) if '.' in y2 else 0
|
334
352
|
if num_dec_2 > num_dec_1:
|
335
353
|
diff = num_dec_2 - num_dec_1
|
336
|
-
y1, dy1 = round_sf_unc(x, dx1, n+diff, min_exp, extra_sf_lim)
|
337
|
-
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)
|
338
356
|
else:
|
339
357
|
diff = num_dec_1 - num_dec_2
|
340
358
|
off1, off2 = 0, 0
|
341
359
|
if num_dec_1 == 0 == num_dec_2:
|
342
|
-
|
343
|
-
|
360
|
+
base_dy1 = '{:e}'.format(dx1).split('e')[0]
|
361
|
+
base_dy2 = '{:e}'.format(dx2).split('e')[0]
|
362
|
+
b1 = float(base_dy1) if np.isfinite(dx1) else 10.
|
363
|
+
b2 = float(base_dy2) if np.isfinite(dx2) else 10.
|
344
364
|
if dx2 > dx1 and b1 <= extra_sf_lim and b2 > extra_sf_lim:
|
345
365
|
off2 = 1
|
346
366
|
if dx1 > dx2 and b2 <= extra_sf_lim and b1 > extra_sf_lim:
|
347
367
|
off1 = 1
|
348
|
-
y1, dy1 = round_sf_unc(x, dx1, n+off1, min_exp, extra_sf_lim)
|
349
|
-
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)
|
350
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:]
|
351
385
|
dy = [dy1, dy2]
|
352
386
|
return y, dy
|
353
387
|
|
@@ -530,6 +564,7 @@ class RichValue():
|
|
530
564
|
self.domain = domain
|
531
565
|
self.num_sf = defaultparams['number of significant figures']
|
532
566
|
self.min_exp = defaultparams['minimum exponent for scientific notation']
|
567
|
+
self.max_dec = defaultparams['maximum number of decimals']
|
533
568
|
self.extra_sf_lim = defaultparams['limit for extra significant figure']
|
534
569
|
self.pdf_info = 'default'
|
535
570
|
self.variables = variables
|
@@ -716,10 +751,10 @@ class RichValue():
|
|
716
751
|
domain = copy.copy(self.domain)
|
717
752
|
is_int = self.is_int
|
718
753
|
min_exp = abs(self.min_exp)
|
754
|
+
max_dec = abs(self.max_dec)
|
719
755
|
extra_sf_lim = self.extra_sf_lim
|
720
756
|
show_domain = defaultparams['show domain']
|
721
|
-
show_asterisk = defaultparams['show asterisk for rich values with'
|
722
|
-
' custom PDF']
|
757
|
+
show_asterisk = defaultparams['show asterisk for rich values with custom PDF']
|
723
758
|
use_extra_sf_in_exacts = \
|
724
759
|
defaultparams['use extra significant figure for exact values']
|
725
760
|
use_extra_sf_in_ranges = \
|
@@ -736,7 +771,7 @@ class RichValue():
|
|
736
771
|
else False)
|
737
772
|
use_exp = True
|
738
773
|
if ((self.is_centr and 'e' not in
|
739
|
-
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)))
|
740
775
|
or self.is_lim and abs(np.floor(_log10(abs(float(x))) < min_exp))
|
741
776
|
or np.isinf(min_exp)):
|
742
777
|
use_exp = False
|
@@ -747,8 +782,8 @@ class RichValue():
|
|
747
782
|
if (not range_bound and use_extra_sf_in_exacts
|
748
783
|
or range_bound and use_extra_sf_in_ranges):
|
749
784
|
n += 1
|
750
|
-
y, (dy1, dy2) = round_sf_uncs(x, [dx1, dx2], n,
|
751
|
-
|
785
|
+
y, (dy1, dy2) = round_sf_uncs(x, [dx1, dx2], n, min_exp,
|
786
|
+
max_dec, extra_sf_lim)
|
752
787
|
if 'e' in y:
|
753
788
|
y, a = y.split('e')
|
754
789
|
a = int(a)
|
@@ -758,14 +793,20 @@ class RichValue():
|
|
758
793
|
dy1, _ = dy1.split('e')
|
759
794
|
if 'e' in dy2:
|
760
795
|
dy2, _ = dy2.split('e')
|
761
|
-
if
|
762
|
-
if
|
763
|
-
|
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)
|
764
803
|
else:
|
765
|
-
|
766
|
-
text = '{} e{}'.format(y, a)
|
804
|
+
text = '{}-{}+{} e{}'.format(y, dy1, dy2, a)
|
767
805
|
else:
|
768
|
-
|
806
|
+
if dy1 == dy2:
|
807
|
+
text = '{}{} e{}'.format(y, dy1, a)
|
808
|
+
else:
|
809
|
+
text = '{}{}{} e{}'.format(y, dy1, dy2, a)
|
769
810
|
if not use_exp:
|
770
811
|
text = text.replace(' e0','')
|
771
812
|
else:
|
@@ -848,6 +889,7 @@ class RichValue():
|
|
848
889
|
is_range = self.is_range
|
849
890
|
is_int = self.is_int
|
850
891
|
min_exp = abs(self.min_exp)
|
892
|
+
max_dec = abs(self.max_dec)
|
851
893
|
extra_sf_lim = self.extra_sf_lim
|
852
894
|
show_domain = defaultparams['show domain']
|
853
895
|
use_exp = True
|
@@ -871,7 +913,7 @@ class RichValue():
|
|
871
913
|
else False)
|
872
914
|
if is_numeric:
|
873
915
|
if not is_range:
|
874
|
-
_, 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)
|
875
917
|
unc_r = np.array(unc_r, float)
|
876
918
|
if not is_range and not use_exp:
|
877
919
|
if not self.is_lim:
|
@@ -883,11 +925,11 @@ class RichValue():
|
|
883
925
|
round_sf(x, n, np.inf, extra_sf_lim))
|
884
926
|
text = '${}$'.format(y)
|
885
927
|
else:
|
886
|
-
y, dy = round_sf_unc(x, dx[0], n,
|
887
|
-
|
928
|
+
y, dy = round_sf_unc(x, dx[0], n, min_exp,
|
929
|
+
max_dec, extra_sf_lim)
|
888
930
|
text = '${} \pm {}$'.format(y, dy)
|
889
931
|
else:
|
890
|
-
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)
|
891
933
|
text = '$'+y + '_{-'+dy[0]+'}^{+'+dy[1]+'}$'
|
892
934
|
else:
|
893
935
|
if is_lolim:
|
@@ -915,8 +957,8 @@ class RichValue():
|
|
915
957
|
text = ('${} {}'.format(y, mult_symbol)
|
916
958
|
+ ' 10^{'+a+'}$')
|
917
959
|
else:
|
918
|
-
y, dy = round_sf_unc(x, dx[0], n,
|
919
|
-
|
960
|
+
y, dy = round_sf_unc(x, dx[0], n, min_exp,
|
961
|
+
max_dec, extra_sf_lim)
|
920
962
|
if 'e' in y:
|
921
963
|
y, a = y.split('e')
|
922
964
|
dy, a = dy.split('e')
|
@@ -926,8 +968,8 @@ class RichValue():
|
|
926
968
|
text = ('$({} \pm {}) '.format(y, dy)
|
927
969
|
+ mult_symbol + ' 10^{'+a+'}$')
|
928
970
|
else:
|
929
|
-
y, dy = round_sf_uncs(x, [dx[0], dx[1]], n,
|
930
|
-
|
971
|
+
y, dy = round_sf_uncs(x, [dx[0], dx[1]], n, min_exp,
|
972
|
+
max_dec, extra_sf_lim)
|
931
973
|
if 'e' in y:
|
932
974
|
y, a = y.split('e')
|
933
975
|
dy1, a = dy[0].split('e')
|
@@ -945,13 +987,13 @@ class RichValue():
|
|
945
987
|
elif is_uplim:
|
946
988
|
symbol = '<'
|
947
989
|
y = int(np.ceil(x)) if is_int else x
|
948
|
-
min_exp = 0
|
949
990
|
y = round_sf(y, n, min_exp, extra_sf_lim)
|
950
|
-
|
951
|
-
|
991
|
+
if 'e' in y:
|
992
|
+
y, a = y.split('e')
|
993
|
+
else:
|
994
|
+
a = '0'
|
952
995
|
text = ('${} {} {}'.format(symbol, y, mult_symbol)
|
953
996
|
+ ' 10^{'+a+'}$')
|
954
|
-
text = text.replace('e-0', 'e-').replace('e+','e')
|
955
997
|
a = int(text.split('10^{')[1].split('}')[0])
|
956
998
|
if abs(a) < min_exp:
|
957
999
|
y = RichValue(x, dx, is_lolim, is_uplim,
|
@@ -962,7 +1004,8 @@ class RichValue():
|
|
962
1004
|
text = y.latex(*kwargs)
|
963
1005
|
if (not use_extra_sf_in_exacts and omit_ones_in_sci_notation
|
964
1006
|
and dx[0] == dx[1] and dx[0] == 0 or np.isnan(dx[0])):
|
965
|
-
|
1007
|
+
if '.' not in text:
|
1008
|
+
text = text.replace('1 {} '.format(mult_symbol), '')
|
966
1009
|
else:
|
967
1010
|
x1 = RichValue(main - unc[0], domain=domain)
|
968
1011
|
x2 = RichValue(main + unc[1], domain=domain)
|
@@ -1452,6 +1495,11 @@ class RichValue():
|
|
1452
1495
|
@minimum_exponent_for_scientific_notation.setter
|
1453
1496
|
def minimum_exponent_for_scientific_notation(self, x): self.min_exp = x
|
1454
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
|
+
|
1455
1503
|
@property
|
1456
1504
|
def limit_for_extra_significant_figure(self): return self.extra_sf_lim
|
1457
1505
|
@limit_for_extra_significant_figure.setter
|
@@ -1642,6 +1690,9 @@ class RichArray(np.ndarray):
|
|
1642
1690
|
def min_exps(self):
|
1643
1691
|
return np.array([x.min_exp for x in self.flat]).reshape(self.shape)
|
1644
1692
|
@property
|
1693
|
+
def max_decs(self):
|
1694
|
+
return np.array([x.max_dec for x in self.flat]).reshape(self.shape)
|
1695
|
+
@property
|
1645
1696
|
def extra_sf_lims(self):
|
1646
1697
|
return np.array([x.extra_sf_lim for x in self.flat]).reshape(self.shape)
|
1647
1698
|
@property
|
@@ -1660,6 +1711,12 @@ class RichArray(np.ndarray):
|
|
1660
1711
|
def are_consts(self):
|
1661
1712
|
return np.array([x.is_const for x in self.flat]).reshape(self.shape)
|
1662
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
|
1663
1720
|
def centers(self):
|
1664
1721
|
return np.array([x.center for x in self.flat]).reshape(self.shape)
|
1665
1722
|
@property
|
@@ -1738,6 +1795,7 @@ class RichArray(np.ndarray):
|
|
1738
1795
|
abbreviations = {'is integer': 'is_int',
|
1739
1796
|
'number of significant figures': 'num_sf',
|
1740
1797
|
'minimum exponent for scientific notation': 'min_exp',
|
1798
|
+
'maximum number of decimals': 'max_dec',
|
1741
1799
|
'limit for extra significant figure': 'extra_sf_lim'}
|
1742
1800
|
attributes = ['domain'] + list(abbreviations.values())
|
1743
1801
|
for entry in abbreviations:
|
@@ -1757,6 +1815,8 @@ class RichArray(np.ndarray):
|
|
1757
1815
|
x.num_sf = params['num_sf']
|
1758
1816
|
if 'min_exp' in params:
|
1759
1817
|
x.min_exp = params['min_exp']
|
1818
|
+
if 'max_dec' in params:
|
1819
|
+
x.max_dec = params['max_dec']
|
1760
1820
|
if 'extra_sf_lim' in params:
|
1761
1821
|
x.extra_sf_lim = params['extra_sf_lim']
|
1762
1822
|
|
@@ -1799,8 +1859,7 @@ class RichArray(np.ndarray):
|
|
1799
1859
|
return np.array(self).mean()
|
1800
1860
|
|
1801
1861
|
def std(self):
|
1802
|
-
std_function = lambda u: (np.sum((u
|
1803
|
-
/ len(self - 1))**0.5
|
1862
|
+
std_function = lambda u: (np.sum((u-u.mean())**2)/(len(self)-1))**0.5
|
1804
1863
|
return self.function(std_function)
|
1805
1864
|
|
1806
1865
|
# Attribute acronyms.
|
@@ -1812,11 +1871,14 @@ class RichArray(np.ndarray):
|
|
1812
1871
|
are_integers = are_ints
|
1813
1872
|
numbers_of_significant_figures = nums_sf
|
1814
1873
|
minimum_exponents_for_scientific_notation = min_exps
|
1874
|
+
maximum_number_of_decimals = max_decs
|
1815
1875
|
limits_for_extra_significant_figure = extra_sf_lims
|
1816
1876
|
are_limits = are_lims
|
1817
1877
|
are_intervals = are_intervs
|
1818
1878
|
are_centereds = are_centrs
|
1819
1879
|
are_constants = are_consts
|
1880
|
+
are_not_a_number = are_nans
|
1881
|
+
are_infinites = are_infs
|
1820
1882
|
relative_uncertainties = rel_uncs
|
1821
1883
|
signals_to_noises = signals_noises
|
1822
1884
|
amplitudes = ampls
|
@@ -1905,6 +1967,8 @@ class RichDataFrame(pd.DataFrame):
|
|
1905
1967
|
@property
|
1906
1968
|
def min_exps(self): return self._property('min_exps')
|
1907
1969
|
@property
|
1970
|
+
def max_decs(self): return self._property('max_decs')
|
1971
|
+
@property
|
1908
1972
|
def extra_sf_lims(self): return self._property('extra_sf_lims')
|
1909
1973
|
@property
|
1910
1974
|
def are_lims(self): return self._property('are_lims')
|
@@ -1917,6 +1981,10 @@ class RichDataFrame(pd.DataFrame):
|
|
1917
1981
|
@property
|
1918
1982
|
def are_consts(self): return self._property('are_consts')
|
1919
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
|
1920
1988
|
def centers(self): return self._property('centers')
|
1921
1989
|
@property
|
1922
1990
|
def rel_uncs(self): return self._property2('rel_uncs')
|
@@ -1964,6 +2032,7 @@ class RichDataFrame(pd.DataFrame):
|
|
1964
2032
|
abbreviations = {'is integer': 'is_int',
|
1965
2033
|
'number of significant figures': 'num_sf',
|
1966
2034
|
'minimum exponent for scientific notation': 'min_exp',
|
2035
|
+
'maximum number of decimals': 'max_dec',
|
1967
2036
|
'limit for extra significant figure': 'extra_sf_lim'}
|
1968
2037
|
attributes = ['domain'] + list(abbreviations.values())
|
1969
2038
|
for entry in abbreviations:
|
@@ -1984,6 +2053,7 @@ class RichDataFrame(pd.DataFrame):
|
|
1984
2053
|
set_is_int = 'is_int' in params
|
1985
2054
|
set_num_sf = 'num_sf' in params
|
1986
2055
|
set_min_exp = 'min_exp' in params
|
2056
|
+
set_max_dec = 'max_dec' in params
|
1987
2057
|
set_extra_sf_lim = 'extra_sf_lim' in params
|
1988
2058
|
row_inds = self.index
|
1989
2059
|
for col in self:
|
@@ -2002,6 +2072,9 @@ class RichDataFrame(pd.DataFrame):
|
|
2002
2072
|
if set_min_exp and col in params['min_exp']:
|
2003
2073
|
for i in row_inds:
|
2004
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]
|
2005
2078
|
if set_extra_sf_lim and col in params['extra_sf_lim']:
|
2006
2079
|
for i in row_inds:
|
2007
2080
|
self[col][i].extra_sf_lim = params['extra_sf_lim'][col]
|
@@ -2060,7 +2133,8 @@ class RichDataFrame(pd.DataFrame):
|
|
2060
2133
|
new_row = pd.DataFrame(new_row, idex=[0])
|
2061
2134
|
return new_row
|
2062
2135
|
|
2063
|
-
def latex(self, return_df=False,
|
2136
|
+
def latex(self, return_df=False, export_frame=True, export_index=True,
|
2137
|
+
row_sep='\\tabularnewline', **kwargs):
|
2064
2138
|
"""Return the content of the dataframe as a table in LaTeX format."""
|
2065
2139
|
row_sep = ' ' + row_sep + ' \n'
|
2066
2140
|
df = copy.copy(self)
|
@@ -2075,17 +2149,35 @@ class RichDataFrame(pd.DataFrame):
|
|
2075
2149
|
if return_df:
|
2076
2150
|
output = df
|
2077
2151
|
else:
|
2152
|
+
columns = list(df.columns)
|
2153
|
+
num_columns = len(columns)
|
2078
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'
|
2079
2166
|
rows = []
|
2080
|
-
for (
|
2081
|
-
cols = []
|
2167
|
+
for (ind,row) in df.iterrows():
|
2168
|
+
cols = [str(ind)] if export_index else []
|
2082
2169
|
for (j,column) in enumerate(df):
|
2083
2170
|
entry = str(row[column])
|
2084
2171
|
if entry == 'nan':
|
2085
2172
|
entry = '...'
|
2086
2173
|
cols += [entry]
|
2087
2174
|
rows += [' & '.join(cols)]
|
2088
|
-
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'
|
2089
2181
|
output = text
|
2090
2182
|
return output
|
2091
2183
|
|
@@ -2118,6 +2210,8 @@ class RichDataFrame(pd.DataFrame):
|
|
2118
2210
|
are_intervals = are_intervs
|
2119
2211
|
are_centereds = are_centrs
|
2120
2212
|
are_constants = are_consts
|
2213
|
+
are_not_a_number = are_nans
|
2214
|
+
are_infinites = are_infs
|
2121
2215
|
relative_uncertainties = rel_uncs
|
2122
2216
|
signals_to_noises = signals_noises
|
2123
2217
|
amplitudes = ampls
|
@@ -2171,6 +2265,9 @@ class RichSeries(pd.Series):
|
|
2171
2265
|
def min_exps(self):
|
2172
2266
|
return pd.Series(self.values.view(RichArray).min_exps, self.index)
|
2173
2267
|
@property
|
2268
|
+
def max_decs(self):
|
2269
|
+
return pd.Series(self.values.view(RichArray).max_decs, self.index)
|
2270
|
+
@property
|
2174
2271
|
def extra_sf_lims(self):
|
2175
2272
|
return pd.Series(self.values.view(RichArray).extra_sf_lim, self.index)
|
2176
2273
|
@property
|
@@ -2189,6 +2286,12 @@ class RichSeries(pd.Series):
|
|
2189
2286
|
def are_consts(self):
|
2190
2287
|
return pd.Series(self.values.view(RichArray).are_consts, self.index)
|
2191
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
|
2192
2295
|
def centers(self):
|
2193
2296
|
return pd.Series(self.values.view(RichArray).centers, self.index)
|
2194
2297
|
@property
|
@@ -2250,10 +2353,13 @@ class RichSeries(pd.Series):
|
|
2250
2353
|
are_integers = are_ints
|
2251
2354
|
numbers_of_scientific_figures = nums_sf
|
2252
2355
|
minimum_exponents_for_scientific_notation = min_exps
|
2356
|
+
maximum_numbers_of_decimals = max_decs
|
2253
2357
|
are_limits = are_lims
|
2254
2358
|
are_intervals = are_intervs
|
2255
2359
|
are_centereds = are_centrs
|
2256
2360
|
are_constants = are_consts
|
2361
|
+
are_not_a_number = are_nans
|
2362
|
+
are_infinites = are_infs
|
2257
2363
|
relative_uncertainties = rel_uncs
|
2258
2364
|
signals_to_noises = signals_noises
|
2259
2365
|
amplitudes = ampls
|
@@ -2305,11 +2411,14 @@ class ComplexRichValue():
|
|
2305
2411
|
|
2306
2412
|
num_sf = min(real.num_sf, imag.num_sf)
|
2307
2413
|
min_exp = round(np.mean([real.min_exp, imag.min_exp]))
|
2414
|
+
max_dec = min(real.max_dec, imag.max_dec)
|
2308
2415
|
extra_sf_lim = min(real.extra_sf_lim, imag.extra_sf_lim)
|
2309
2416
|
real.num_sf = num_sf
|
2310
2417
|
imag.num_sf = num_sf
|
2311
2418
|
real.min_exp = min_exp
|
2312
2419
|
imag.min_exp = min_exp
|
2420
|
+
real.max_dec = max_dec
|
2421
|
+
real.max_dec = max_dec
|
2313
2422
|
real.extra_sf_lim = extra_sf_lim
|
2314
2423
|
imag.extra_sf_lim = extra_sf_lim
|
2315
2424
|
|
@@ -2352,16 +2461,21 @@ class ComplexRichValue():
|
|
2352
2461
|
self.imag.num_sf = x
|
2353
2462
|
|
2354
2463
|
@property
|
2355
|
-
def min_exp(self): return round(np.mean([self.real.min_exp,
|
2356
|
-
self.imag.min_exp]))
|
2464
|
+
def min_exp(self): return round(np.mean([self.real.min_exp, self.imag.min_exp]))
|
2357
2465
|
@min_exp.setter
|
2358
2466
|
def min_exp(self, x):
|
2359
2467
|
self.real.min_exp = x
|
2360
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
|
2361
2476
|
|
2362
2477
|
@property
|
2363
|
-
def extra_sf_lim(self): return max(self.real.extra_sf_lim,
|
2364
|
-
self.imag.extra_sf_lim)
|
2478
|
+
def extra_sf_lim(self): return max(self.real.extra_sf_lim, self.imag.extra_sf_lim)
|
2365
2479
|
@extra_sf_lim.setter
|
2366
2480
|
def extra_sf_lim(self, x):
|
2367
2481
|
self.real.extra_sf_lim = x
|
@@ -2663,7 +2777,7 @@ def add_rich_values(x, y):
|
|
2663
2777
|
is_int = x.is_int and y.is_int
|
2664
2778
|
domain = [x.domain[0] + y.domain[0], x.domain[1] + y.domain[1]]
|
2665
2779
|
sigmas = defaultparams['sigmas to use approximate uncertainty propagation']
|
2666
|
-
if x.is_exact or y.is_exact:
|
2780
|
+
if (x.is_exact or y.is_exact) and (x.is_interv or y.is_interv):
|
2667
2781
|
z = list(np.array(x.interval()) + np.array(y.interval()))
|
2668
2782
|
z = RichValue(z, domain=domain, is_int=is_int)
|
2669
2783
|
elif (not (x.is_interv or y.is_interv)
|
@@ -2687,7 +2801,7 @@ def multiply_rich_values(x, y):
|
|
2687
2801
|
is_int = x.is_int and y.is_int
|
2688
2802
|
domain = propagate_domain(x.domain, y.domain, lambda a,b: a*b)
|
2689
2803
|
sigmas = defaultparams['sigmas to use approximate uncertainty propagation']
|
2690
|
-
if x.is_exact or y.is_exact:
|
2804
|
+
if (x.is_exact or y.is_exact) and (x.is_interv or y.is_interv):
|
2691
2805
|
z = list(np.array(x.interval()) * np.array(y.interval()))
|
2692
2806
|
z = RichValue(z, domain=domain, is_int=is_int)
|
2693
2807
|
elif (not (x.is_interv or y.is_interv)
|
@@ -2933,7 +3047,7 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
2933
3047
|
def parse_as_rich_value(text):
|
2934
3048
|
"""Obtain the properties of the input text as a rich value."""
|
2935
3049
|
def parse_value(text):
|
2936
|
-
"""Parse input text as a value."""
|
3050
|
+
"""Parse input text as a numeric value."""
|
2937
3051
|
text = str(text)
|
2938
3052
|
if any([char.isalpha() for char in text.replace(' e','')]):
|
2939
3053
|
for short_name in abbreviations:
|
@@ -2992,8 +3106,24 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
2992
3106
|
is_uplim, is_lolim = False, False
|
2993
3107
|
text = (text.replace('+-', '+/-').replace(' -', '-')
|
2994
3108
|
.replace(' +/-', '+/-').replace('+/- ', '+/-'))
|
2995
|
-
|
2996
|
-
|
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:
|
2997
3127
|
x, dx = x_dx.split('+/-')
|
2998
3128
|
text = '{}-{}+{} {}'.format(x, dx, dx, e)
|
2999
3129
|
dx1, dx2 = dx, dx
|
@@ -3014,10 +3144,9 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
3014
3144
|
else:
|
3015
3145
|
x = text.split(' ')[0]
|
3016
3146
|
dx1, dx2 = '0', '0'
|
3017
|
-
|
3018
|
-
|
3019
|
-
|
3020
|
-
dx2 = '{} {}'.format(dx2 ,e)
|
3147
|
+
x = '{} {}'.format(x, e)
|
3148
|
+
dx1 = '{} {}'.format(dx1, e)
|
3149
|
+
dx2 = '{} {}'.format(dx2, e)
|
3021
3150
|
x = parse_value(x)
|
3022
3151
|
dx1 = parse_value(dx1)
|
3023
3152
|
dx2 = parse_value(dx2)
|
@@ -3070,7 +3199,7 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
3070
3199
|
unc = 0
|
3071
3200
|
is_lolim, is_uplim, is_range = False, False, True
|
3072
3201
|
min_exp = round(np.mean([me1, me2]))
|
3073
|
-
extra_sf_lim =
|
3202
|
+
extra_sf_lim = max(el1, el2)
|
3074
3203
|
return (main, unc, is_lolim, is_uplim, is_range, domain,
|
3075
3204
|
min_exp, extra_sf_lim)
|
3076
3205
|
|
@@ -3203,7 +3332,7 @@ def rich_array(array, domain=None, is_int=None,
|
|
3203
3332
|
rarray = RichArray(mains, uncs, are_lolims, are_uplims, are_ranges,
|
3204
3333
|
domains, are_ints, variables, expressions)
|
3205
3334
|
min_exp = round(np.mean(min_exps))
|
3206
|
-
extra_sf_lim =
|
3335
|
+
extra_sf_lim = max(extra_sf_lims)
|
3207
3336
|
rarray.set_params({'min_exp': min_exp, 'extra_sf_lim': extra_sf_lim})
|
3208
3337
|
return rarray
|
3209
3338
|
|
@@ -3272,8 +3401,10 @@ def rich_dataframe(df, domains=None, are_ints=None,
|
|
3272
3401
|
domain = defaultparams['domain']
|
3273
3402
|
if is_int is None:
|
3274
3403
|
is_int = defaultparams['assume integers']
|
3275
|
-
|
3276
|
-
|
3404
|
+
try:
|
3405
|
+
entry = rich_value(text, domain, is_int, use_default_extra_sf_lim)
|
3406
|
+
except:
|
3407
|
+
entry = text
|
3277
3408
|
if is_rich_value or is_number:
|
3278
3409
|
df.at[i,col] = entry
|
3279
3410
|
rdf = RichDataFrame(df)
|
@@ -3582,7 +3713,7 @@ def loguniform_distribution(low=-1, high=1, size=1,
|
|
3582
3713
|
return distr
|
3583
3714
|
|
3584
3715
|
def distr_with_rich_values(function, args, len_samples=None,
|
3585
|
-
is_vectorizable=False):
|
3716
|
+
is_vectorizable=False, **kwargs):
|
3586
3717
|
"""
|
3587
3718
|
Same as function_with_rich_values, but just returns the final distribution.
|
3588
3719
|
"""
|
@@ -3688,7 +3819,7 @@ def remove_zero_infs(interval, zero_log, inf_log):
|
|
3688
3819
|
return new_interval
|
3689
3820
|
|
3690
3821
|
def evaluate_distr(distr, domain=None, function=None, args=None,
|
3691
|
-
len_samples=None, is_vectorizable=False, consider_intervs=
|
3822
|
+
len_samples=None, is_vectorizable=False, consider_intervs=None,
|
3692
3823
|
is_domain_cyclic=False, lims_fraction=None, num_reps_lims=None,
|
3693
3824
|
save_pdf=None, **kwargs):
|
3694
3825
|
"""
|
@@ -3774,10 +3905,17 @@ def evaluate_distr(distr, domain=None, function=None, args=None,
|
|
3774
3905
|
return tuple(all_vars)
|
3775
3906
|
|
3776
3907
|
if args is not None:
|
3908
|
+
if type(args) is np.ndarray:
|
3909
|
+
args = [rich_value(arg) for arg in args]
|
3777
3910
|
if type(args) not in (tuple, list):
|
3778
3911
|
args = [args]
|
3779
|
-
|
3780
|
-
|
3912
|
+
if type(args[0]) is not RichArray:
|
3913
|
+
args = [rich_value(arg) if type(arg) not in
|
3914
|
+
(RichValue, ComplexRichValue) else arg for arg in args]
|
3915
|
+
if consider_intervs is None:
|
3916
|
+
consider_intervs = True
|
3917
|
+
if args is not None and all([arg.is_centr for arg in args]):
|
3918
|
+
consider_intervs = False
|
3781
3919
|
|
3782
3920
|
distr = np.array(distr)
|
3783
3921
|
|
@@ -4076,6 +4214,7 @@ def function_with_rich_values(function, args, unc_function=None,
|
|
4076
4214
|
args = [args]
|
4077
4215
|
args = [rich_value(arg) if type(arg) not in (RichValue, ComplexRichValue)
|
4078
4216
|
else arg for arg in args]
|
4217
|
+
args_copy = copy.copy(args)
|
4079
4218
|
|
4080
4219
|
input_function = copy.copy(function)
|
4081
4220
|
if type(function) is str:
|
@@ -4119,7 +4258,7 @@ def function_with_rich_values(function, args, unc_function=None,
|
|
4119
4258
|
|
4120
4259
|
if len_samples is None:
|
4121
4260
|
len_samples = int(len(args)**0.5 * defaultparams['size of samples'])
|
4122
|
-
num_sf =
|
4261
|
+
num_sf = int(np.median([arg.num_sf for arg in args]))
|
4123
4262
|
min_exp = round(np.mean([arg.min_exp for arg in args]))
|
4124
4263
|
extra_sf_lim = max([arg.extra_sf_lim for arg in args])
|
4125
4264
|
|
@@ -4136,9 +4275,6 @@ def function_with_rich_values(function, args, unc_function=None,
|
|
4136
4275
|
use_analytic_propagation = False
|
4137
4276
|
|
4138
4277
|
args_main = np.array([arg.main for arg in args])
|
4139
|
-
# print()
|
4140
|
-
# print(args)
|
4141
|
-
# print(args[0].expression)
|
4142
4278
|
with np.errstate(divide='ignore', invalid='ignore'):
|
4143
4279
|
main = function(*args_main)
|
4144
4280
|
output_size = np.array(main).size
|
@@ -4224,16 +4360,14 @@ def function_with_rich_values(function, args, unc_function=None,
|
|
4224
4360
|
|
4225
4361
|
mains = [main] if output_size == 1 else main
|
4226
4362
|
if unc_function is not None:
|
4227
|
-
|
4228
|
-
|
4363
|
+
uncs = []
|
4364
|
+
args_main = np.array([arg.main for arg in args_copy])
|
4365
|
+
for i in (0,1):
|
4366
|
+
args_unc = [arg.unc[i] for arg in args_copy]
|
4367
|
+
uncs += [unc_function(*args_main, *args_unc)]
|
4229
4368
|
uncs = [uncs] if output_size == 1 else uncs
|
4230
|
-
|
4231
|
-
|
4232
|
-
if not hasattr(uncs[k], '__iter__'):
|
4233
|
-
uncs[k] = [uncs[k]]*2
|
4234
|
-
uncs[k][1] = abs(uncs[k][1])
|
4235
|
-
if not hasattr(uncs,'__iter__'):
|
4236
|
-
uncs = [uncs]*output_size
|
4369
|
+
for k in range(output_size):
|
4370
|
+
uncs[k][1] = abs(uncs[k][1])
|
4237
4371
|
else:
|
4238
4372
|
inds_combs = list(itertools.product(*[[0,1,2]]*len(args)))
|
4239
4373
|
comb_main = tuple([1]*len(args))
|
@@ -4261,6 +4395,9 @@ def function_with_rich_values(function, args, unc_function=None,
|
|
4261
4395
|
real_k = RichValue(main_k.real, unc_k.real, domain=domain_k)
|
4262
4396
|
imag_k = RichValue(main_k.imag, unc_k.imag, domain=domain_k)
|
4263
4397
|
rval_k = ComplexRichValue(real_k, imag_k)
|
4398
|
+
rval_k.num_sf = num_sf
|
4399
|
+
rval_k.min_exp = min_exp
|
4400
|
+
rval_k.extra_sf_lim = extra_sf_lim
|
4264
4401
|
output += [rval_k]
|
4265
4402
|
|
4266
4403
|
else:
|
@@ -4336,6 +4473,43 @@ def function_with_rich_arrays(function, args, elementwise=False, **kwargs):
|
|
4336
4473
|
output : rich array / rich value
|
4337
4474
|
Result of the function.
|
4338
4475
|
"""
|
4476
|
+
if 'domain' in kwargs:
|
4477
|
+
domain = kwargs['domain']
|
4478
|
+
del kwargs['domain']
|
4479
|
+
else:
|
4480
|
+
domain = None
|
4481
|
+
distr = distr_with_rich_arrays(function, args, elementwise, **kwargs)
|
4482
|
+
if len(distr.shape) == 1:
|
4483
|
+
output = evaluate_distr(distr, domain, function, args, **kwargs)
|
4484
|
+
else:
|
4485
|
+
output_size = distr.shape[1]
|
4486
|
+
output = []
|
4487
|
+
for k in range(output_size):
|
4488
|
+
function_k = lambda *args: function(args)[k]
|
4489
|
+
rval_k = evaluate_distr(distr[:,k], domain, function_k, **kwargs)
|
4490
|
+
output += [rval_k]
|
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,:]
|
4502
|
+
output_type = RichArray if type(main) is np.ndarray else type(main)
|
4503
|
+
if output_type is tuple and output_size > 1:
|
4504
|
+
output = tuple(output)
|
4505
|
+
elif output_type is RichArray:
|
4506
|
+
output = np.array(output).view(RichArray)
|
4507
|
+
return output
|
4508
|
+
|
4509
|
+
def distr_with_rich_arrays(function, args, elementwise=False, **kwargs):
|
4510
|
+
"""
|
4511
|
+
Same as function_with_rich_arrays, but just returns the final distribution.
|
4512
|
+
"""
|
4339
4513
|
if type(args) not in (tuple, list):
|
4340
4514
|
args = [args]
|
4341
4515
|
args = [rich_array(arg) if type(arg) != RichArray else arg
|
@@ -4351,6 +4525,8 @@ def function_with_rich_arrays(function, args, elementwise=False, **kwargs):
|
|
4351
4525
|
if 'len_samples' not in kwargs:
|
4352
4526
|
kwargs['len_samples'] = int(len(args)**0.5
|
4353
4527
|
* defaultparams['size of samples'])
|
4528
|
+
if 'consider_intervs' in kwargs:
|
4529
|
+
del kwargs['consider_intervs']
|
4354
4530
|
if elementwise:
|
4355
4531
|
same_shapes = True
|
4356
4532
|
for arg in args[1:]:
|
@@ -4359,16 +4535,14 @@ def function_with_rich_arrays(function, args, elementwise=False, **kwargs):
|
|
4359
4535
|
break
|
4360
4536
|
if not same_shapes:
|
4361
4537
|
raise Exception('Input arrays have different shapes.')
|
4362
|
-
|
4538
|
+
distr = []
|
4363
4539
|
args_flat = np.array([arg.flatten() for arg in args])
|
4364
4540
|
for i in range(args[0].size):
|
4365
4541
|
args_i = np.array(args_flat)[:,i].tolist()
|
4366
|
-
|
4367
|
-
|
4368
|
-
|
4369
|
-
|
4370
|
-
array = array.view(RichArray)
|
4371
|
-
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
|
4372
4546
|
else:
|
4373
4547
|
if type(function) is str:
|
4374
4548
|
variables = list(np.concatenate(tuple(arg.variables for arg in args)))
|
@@ -4410,7 +4584,7 @@ def function_with_rich_arrays(function, args, elementwise=False, **kwargs):
|
|
4410
4584
|
alt_args = []
|
4411
4585
|
for arg in args:
|
4412
4586
|
alt_args += list(arg.flat)
|
4413
|
-
output =
|
4587
|
+
output = distr_with_rich_values(alt_function, alt_args, **kwargs)
|
4414
4588
|
return output
|
4415
4589
|
|
4416
4590
|
def fmean(array, function='None', inverse_function='None',
|
@@ -4524,12 +4698,12 @@ def errorbar(x, y, lims_factor=None, **kwargs):
|
|
4524
4698
|
xa, ya = rich_array(x), rich_array(y)
|
4525
4699
|
xc = rich_array([x]) if len(xa.shape) == 0 else xa
|
4526
4700
|
yc = rich_array([y]) if len(ya.shape) == 0 else ya
|
4527
|
-
if lims_factor
|
4528
|
-
lims_factor_x, lims_factor_y = None, None
|
4529
|
-
elif type(lims_factor) in (float, int):
|
4701
|
+
if type(lims_factor) in (float, int):
|
4530
4702
|
lims_factor_x, lims_factor_y = [lims_factor]*2
|
4531
4703
|
elif type(lims_factor) in (list, tuple):
|
4532
4704
|
lims_factor_x, lims_factor_y = lims_factor
|
4705
|
+
else:
|
4706
|
+
lims_factor_x, lims_factor_y = None, None
|
4533
4707
|
if lims_factor_x is None:
|
4534
4708
|
lims_factor_x = lim_factor(xc)
|
4535
4709
|
if lims_factor_y is None:
|
@@ -4884,6 +5058,10 @@ def _log10(x):
|
|
4884
5058
|
y = np.log10(x)
|
4885
5059
|
return y
|
4886
5060
|
|
5061
|
+
# Abbreviations from NumPy.
|
5062
|
+
inf = np.inf
|
5063
|
+
nan = np.nan
|
5064
|
+
|
4887
5065
|
# Functions for masking arrays.
|
4888
5066
|
def isnan(x):
|
4889
5067
|
x = rich_array(x) if type(x) is not RichArray else x
|
@@ -4979,6 +5157,7 @@ rich_df = rdataframe = rich_dataframe
|
|
4979
5157
|
function = function_with_rich_values
|
4980
5158
|
array_function = function_with_rich_arrays
|
4981
5159
|
distribution = distr_with_rich_values
|
5160
|
+
array_distribution = distr_with_rich_arrays
|
4982
5161
|
evaluate_distribution = evaluate_distr
|
4983
5162
|
center_and_uncertainties = center_and_uncs
|
4984
5163
|
is_not_a_number = is_nan = isnan
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: richvalues
|
3
|
-
Version: 4.0
|
3
|
+
Version: 4.1.0
|
4
4
|
Summary: Python library for working with uncertainties and upper/lower limits
|
5
5
|
Home-page: https://github.com/andresmegias/richvalues/
|
6
6
|
Author: Andrés Megías Toledano
|
@@ -15,7 +15,7 @@ License-File: LICENSE
|
|
15
15
|
|
16
16
|
RichValues is a Python 3 library for working with numeric values with uncertainties, upper/lower limits and finite intervals, which may be called _rich values_.
|
17
17
|
|
18
|
-
With it, one can import rich values written in plain text documents in an easily readable format, operate with them propagating the uncertainties automatically, and export them in the same formatting style as the import. It also allows to easily plot rich values and to make fits to any function, taking into account the uncertainties and the upper/limits or finite intervals. Moreover, correlations between variables are taken into account when performing calculations with rich values.
|
18
|
+
With it, one can import rich values written in plain text documents in an easily readable format, operate with them propagating the uncertainties automatically, and export them in the same formatting style as the import. It also allows to easily plot rich values and to make fits to any function, taking into account the uncertainties and the upper/lower limits or finite intervals. Moreover, correlations between variables are taken into account when performing calculations with rich values.
|
19
19
|
|
20
20
|
The libraries NumPy, Pandas, SciPy and Matplotlib are required by RichValues. A user guide and a quick tutorial are available on GitHub: https://github.com/andresmegias/richvalues/.
|
21
21
|
|
@@ -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',
|
Binary file
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|