richvalues 4.0.5__tar.gz → 4.1.1__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.1}/PKG-INFO +2 -2
- {richvalues-4.0.5 → richvalues-4.1.1}/README.md +1 -1
- {richvalues-4.0.5 → richvalues-4.1.1}/pyproject.toml +1 -1
- {richvalues-4.0.5 → richvalues-4.1.1}/richvalues/__init__.py +280 -99
- {richvalues-4.0.5 → richvalues-4.1.1}/richvalues.egg-info/PKG-INFO +2 -2
- {richvalues-4.0.5 → richvalues-4.1.1}/richvalues.egg-info/SOURCES.txt +0 -1
- {richvalues-4.0.5 → richvalues-4.1.1}/setup.py +1 -1
- richvalues-4.0.5/richvalues.egg-info/.DS_Store +0 -0
- {richvalues-4.0.5 → richvalues-4.1.1}/LICENSE +0 -0
- {richvalues-4.0.5 → richvalues-4.1.1}/richvalues.egg-info/dependency_links.txt +0 -0
- {richvalues-4.0.5 → richvalues-4.1.1}/richvalues.egg-info/requires.txt +0 -0
- {richvalues-4.0.5 → richvalues-4.1.1}/richvalues.egg-info/top_level.txt +0 -0
- {richvalues-4.0.5 → richvalues-4.1.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: richvalues
|
3
|
-
Version: 4.
|
3
|
+
Version: 4.1.1
|
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.
|
7
|
+
version = "4.1.1"
|
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.
|
40
|
+
__version__ = '4.1.1'
|
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,22 @@ 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
|
+
dy1 = dy1.replace('(-', '(')
|
807
|
+
dy2 = dy2.replace('(+', '(')
|
808
|
+
if dy1 == dy2:
|
809
|
+
text = '{}{} e{}'.format(y, dy1, a)
|
810
|
+
else:
|
811
|
+
text = '{}{}{} e{}'.format(y, dy1, dy2, a)
|
769
812
|
if not use_exp:
|
770
813
|
text = text.replace(' e0','')
|
771
814
|
else:
|
@@ -848,6 +891,7 @@ class RichValue():
|
|
848
891
|
is_range = self.is_range
|
849
892
|
is_int = self.is_int
|
850
893
|
min_exp = abs(self.min_exp)
|
894
|
+
max_dec = abs(self.max_dec)
|
851
895
|
extra_sf_lim = self.extra_sf_lim
|
852
896
|
show_domain = defaultparams['show domain']
|
853
897
|
use_exp = True
|
@@ -871,7 +915,7 @@ class RichValue():
|
|
871
915
|
else False)
|
872
916
|
if is_numeric:
|
873
917
|
if not is_range:
|
874
|
-
_, unc_r = round_sf_uncs(x, dx, n, min_exp, extra_sf_lim)
|
918
|
+
_, unc_r = round_sf_uncs(x, dx, n, min_exp, np.inf, extra_sf_lim)
|
875
919
|
unc_r = np.array(unc_r, float)
|
876
920
|
if not is_range and not use_exp:
|
877
921
|
if not self.is_lim:
|
@@ -883,11 +927,11 @@ class RichValue():
|
|
883
927
|
round_sf(x, n, np.inf, extra_sf_lim))
|
884
928
|
text = '${}$'.format(y)
|
885
929
|
else:
|
886
|
-
y, dy = round_sf_unc(x, dx[0], n,
|
887
|
-
|
930
|
+
y, dy = round_sf_unc(x, dx[0], n, min_exp,
|
931
|
+
max_dec, extra_sf_lim)
|
888
932
|
text = '${} \pm {}$'.format(y, dy)
|
889
933
|
else:
|
890
|
-
y, dy = round_sf_uncs(x, dx, n, min_exp, extra_sf_lim)
|
934
|
+
y, dy = round_sf_uncs(x, dx, n, min_exp, max_dec, extra_sf_lim)
|
891
935
|
text = '$'+y + '_{-'+dy[0]+'}^{+'+dy[1]+'}$'
|
892
936
|
else:
|
893
937
|
if is_lolim:
|
@@ -915,8 +959,8 @@ class RichValue():
|
|
915
959
|
text = ('${} {}'.format(y, mult_symbol)
|
916
960
|
+ ' 10^{'+a+'}$')
|
917
961
|
else:
|
918
|
-
y, dy = round_sf_unc(x, dx[0], n,
|
919
|
-
|
962
|
+
y, dy = round_sf_unc(x, dx[0], n, min_exp,
|
963
|
+
max_dec, extra_sf_lim)
|
920
964
|
if 'e' in y:
|
921
965
|
y, a = y.split('e')
|
922
966
|
dy, a = dy.split('e')
|
@@ -926,8 +970,8 @@ class RichValue():
|
|
926
970
|
text = ('$({} \pm {}) '.format(y, dy)
|
927
971
|
+ mult_symbol + ' 10^{'+a+'}$')
|
928
972
|
else:
|
929
|
-
y, dy = round_sf_uncs(x, [dx[0], dx[1]], n,
|
930
|
-
|
973
|
+
y, dy = round_sf_uncs(x, [dx[0], dx[1]], n, min_exp,
|
974
|
+
max_dec, extra_sf_lim)
|
931
975
|
if 'e' in y:
|
932
976
|
y, a = y.split('e')
|
933
977
|
dy1, a = dy[0].split('e')
|
@@ -945,13 +989,13 @@ class RichValue():
|
|
945
989
|
elif is_uplim:
|
946
990
|
symbol = '<'
|
947
991
|
y = int(np.ceil(x)) if is_int else x
|
948
|
-
min_exp = 0
|
949
992
|
y = round_sf(y, n, min_exp, extra_sf_lim)
|
950
|
-
|
951
|
-
|
993
|
+
if 'e' in y:
|
994
|
+
y, a = y.split('e')
|
995
|
+
else:
|
996
|
+
a = '0'
|
952
997
|
text = ('${} {} {}'.format(symbol, y, mult_symbol)
|
953
998
|
+ ' 10^{'+a+'}$')
|
954
|
-
text = text.replace('e-0', 'e-').replace('e+','e')
|
955
999
|
a = int(text.split('10^{')[1].split('}')[0])
|
956
1000
|
if abs(a) < min_exp:
|
957
1001
|
y = RichValue(x, dx, is_lolim, is_uplim,
|
@@ -962,7 +1006,8 @@ class RichValue():
|
|
962
1006
|
text = y.latex(*kwargs)
|
963
1007
|
if (not use_extra_sf_in_exacts and omit_ones_in_sci_notation
|
964
1008
|
and dx[0] == dx[1] and dx[0] == 0 or np.isnan(dx[0])):
|
965
|
-
|
1009
|
+
if '.' not in text:
|
1010
|
+
text = text.replace('1 {} '.format(mult_symbol), '')
|
966
1011
|
else:
|
967
1012
|
x1 = RichValue(main - unc[0], domain=domain)
|
968
1013
|
x2 = RichValue(main + unc[1], domain=domain)
|
@@ -1452,6 +1497,11 @@ class RichValue():
|
|
1452
1497
|
@minimum_exponent_for_scientific_notation.setter
|
1453
1498
|
def minimum_exponent_for_scientific_notation(self, x): self.min_exp = x
|
1454
1499
|
|
1500
|
+
@property
|
1501
|
+
def maximum_number_of_decimals(self): return self.max_dec
|
1502
|
+
@maximum_number_of_decimals.setter
|
1503
|
+
def maximum_number_of_decimals(self, x): self.max_dec = x
|
1504
|
+
|
1455
1505
|
@property
|
1456
1506
|
def limit_for_extra_significant_figure(self): return self.extra_sf_lim
|
1457
1507
|
@limit_for_extra_significant_figure.setter
|
@@ -1642,6 +1692,9 @@ class RichArray(np.ndarray):
|
|
1642
1692
|
def min_exps(self):
|
1643
1693
|
return np.array([x.min_exp for x in self.flat]).reshape(self.shape)
|
1644
1694
|
@property
|
1695
|
+
def max_decs(self):
|
1696
|
+
return np.array([x.max_dec for x in self.flat]).reshape(self.shape)
|
1697
|
+
@property
|
1645
1698
|
def extra_sf_lims(self):
|
1646
1699
|
return np.array([x.extra_sf_lim for x in self.flat]).reshape(self.shape)
|
1647
1700
|
@property
|
@@ -1660,6 +1713,12 @@ class RichArray(np.ndarray):
|
|
1660
1713
|
def are_consts(self):
|
1661
1714
|
return np.array([x.is_const for x in self.flat]).reshape(self.shape)
|
1662
1715
|
@property
|
1716
|
+
def are_nans(self):
|
1717
|
+
return np.array([x.is_nan for x in self.flat]).reshape(self.shape)
|
1718
|
+
@property
|
1719
|
+
def are_infs(self):
|
1720
|
+
return np.array([x.is_inf for x in self.flat]).reshape(self.shape)
|
1721
|
+
@property
|
1663
1722
|
def centers(self):
|
1664
1723
|
return np.array([x.center for x in self.flat]).reshape(self.shape)
|
1665
1724
|
@property
|
@@ -1738,6 +1797,7 @@ class RichArray(np.ndarray):
|
|
1738
1797
|
abbreviations = {'is integer': 'is_int',
|
1739
1798
|
'number of significant figures': 'num_sf',
|
1740
1799
|
'minimum exponent for scientific notation': 'min_exp',
|
1800
|
+
'maximum number of decimals': 'max_dec',
|
1741
1801
|
'limit for extra significant figure': 'extra_sf_lim'}
|
1742
1802
|
attributes = ['domain'] + list(abbreviations.values())
|
1743
1803
|
for entry in abbreviations:
|
@@ -1757,6 +1817,8 @@ class RichArray(np.ndarray):
|
|
1757
1817
|
x.num_sf = params['num_sf']
|
1758
1818
|
if 'min_exp' in params:
|
1759
1819
|
x.min_exp = params['min_exp']
|
1820
|
+
if 'max_dec' in params:
|
1821
|
+
x.max_dec = params['max_dec']
|
1760
1822
|
if 'extra_sf_lim' in params:
|
1761
1823
|
x.extra_sf_lim = params['extra_sf_lim']
|
1762
1824
|
|
@@ -1799,8 +1861,7 @@ class RichArray(np.ndarray):
|
|
1799
1861
|
return np.array(self).mean()
|
1800
1862
|
|
1801
1863
|
def std(self):
|
1802
|
-
std_function = lambda u: (np.sum((u
|
1803
|
-
/ len(self - 1))**0.5
|
1864
|
+
std_function = lambda u: (np.sum((u-u.mean())**2)/(len(self)-1))**0.5
|
1804
1865
|
return self.function(std_function)
|
1805
1866
|
|
1806
1867
|
# Attribute acronyms.
|
@@ -1812,11 +1873,14 @@ class RichArray(np.ndarray):
|
|
1812
1873
|
are_integers = are_ints
|
1813
1874
|
numbers_of_significant_figures = nums_sf
|
1814
1875
|
minimum_exponents_for_scientific_notation = min_exps
|
1876
|
+
maximum_number_of_decimals = max_decs
|
1815
1877
|
limits_for_extra_significant_figure = extra_sf_lims
|
1816
1878
|
are_limits = are_lims
|
1817
1879
|
are_intervals = are_intervs
|
1818
1880
|
are_centereds = are_centrs
|
1819
1881
|
are_constants = are_consts
|
1882
|
+
are_not_a_number = are_nans
|
1883
|
+
are_infinites = are_infs
|
1820
1884
|
relative_uncertainties = rel_uncs
|
1821
1885
|
signals_to_noises = signals_noises
|
1822
1886
|
amplitudes = ampls
|
@@ -1905,6 +1969,8 @@ class RichDataFrame(pd.DataFrame):
|
|
1905
1969
|
@property
|
1906
1970
|
def min_exps(self): return self._property('min_exps')
|
1907
1971
|
@property
|
1972
|
+
def max_decs(self): return self._property('max_decs')
|
1973
|
+
@property
|
1908
1974
|
def extra_sf_lims(self): return self._property('extra_sf_lims')
|
1909
1975
|
@property
|
1910
1976
|
def are_lims(self): return self._property('are_lims')
|
@@ -1917,6 +1983,10 @@ class RichDataFrame(pd.DataFrame):
|
|
1917
1983
|
@property
|
1918
1984
|
def are_consts(self): return self._property('are_consts')
|
1919
1985
|
@property
|
1986
|
+
def are_nans(self): return self._property('are_nans')
|
1987
|
+
@property
|
1988
|
+
def are_infs(self): return self._property('are_infs')
|
1989
|
+
@property
|
1920
1990
|
def centers(self): return self._property('centers')
|
1921
1991
|
@property
|
1922
1992
|
def rel_uncs(self): return self._property2('rel_uncs')
|
@@ -1964,6 +2034,7 @@ class RichDataFrame(pd.DataFrame):
|
|
1964
2034
|
abbreviations = {'is integer': 'is_int',
|
1965
2035
|
'number of significant figures': 'num_sf',
|
1966
2036
|
'minimum exponent for scientific notation': 'min_exp',
|
2037
|
+
'maximum number of decimals': 'max_dec',
|
1967
2038
|
'limit for extra significant figure': 'extra_sf_lim'}
|
1968
2039
|
attributes = ['domain'] + list(abbreviations.values())
|
1969
2040
|
for entry in abbreviations:
|
@@ -1984,6 +2055,7 @@ class RichDataFrame(pd.DataFrame):
|
|
1984
2055
|
set_is_int = 'is_int' in params
|
1985
2056
|
set_num_sf = 'num_sf' in params
|
1986
2057
|
set_min_exp = 'min_exp' in params
|
2058
|
+
set_max_dec = 'max_dec' in params
|
1987
2059
|
set_extra_sf_lim = 'extra_sf_lim' in params
|
1988
2060
|
row_inds = self.index
|
1989
2061
|
for col in self:
|
@@ -2002,6 +2074,9 @@ class RichDataFrame(pd.DataFrame):
|
|
2002
2074
|
if set_min_exp and col in params['min_exp']:
|
2003
2075
|
for i in row_inds:
|
2004
2076
|
self[col][i].min_exp = params['min_exp'][col]
|
2077
|
+
if set_max_dec and col in params['max_dec']:
|
2078
|
+
for i in row_inds:
|
2079
|
+
self[col][i].max_dec = params['max_dec'][col]
|
2005
2080
|
if set_extra_sf_lim and col in params['extra_sf_lim']:
|
2006
2081
|
for i in row_inds:
|
2007
2082
|
self[col][i].extra_sf_lim = params['extra_sf_lim'][col]
|
@@ -2060,7 +2135,8 @@ class RichDataFrame(pd.DataFrame):
|
|
2060
2135
|
new_row = pd.DataFrame(new_row, idex=[0])
|
2061
2136
|
return new_row
|
2062
2137
|
|
2063
|
-
def latex(self, return_df=False,
|
2138
|
+
def latex(self, return_df=False, export_frame=True, export_index=True,
|
2139
|
+
row_sep='\\tabularnewline', **kwargs):
|
2064
2140
|
"""Return the content of the dataframe as a table in LaTeX format."""
|
2065
2141
|
row_sep = ' ' + row_sep + ' \n'
|
2066
2142
|
df = copy.copy(self)
|
@@ -2075,17 +2151,35 @@ class RichDataFrame(pd.DataFrame):
|
|
2075
2151
|
if return_df:
|
2076
2152
|
output = df
|
2077
2153
|
else:
|
2154
|
+
columns = list(df.columns)
|
2155
|
+
num_columns = len(columns)
|
2078
2156
|
text = ''
|
2157
|
+
if export_frame:
|
2158
|
+
text += '\\renewcommand*{\\arraystretch}{1.4}' + ' \n'
|
2159
|
+
text += ('\\begin{tabular}{' + 'l'*export_index
|
2160
|
+
+ num_columns*'c' + '}' + ' \n')
|
2161
|
+
text += '\\hline \n'
|
2162
|
+
columns = ['{\\bf ' + column + '}' for column in columns]
|
2163
|
+
index_name = df.index.name if df.index.name is not None else ' '
|
2164
|
+
if export_index:
|
2165
|
+
columns = ['{\\bf ' + index_name + '}'] + columns
|
2166
|
+
if export_frame:
|
2167
|
+
text += ' & '.join(columns) + row_sep + '\\hline \n'
|
2079
2168
|
rows = []
|
2080
|
-
for (
|
2081
|
-
cols = []
|
2169
|
+
for (ind,row) in df.iterrows():
|
2170
|
+
cols = [str(ind)] if export_index else []
|
2082
2171
|
for (j,column) in enumerate(df):
|
2083
2172
|
entry = str(row[column])
|
2084
2173
|
if entry == 'nan':
|
2085
2174
|
entry = '...'
|
2086
2175
|
cols += [entry]
|
2087
2176
|
rows += [' & '.join(cols)]
|
2088
|
-
text
|
2177
|
+
text += row_sep.join(rows)
|
2178
|
+
if export_frame:
|
2179
|
+
text += row_sep
|
2180
|
+
text += '\\hline \n'
|
2181
|
+
text += '\\end{tabular}' + ' \n'
|
2182
|
+
text += '\\renewcommand*{\\arraystretch}{1.0}' + ' \n'
|
2089
2183
|
output = text
|
2090
2184
|
return output
|
2091
2185
|
|
@@ -2118,6 +2212,8 @@ class RichDataFrame(pd.DataFrame):
|
|
2118
2212
|
are_intervals = are_intervs
|
2119
2213
|
are_centereds = are_centrs
|
2120
2214
|
are_constants = are_consts
|
2215
|
+
are_not_a_number = are_nans
|
2216
|
+
are_infinites = are_infs
|
2121
2217
|
relative_uncertainties = rel_uncs
|
2122
2218
|
signals_to_noises = signals_noises
|
2123
2219
|
amplitudes = ampls
|
@@ -2171,6 +2267,9 @@ class RichSeries(pd.Series):
|
|
2171
2267
|
def min_exps(self):
|
2172
2268
|
return pd.Series(self.values.view(RichArray).min_exps, self.index)
|
2173
2269
|
@property
|
2270
|
+
def max_decs(self):
|
2271
|
+
return pd.Series(self.values.view(RichArray).max_decs, self.index)
|
2272
|
+
@property
|
2174
2273
|
def extra_sf_lims(self):
|
2175
2274
|
return pd.Series(self.values.view(RichArray).extra_sf_lim, self.index)
|
2176
2275
|
@property
|
@@ -2189,6 +2288,12 @@ class RichSeries(pd.Series):
|
|
2189
2288
|
def are_consts(self):
|
2190
2289
|
return pd.Series(self.values.view(RichArray).are_consts, self.index)
|
2191
2290
|
@property
|
2291
|
+
def are_nans(self):
|
2292
|
+
return pd.Series(self.values.view(RichArray).are_nans, self.index)
|
2293
|
+
@property
|
2294
|
+
def are_infs(self):
|
2295
|
+
return pd.Series(self.values.view(RichArray).are_infs, self.index)
|
2296
|
+
@property
|
2192
2297
|
def centers(self):
|
2193
2298
|
return pd.Series(self.values.view(RichArray).centers, self.index)
|
2194
2299
|
@property
|
@@ -2250,10 +2355,13 @@ class RichSeries(pd.Series):
|
|
2250
2355
|
are_integers = are_ints
|
2251
2356
|
numbers_of_scientific_figures = nums_sf
|
2252
2357
|
minimum_exponents_for_scientific_notation = min_exps
|
2358
|
+
maximum_numbers_of_decimals = max_decs
|
2253
2359
|
are_limits = are_lims
|
2254
2360
|
are_intervals = are_intervs
|
2255
2361
|
are_centereds = are_centrs
|
2256
2362
|
are_constants = are_consts
|
2363
|
+
are_not_a_number = are_nans
|
2364
|
+
are_infinites = are_infs
|
2257
2365
|
relative_uncertainties = rel_uncs
|
2258
2366
|
signals_to_noises = signals_noises
|
2259
2367
|
amplitudes = ampls
|
@@ -2305,11 +2413,14 @@ class ComplexRichValue():
|
|
2305
2413
|
|
2306
2414
|
num_sf = min(real.num_sf, imag.num_sf)
|
2307
2415
|
min_exp = round(np.mean([real.min_exp, imag.min_exp]))
|
2416
|
+
max_dec = min(real.max_dec, imag.max_dec)
|
2308
2417
|
extra_sf_lim = min(real.extra_sf_lim, imag.extra_sf_lim)
|
2309
2418
|
real.num_sf = num_sf
|
2310
2419
|
imag.num_sf = num_sf
|
2311
2420
|
real.min_exp = min_exp
|
2312
2421
|
imag.min_exp = min_exp
|
2422
|
+
real.max_dec = max_dec
|
2423
|
+
real.max_dec = max_dec
|
2313
2424
|
real.extra_sf_lim = extra_sf_lim
|
2314
2425
|
imag.extra_sf_lim = extra_sf_lim
|
2315
2426
|
|
@@ -2352,16 +2463,21 @@ class ComplexRichValue():
|
|
2352
2463
|
self.imag.num_sf = x
|
2353
2464
|
|
2354
2465
|
@property
|
2355
|
-
def min_exp(self): return round(np.mean([self.real.min_exp,
|
2356
|
-
self.imag.min_exp]))
|
2466
|
+
def min_exp(self): return round(np.mean([self.real.min_exp, self.imag.min_exp]))
|
2357
2467
|
@min_exp.setter
|
2358
2468
|
def min_exp(self, x):
|
2359
2469
|
self.real.min_exp = x
|
2360
2470
|
self.imag.min_exp = x
|
2471
|
+
|
2472
|
+
@property
|
2473
|
+
def max_dec(self): return min(self.real.max_dec, self.imag.max_dec)
|
2474
|
+
@max_dec.setter
|
2475
|
+
def max_dec(self, x):
|
2476
|
+
self.real.max_dec = x
|
2477
|
+
self.imag.max_dec = x
|
2361
2478
|
|
2362
2479
|
@property
|
2363
|
-
def extra_sf_lim(self): return max(self.real.extra_sf_lim,
|
2364
|
-
self.imag.extra_sf_lim)
|
2480
|
+
def extra_sf_lim(self): return max(self.real.extra_sf_lim, self.imag.extra_sf_lim)
|
2365
2481
|
@extra_sf_lim.setter
|
2366
2482
|
def extra_sf_lim(self, x):
|
2367
2483
|
self.real.extra_sf_lim = x
|
@@ -2663,7 +2779,7 @@ def add_rich_values(x, y):
|
|
2663
2779
|
is_int = x.is_int and y.is_int
|
2664
2780
|
domain = [x.domain[0] + y.domain[0], x.domain[1] + y.domain[1]]
|
2665
2781
|
sigmas = defaultparams['sigmas to use approximate uncertainty propagation']
|
2666
|
-
if x.is_exact or y.is_exact:
|
2782
|
+
if (x.is_exact or y.is_exact) and (x.is_interv or y.is_interv):
|
2667
2783
|
z = list(np.array(x.interval()) + np.array(y.interval()))
|
2668
2784
|
z = RichValue(z, domain=domain, is_int=is_int)
|
2669
2785
|
elif (not (x.is_interv or y.is_interv)
|
@@ -2687,7 +2803,7 @@ def multiply_rich_values(x, y):
|
|
2687
2803
|
is_int = x.is_int and y.is_int
|
2688
2804
|
domain = propagate_domain(x.domain, y.domain, lambda a,b: a*b)
|
2689
2805
|
sigmas = defaultparams['sigmas to use approximate uncertainty propagation']
|
2690
|
-
if x.is_exact or y.is_exact:
|
2806
|
+
if (x.is_exact or y.is_exact) and (x.is_interv or y.is_interv):
|
2691
2807
|
z = list(np.array(x.interval()) * np.array(y.interval()))
|
2692
2808
|
z = RichValue(z, domain=domain, is_int=is_int)
|
2693
2809
|
elif (not (x.is_interv or y.is_interv)
|
@@ -2933,7 +3049,7 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
2933
3049
|
def parse_as_rich_value(text):
|
2934
3050
|
"""Obtain the properties of the input text as a rich value."""
|
2935
3051
|
def parse_value(text):
|
2936
|
-
"""Parse input text as a value."""
|
3052
|
+
"""Parse input text as a numeric value."""
|
2937
3053
|
text = str(text)
|
2938
3054
|
if any([char.isalpha() for char in text.replace(' e','')]):
|
2939
3055
|
for short_name in abbreviations:
|
@@ -2992,8 +3108,24 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
2992
3108
|
is_uplim, is_lolim = False, False
|
2993
3109
|
text = (text.replace('+-', '+/-').replace(' -', '-')
|
2994
3110
|
.replace(' +/-', '+/-').replace('+/- ', '+/-'))
|
2995
|
-
|
2996
|
-
|
3111
|
+
x_dx, e = text.split(' ')
|
3112
|
+
if ')' in text:
|
3113
|
+
if text.count(')') == 1:
|
3114
|
+
x, dx = x_dx.split('(')
|
3115
|
+
dx = dx[:-1]
|
3116
|
+
dx1, dx2 = dx
|
3117
|
+
else:
|
3118
|
+
x, dx1, dx2 = x_dx.split('(')
|
3119
|
+
dx1 = dx1[:-1]
|
3120
|
+
dx2 = dx2[:-1]
|
3121
|
+
if dx1.startswith('+'):
|
3122
|
+
dx1, dx2 = dx2, dx1
|
3123
|
+
dx1 = dx1[1:]
|
3124
|
+
dx2 = dx2[1:]
|
3125
|
+
d = len(x.split('.')[1]) if '.' in x else 0
|
3126
|
+
dx1 = '{:f}'.format(float(dx1)*10**(-d))
|
3127
|
+
dx2 = '{:f}'.format(float(dx2)*10**(-d))
|
3128
|
+
elif '+/-' in text:
|
2997
3129
|
x, dx = x_dx.split('+/-')
|
2998
3130
|
text = '{}-{}+{} {}'.format(x, dx, dx, e)
|
2999
3131
|
dx1, dx2 = dx, dx
|
@@ -3014,10 +3146,9 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
3014
3146
|
else:
|
3015
3147
|
x = text.split(' ')[0]
|
3016
3148
|
dx1, dx2 = '0', '0'
|
3017
|
-
|
3018
|
-
|
3019
|
-
|
3020
|
-
dx2 = '{} {}'.format(dx2 ,e)
|
3149
|
+
x = '{} {}'.format(x, e)
|
3150
|
+
dx1 = '{} {}'.format(dx1, e)
|
3151
|
+
dx2 = '{} {}'.format(dx2, e)
|
3021
3152
|
x = parse_value(x)
|
3022
3153
|
dx1 = parse_value(dx1)
|
3023
3154
|
dx2 = parse_value(dx2)
|
@@ -3070,7 +3201,7 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
3070
3201
|
unc = 0
|
3071
3202
|
is_lolim, is_uplim, is_range = False, False, True
|
3072
3203
|
min_exp = round(np.mean([me1, me2]))
|
3073
|
-
extra_sf_lim =
|
3204
|
+
extra_sf_lim = max(el1, el2)
|
3074
3205
|
return (main, unc, is_lolim, is_uplim, is_range, domain,
|
3075
3206
|
min_exp, extra_sf_lim)
|
3076
3207
|
|
@@ -3203,7 +3334,7 @@ def rich_array(array, domain=None, is_int=None,
|
|
3203
3334
|
rarray = RichArray(mains, uncs, are_lolims, are_uplims, are_ranges,
|
3204
3335
|
domains, are_ints, variables, expressions)
|
3205
3336
|
min_exp = round(np.mean(min_exps))
|
3206
|
-
extra_sf_lim =
|
3337
|
+
extra_sf_lim = max(extra_sf_lims)
|
3207
3338
|
rarray.set_params({'min_exp': min_exp, 'extra_sf_lim': extra_sf_lim})
|
3208
3339
|
return rarray
|
3209
3340
|
|
@@ -3272,8 +3403,10 @@ def rich_dataframe(df, domains=None, are_ints=None,
|
|
3272
3403
|
domain = defaultparams['domain']
|
3273
3404
|
if is_int is None:
|
3274
3405
|
is_int = defaultparams['assume integers']
|
3275
|
-
|
3276
|
-
|
3406
|
+
try:
|
3407
|
+
entry = rich_value(text, domain, is_int, use_default_extra_sf_lim)
|
3408
|
+
except:
|
3409
|
+
entry = text
|
3277
3410
|
if is_rich_value or is_number:
|
3278
3411
|
df.at[i,col] = entry
|
3279
3412
|
rdf = RichDataFrame(df)
|
@@ -3582,7 +3715,7 @@ def loguniform_distribution(low=-1, high=1, size=1,
|
|
3582
3715
|
return distr
|
3583
3716
|
|
3584
3717
|
def distr_with_rich_values(function, args, len_samples=None,
|
3585
|
-
is_vectorizable=False):
|
3718
|
+
is_vectorizable=False, **kwargs):
|
3586
3719
|
"""
|
3587
3720
|
Same as function_with_rich_values, but just returns the final distribution.
|
3588
3721
|
"""
|
@@ -3688,7 +3821,7 @@ def remove_zero_infs(interval, zero_log, inf_log):
|
|
3688
3821
|
return new_interval
|
3689
3822
|
|
3690
3823
|
def evaluate_distr(distr, domain=None, function=None, args=None,
|
3691
|
-
len_samples=None, is_vectorizable=False, consider_intervs=
|
3824
|
+
len_samples=None, is_vectorizable=False, consider_intervs=None,
|
3692
3825
|
is_domain_cyclic=False, lims_fraction=None, num_reps_lims=None,
|
3693
3826
|
save_pdf=None, **kwargs):
|
3694
3827
|
"""
|
@@ -3774,10 +3907,17 @@ def evaluate_distr(distr, domain=None, function=None, args=None,
|
|
3774
3907
|
return tuple(all_vars)
|
3775
3908
|
|
3776
3909
|
if args is not None:
|
3910
|
+
if type(args) is np.ndarray:
|
3911
|
+
args = [rich_value(arg) for arg in args]
|
3777
3912
|
if type(args) not in (tuple, list):
|
3778
3913
|
args = [args]
|
3779
|
-
|
3780
|
-
|
3914
|
+
if type(args[0]) is not RichArray:
|
3915
|
+
args = [rich_value(arg) if type(arg) not in
|
3916
|
+
(RichValue, ComplexRichValue) else arg for arg in args]
|
3917
|
+
if consider_intervs is None:
|
3918
|
+
consider_intervs = True
|
3919
|
+
if args is not None and all([arg.is_centr for arg in args]):
|
3920
|
+
consider_intervs = False
|
3781
3921
|
|
3782
3922
|
distr = np.array(distr)
|
3783
3923
|
|
@@ -4076,6 +4216,7 @@ def function_with_rich_values(function, args, unc_function=None,
|
|
4076
4216
|
args = [args]
|
4077
4217
|
args = [rich_value(arg) if type(arg) not in (RichValue, ComplexRichValue)
|
4078
4218
|
else arg for arg in args]
|
4219
|
+
args_copy = copy.copy(args)
|
4079
4220
|
|
4080
4221
|
input_function = copy.copy(function)
|
4081
4222
|
if type(function) is str:
|
@@ -4119,7 +4260,7 @@ def function_with_rich_values(function, args, unc_function=None,
|
|
4119
4260
|
|
4120
4261
|
if len_samples is None:
|
4121
4262
|
len_samples = int(len(args)**0.5 * defaultparams['size of samples'])
|
4122
|
-
num_sf =
|
4263
|
+
num_sf = int(np.median([arg.num_sf for arg in args]))
|
4123
4264
|
min_exp = round(np.mean([arg.min_exp for arg in args]))
|
4124
4265
|
extra_sf_lim = max([arg.extra_sf_lim for arg in args])
|
4125
4266
|
|
@@ -4136,9 +4277,6 @@ def function_with_rich_values(function, args, unc_function=None,
|
|
4136
4277
|
use_analytic_propagation = False
|
4137
4278
|
|
4138
4279
|
args_main = np.array([arg.main for arg in args])
|
4139
|
-
# print()
|
4140
|
-
# print(args)
|
4141
|
-
# print(args[0].expression)
|
4142
4280
|
with np.errstate(divide='ignore', invalid='ignore'):
|
4143
4281
|
main = function(*args_main)
|
4144
4282
|
output_size = np.array(main).size
|
@@ -4224,16 +4362,14 @@ def function_with_rich_values(function, args, unc_function=None,
|
|
4224
4362
|
|
4225
4363
|
mains = [main] if output_size == 1 else main
|
4226
4364
|
if unc_function is not None:
|
4227
|
-
|
4228
|
-
|
4365
|
+
uncs = []
|
4366
|
+
args_main = np.array([arg.main for arg in args_copy])
|
4367
|
+
for i in (0,1):
|
4368
|
+
args_unc = [arg.unc[i] for arg in args_copy]
|
4369
|
+
uncs += [unc_function(*args_main, *args_unc)]
|
4229
4370
|
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
|
4371
|
+
for k in range(output_size):
|
4372
|
+
uncs[k][1] = abs(uncs[k][1])
|
4237
4373
|
else:
|
4238
4374
|
inds_combs = list(itertools.product(*[[0,1,2]]*len(args)))
|
4239
4375
|
comb_main = tuple([1]*len(args))
|
@@ -4261,6 +4397,9 @@ def function_with_rich_values(function, args, unc_function=None,
|
|
4261
4397
|
real_k = RichValue(main_k.real, unc_k.real, domain=domain_k)
|
4262
4398
|
imag_k = RichValue(main_k.imag, unc_k.imag, domain=domain_k)
|
4263
4399
|
rval_k = ComplexRichValue(real_k, imag_k)
|
4400
|
+
rval_k.num_sf = num_sf
|
4401
|
+
rval_k.min_exp = min_exp
|
4402
|
+
rval_k.extra_sf_lim = extra_sf_lim
|
4264
4403
|
output += [rval_k]
|
4265
4404
|
|
4266
4405
|
else:
|
@@ -4336,6 +4475,43 @@ def function_with_rich_arrays(function, args, elementwise=False, **kwargs):
|
|
4336
4475
|
output : rich array / rich value
|
4337
4476
|
Result of the function.
|
4338
4477
|
"""
|
4478
|
+
if 'domain' in kwargs:
|
4479
|
+
domain = kwargs['domain']
|
4480
|
+
del kwargs['domain']
|
4481
|
+
else:
|
4482
|
+
domain = None
|
4483
|
+
distr = distr_with_rich_arrays(function, args, elementwise, **kwargs)
|
4484
|
+
if len(distr.shape) == 1:
|
4485
|
+
output = evaluate_distr(distr, domain, function, args, **kwargs)
|
4486
|
+
else:
|
4487
|
+
output_size = distr.shape[1]
|
4488
|
+
output = []
|
4489
|
+
for k in range(output_size):
|
4490
|
+
function_k = lambda *args: function(args)[k]
|
4491
|
+
rval_k = evaluate_distr(distr[:,k], domain, function_k, **kwargs)
|
4492
|
+
output += [rval_k]
|
4493
|
+
if type(args) not in (tuple, list):
|
4494
|
+
args = [args]
|
4495
|
+
for (i,arg) in enumerate(args):
|
4496
|
+
if type(arg) is not RichArray:
|
4497
|
+
args[i] = RichArray(arg)
|
4498
|
+
args_mains = [arg.mains for arg in args]
|
4499
|
+
if type(function) is not str:
|
4500
|
+
with np.errstate(divide='ignore', invalid='ignore'):
|
4501
|
+
main = function(*args_mains)
|
4502
|
+
else:
|
4503
|
+
main = distr[0,:]
|
4504
|
+
output_type = RichArray if type(main) is np.ndarray else type(main)
|
4505
|
+
if output_type is tuple and output_size > 1:
|
4506
|
+
output = tuple(output)
|
4507
|
+
elif output_type is RichArray:
|
4508
|
+
output = np.array(output).view(RichArray)
|
4509
|
+
return output
|
4510
|
+
|
4511
|
+
def distr_with_rich_arrays(function, args, elementwise=False, **kwargs):
|
4512
|
+
"""
|
4513
|
+
Same as function_with_rich_arrays, but just returns the final distribution.
|
4514
|
+
"""
|
4339
4515
|
if type(args) not in (tuple, list):
|
4340
4516
|
args = [args]
|
4341
4517
|
args = [rich_array(arg) if type(arg) != RichArray else arg
|
@@ -4351,6 +4527,8 @@ def function_with_rich_arrays(function, args, elementwise=False, **kwargs):
|
|
4351
4527
|
if 'len_samples' not in kwargs:
|
4352
4528
|
kwargs['len_samples'] = int(len(args)**0.5
|
4353
4529
|
* defaultparams['size of samples'])
|
4530
|
+
if 'consider_intervs' in kwargs:
|
4531
|
+
del kwargs['consider_intervs']
|
4354
4532
|
if elementwise:
|
4355
4533
|
same_shapes = True
|
4356
4534
|
for arg in args[1:]:
|
@@ -4359,16 +4537,14 @@ def function_with_rich_arrays(function, args, elementwise=False, **kwargs):
|
|
4359
4537
|
break
|
4360
4538
|
if not same_shapes:
|
4361
4539
|
raise Exception('Input arrays have different shapes.')
|
4362
|
-
|
4540
|
+
distr = []
|
4363
4541
|
args_flat = np.array([arg.flatten() for arg in args])
|
4364
4542
|
for i in range(args[0].size):
|
4365
4543
|
args_i = np.array(args_flat)[:,i].tolist()
|
4366
|
-
|
4367
|
-
|
4368
|
-
|
4369
|
-
|
4370
|
-
array = array.view(RichArray)
|
4371
|
-
output = array
|
4544
|
+
distr_i = distr_with_rich_values(function, args_i, **kwargs)
|
4545
|
+
distr += [distr_i]
|
4546
|
+
distr = np.array(distr).T
|
4547
|
+
output = distr
|
4372
4548
|
else:
|
4373
4549
|
if type(function) is str:
|
4374
4550
|
variables = list(np.concatenate(tuple(arg.variables for arg in args)))
|
@@ -4410,7 +4586,7 @@ def function_with_rich_arrays(function, args, elementwise=False, **kwargs):
|
|
4410
4586
|
alt_args = []
|
4411
4587
|
for arg in args:
|
4412
4588
|
alt_args += list(arg.flat)
|
4413
|
-
output =
|
4589
|
+
output = distr_with_rich_values(alt_function, alt_args, **kwargs)
|
4414
4590
|
return output
|
4415
4591
|
|
4416
4592
|
def fmean(array, function='None', inverse_function='None',
|
@@ -4524,12 +4700,12 @@ def errorbar(x, y, lims_factor=None, **kwargs):
|
|
4524
4700
|
xa, ya = rich_array(x), rich_array(y)
|
4525
4701
|
xc = rich_array([x]) if len(xa.shape) == 0 else xa
|
4526
4702
|
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):
|
4703
|
+
if type(lims_factor) in (float, int):
|
4530
4704
|
lims_factor_x, lims_factor_y = [lims_factor]*2
|
4531
4705
|
elif type(lims_factor) in (list, tuple):
|
4532
4706
|
lims_factor_x, lims_factor_y = lims_factor
|
4707
|
+
else:
|
4708
|
+
lims_factor_x, lims_factor_y = None, None
|
4533
4709
|
if lims_factor_x is None:
|
4534
4710
|
lims_factor_x = lim_factor(xc)
|
4535
4711
|
if lims_factor_y is None:
|
@@ -4884,6 +5060,10 @@ def _log10(x):
|
|
4884
5060
|
y = np.log10(x)
|
4885
5061
|
return y
|
4886
5062
|
|
5063
|
+
# Abbreviations from NumPy.
|
5064
|
+
inf = np.inf
|
5065
|
+
nan = np.nan
|
5066
|
+
|
4887
5067
|
# Functions for masking arrays.
|
4888
5068
|
def isnan(x):
|
4889
5069
|
x = rich_array(x) if type(x) is not RichArray else x
|
@@ -4979,8 +5159,9 @@ rich_df = rdataframe = rich_dataframe
|
|
4979
5159
|
function = function_with_rich_values
|
4980
5160
|
array_function = function_with_rich_arrays
|
4981
5161
|
distribution = distr_with_rich_values
|
5162
|
+
array_distribution = distr_with_rich_arrays
|
4982
5163
|
evaluate_distribution = evaluate_distr
|
4983
5164
|
center_and_uncertainties = center_and_uncs
|
4984
5165
|
is_not_a_number = is_nan = isnan
|
4985
5166
|
is_infinite = is_inf = isinf
|
4986
|
-
is_finite = is_finite = isfinite
|
5167
|
+
is_finite = is_finite = isfinite
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: richvalues
|
3
|
-
Version: 4.
|
3
|
+
Version: 4.1.1
|
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.
|
8
|
+
version = '4.1.1',
|
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
|