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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: richvalues
3
- Version: 4.0.5
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.0.5"
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.0
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.5'
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
- 'minimum exponent for scientific notation')
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
- if float(dy[0]) <= extra_sf_lim:
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
- 'minimum exponent for scientific notation')
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
- b1 = float(str(dy1)[0]) if np.isfinite(dx1) else 10.
343
- b2 = float(str(dy2)[0]) if np.isfinite(dx2) else 10.
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
- min_exp, extra_sf_lim)
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 dy1 == dy2:
762
- if float(dy1) != 0:
763
- text = '{}+/-{} e{}'.format(y, dy1, a)
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
- y = int(round(float(y))) if is_int else y
766
- text = '{} e{}'.format(y, a)
804
+ text = '{}-{}+{} e{}'.format(y, dy1, dy2, a)
767
805
  else:
768
- text = '{}-{}+{} e{}'.format(y, dy1, dy2, a)
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
- min_exp, extra_sf_lim)
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
- min_exp, extra_sf_lim)
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
- min_exp, extra_sf_lim)
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
- y, a = y.split('e')
951
- a = str(int(a))
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
- text = text.replace('1 {} '.format(mult_symbol), '')
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 - u.mean())**2)
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, row_sep='\\tabularnewline', **kwargs):
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 (i,row) in df.iterrows():
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 = row_sep.join(rows)
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
- if '+/-' in text:
2996
- x_dx, e = text.split(' ')
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
- e = text.split(' ')[1]
3018
- x = '{} {}'.format(x ,e)
3019
- dx1 = '{} {}'.format(dx1 ,e)
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 = min(el1, el2)
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 = min(extra_sf_lims)
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
- entry = rich_value(text, domain, is_int,
3276
- use_default_extra_sf_lim)
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=True,
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
- args = [rich_value(arg) if type(arg) not in
3780
- (RichValue, ComplexRichValue) else arg for arg in args]
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 = min([arg.num_sf for arg in args])
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
- args_unc = [np.array(arg.unc) for arg in args]
4228
- uncs = unc_function(*args_main, *args_unc)
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
- if output_size > 1:
4231
- for k in range(output_size):
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
- array = np.empty(0, RichValue)
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
- rvalue = function_with_rich_values(function, args_i, **kwargs)
4367
- array = np.append(array, rvalue)
4368
- if shape == ():
4369
- array = np.array(array[0])
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 = function_with_rich_values(alt_function, alt_args, **kwargs)
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 is None:
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.0.5
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
 
@@ -3,7 +3,6 @@ README.md
3
3
  pyproject.toml
4
4
  setup.py
5
5
  richvalues/__init__.py
6
- richvalues.egg-info/.DS_Store
7
6
  richvalues.egg-info/PKG-INFO
8
7
  richvalues.egg-info/SOURCES.txt
9
8
  richvalues.egg-info/dependency_links.txt
@@ -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.5',
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',
File without changes
File without changes