richvalues 4.0.5__tar.gz → 4.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: richvalues
3
- Version: 4.0.5
3
+ Version: 4.1.0
4
4
  Summary: Python library for working with uncertainties and upper/lower limits
5
5
  Home-page: https://github.com/andresmegias/richvalues/
6
6
  Author: Andrés Megías Toledano
@@ -15,7 +15,7 @@ License-File: LICENSE
15
15
 
16
16
  RichValues is a Python 3 library for working with numeric values with uncertainties, upper/lower limits and finite intervals, which may be called _rich values_.
17
17
 
18
- With it, one can import rich values written in plain text documents in an easily readable format, operate with them propagating the uncertainties automatically, and export them in the same formatting style as the import. It also allows to easily plot rich values and to make fits to any function, taking into account the uncertainties and the upper/limits or finite intervals. Moreover, correlations between variables are taken into account when performing calculations with rich values.
18
+ With it, one can import rich values written in plain text documents in an easily readable format, operate with them propagating the uncertainties automatically, and export them in the same formatting style as the import. It also allows to easily plot rich values and to make fits to any function, taking into account the uncertainties and the upper/lower limits or finite intervals. Moreover, correlations between variables are taken into account when performing calculations with rich values.
19
19
 
20
20
  The libraries NumPy, Pandas, SciPy and Matplotlib are required by RichValues. A user guide and a quick tutorial are available on GitHub: https://github.com/andresmegias/richvalues/.
21
21
 
@@ -1,5 +1,5 @@
1
1
  RichValues is a Python 3 library for working with numeric values with uncertainties, upper/lower limits and finite intervals, which may be called _rich values_.
2
2
 
3
- With it, one can import rich values written in plain text documents in an easily readable format, operate with them propagating the uncertainties automatically, and export them in the same formatting style as the import. It also allows to easily plot rich values and to make fits to any function, taking into account the uncertainties and the upper/limits or finite intervals. Moreover, correlations between variables are taken into account when performing calculations with rich values.
3
+ With it, one can import rich values written in plain text documents in an easily readable format, operate with them propagating the uncertainties automatically, and export them in the same formatting style as the import. It also allows to easily plot rich values and to make fits to any function, taking into account the uncertainties and the upper/lower limits or finite intervals. Moreover, correlations between variables are taken into account when performing calculations with rich values.
4
4
 
5
5
  The libraries NumPy, Pandas, SciPy and Matplotlib are required by RichValues. A user guide and a quick tutorial are available on GitHub: https://github.com/andresmegias/richvalues/.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "richvalues"
7
- version = "4.0.5"
7
+ version = "4.1.0"
8
8
  description = "Python library for working with uncertainties and upper/lower limits"
9
9
  license = {file="LICENSE"}
10
10
  authors = [{name="Andrés Megías Toledano"}]
@@ -4,7 +4,7 @@
4
4
  """
5
5
  Rich Values Library
6
6
  -------------------
7
- Version 4.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.0'
41
41
  __author__ = 'Andrés Megías Toledano'
42
42
 
43
43
  import copy
@@ -57,6 +57,7 @@ defaultparams = {
57
57
  'size of samples': int(8e3),
58
58
  'number of significant figures': 1,
59
59
  'minimum exponent for scientific notation': 4,
60
+ 'maximum number of decimals': 5,
60
61
  'limit for extra significant figure': 2.5,
61
62
  'use extra significant figure for exact values': True,
62
63
  'use extra significant figure for finite intervals': True,
@@ -174,7 +175,7 @@ def round_sf(x, n=None, min_exp=None, extra_sf_lim=None):
174
175
  y = y.replace('e+','e').replace('e00','e0')
175
176
  return y
176
177
 
177
- def round_sf_unc(x, dx, n=None, min_exp=None, extra_sf_lim=None):
178
+ def round_sf_unc(x, dx, n=None, min_exp=None, max_dec=None, extra_sf_lim=None):
178
179
  """
179
180
  Round a value and its uncertainty depending on their significant figures.
180
181
 
@@ -189,6 +190,9 @@ def round_sf_unc(x, dx, n=None, min_exp=None, extra_sf_lim=None):
189
190
  min_exp : int, optional
190
191
  Minimum decimal exponent, in absolute value, to display the values in
191
192
  scientific notation. The default is 4.
193
+ max_dec : int, optional
194
+ Maximum number of decimals, to use the notation with parenthesis.
195
+ The default is 5.
192
196
  extra_sf_lim : float, optional
193
197
  If the number expressed in scientific notation has a base that is lower
194
198
  than this value, an additional significant figure will be used.
@@ -202,10 +206,9 @@ def round_sf_unc(x, dx, n=None, min_exp=None, extra_sf_lim=None):
202
206
  Rounded uncertainty.
203
207
  """
204
208
  n = set_default_value(n, 'number of significant figures')
205
- min_exp = set_default_value(min_exp,
206
- '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,20 @@ 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
+ if dy1 == dy2:
807
+ text = '{}{} e{}'.format(y, dy1, a)
808
+ else:
809
+ text = '{}{}{} e{}'.format(y, dy1, dy2, a)
769
810
  if not use_exp:
770
811
  text = text.replace(' e0','')
771
812
  else:
@@ -848,6 +889,7 @@ class RichValue():
848
889
  is_range = self.is_range
849
890
  is_int = self.is_int
850
891
  min_exp = abs(self.min_exp)
892
+ max_dec = abs(self.max_dec)
851
893
  extra_sf_lim = self.extra_sf_lim
852
894
  show_domain = defaultparams['show domain']
853
895
  use_exp = True
@@ -871,7 +913,7 @@ class RichValue():
871
913
  else False)
872
914
  if is_numeric:
873
915
  if not is_range:
874
- _, unc_r = round_sf_uncs(x, dx, n, min_exp, extra_sf_lim)
916
+ _, unc_r = round_sf_uncs(x, dx, n, min_exp, np.inf, extra_sf_lim)
875
917
  unc_r = np.array(unc_r, float)
876
918
  if not is_range and not use_exp:
877
919
  if not self.is_lim:
@@ -883,11 +925,11 @@ class RichValue():
883
925
  round_sf(x, n, np.inf, extra_sf_lim))
884
926
  text = '${}$'.format(y)
885
927
  else:
886
- y, dy = round_sf_unc(x, dx[0], n,
887
- min_exp, extra_sf_lim)
928
+ y, dy = round_sf_unc(x, dx[0], n, min_exp,
929
+ max_dec, extra_sf_lim)
888
930
  text = '${} \pm {}$'.format(y, dy)
889
931
  else:
890
- y, dy = round_sf_uncs(x, dx, n, min_exp, extra_sf_lim)
932
+ y, dy = round_sf_uncs(x, dx, n, min_exp, max_dec, extra_sf_lim)
891
933
  text = '$'+y + '_{-'+dy[0]+'}^{+'+dy[1]+'}$'
892
934
  else:
893
935
  if is_lolim:
@@ -915,8 +957,8 @@ class RichValue():
915
957
  text = ('${} {}'.format(y, mult_symbol)
916
958
  + ' 10^{'+a+'}$')
917
959
  else:
918
- y, dy = round_sf_unc(x, dx[0], n,
919
- min_exp, extra_sf_lim)
960
+ y, dy = round_sf_unc(x, dx[0], n, min_exp,
961
+ max_dec, extra_sf_lim)
920
962
  if 'e' in y:
921
963
  y, a = y.split('e')
922
964
  dy, a = dy.split('e')
@@ -926,8 +968,8 @@ class RichValue():
926
968
  text = ('$({} \pm {}) '.format(y, dy)
927
969
  + mult_symbol + ' 10^{'+a+'}$')
928
970
  else:
929
- y, dy = round_sf_uncs(x, [dx[0], dx[1]], n,
930
- min_exp, extra_sf_lim)
971
+ y, dy = round_sf_uncs(x, [dx[0], dx[1]], n, min_exp,
972
+ max_dec, extra_sf_lim)
931
973
  if 'e' in y:
932
974
  y, a = y.split('e')
933
975
  dy1, a = dy[0].split('e')
@@ -945,13 +987,13 @@ class RichValue():
945
987
  elif is_uplim:
946
988
  symbol = '<'
947
989
  y = int(np.ceil(x)) if is_int else x
948
- min_exp = 0
949
990
  y = round_sf(y, n, min_exp, extra_sf_lim)
950
- y, a = y.split('e')
951
- a = str(int(a))
991
+ if 'e' in y:
992
+ y, a = y.split('e')
993
+ else:
994
+ a = '0'
952
995
  text = ('${} {} {}'.format(symbol, y, mult_symbol)
953
996
  + ' 10^{'+a+'}$')
954
- text = text.replace('e-0', 'e-').replace('e+','e')
955
997
  a = int(text.split('10^{')[1].split('}')[0])
956
998
  if abs(a) < min_exp:
957
999
  y = RichValue(x, dx, is_lolim, is_uplim,
@@ -962,7 +1004,8 @@ class RichValue():
962
1004
  text = y.latex(*kwargs)
963
1005
  if (not use_extra_sf_in_exacts and omit_ones_in_sci_notation
964
1006
  and dx[0] == dx[1] and dx[0] == 0 or np.isnan(dx[0])):
965
- text = text.replace('1 {} '.format(mult_symbol), '')
1007
+ if '.' not in text:
1008
+ text = text.replace('1 {} '.format(mult_symbol), '')
966
1009
  else:
967
1010
  x1 = RichValue(main - unc[0], domain=domain)
968
1011
  x2 = RichValue(main + unc[1], domain=domain)
@@ -1452,6 +1495,11 @@ class RichValue():
1452
1495
  @minimum_exponent_for_scientific_notation.setter
1453
1496
  def minimum_exponent_for_scientific_notation(self, x): self.min_exp = x
1454
1497
 
1498
+ @property
1499
+ def maximum_number_of_decimals(self): return self.max_dec
1500
+ @maximum_number_of_decimals.setter
1501
+ def maximum_number_of_decimals(self, x): self.max_dec = x
1502
+
1455
1503
  @property
1456
1504
  def limit_for_extra_significant_figure(self): return self.extra_sf_lim
1457
1505
  @limit_for_extra_significant_figure.setter
@@ -1642,6 +1690,9 @@ class RichArray(np.ndarray):
1642
1690
  def min_exps(self):
1643
1691
  return np.array([x.min_exp for x in self.flat]).reshape(self.shape)
1644
1692
  @property
1693
+ def max_decs(self):
1694
+ return np.array([x.max_dec for x in self.flat]).reshape(self.shape)
1695
+ @property
1645
1696
  def extra_sf_lims(self):
1646
1697
  return np.array([x.extra_sf_lim for x in self.flat]).reshape(self.shape)
1647
1698
  @property
@@ -1660,6 +1711,12 @@ class RichArray(np.ndarray):
1660
1711
  def are_consts(self):
1661
1712
  return np.array([x.is_const for x in self.flat]).reshape(self.shape)
1662
1713
  @property
1714
+ def are_nans(self):
1715
+ return np.array([x.is_nan for x in self.flat]).reshape(self.shape)
1716
+ @property
1717
+ def are_infs(self):
1718
+ return np.array([x.is_inf for x in self.flat]).reshape(self.shape)
1719
+ @property
1663
1720
  def centers(self):
1664
1721
  return np.array([x.center for x in self.flat]).reshape(self.shape)
1665
1722
  @property
@@ -1738,6 +1795,7 @@ class RichArray(np.ndarray):
1738
1795
  abbreviations = {'is integer': 'is_int',
1739
1796
  'number of significant figures': 'num_sf',
1740
1797
  'minimum exponent for scientific notation': 'min_exp',
1798
+ 'maximum number of decimals': 'max_dec',
1741
1799
  'limit for extra significant figure': 'extra_sf_lim'}
1742
1800
  attributes = ['domain'] + list(abbreviations.values())
1743
1801
  for entry in abbreviations:
@@ -1757,6 +1815,8 @@ class RichArray(np.ndarray):
1757
1815
  x.num_sf = params['num_sf']
1758
1816
  if 'min_exp' in params:
1759
1817
  x.min_exp = params['min_exp']
1818
+ if 'max_dec' in params:
1819
+ x.max_dec = params['max_dec']
1760
1820
  if 'extra_sf_lim' in params:
1761
1821
  x.extra_sf_lim = params['extra_sf_lim']
1762
1822
 
@@ -1799,8 +1859,7 @@ class RichArray(np.ndarray):
1799
1859
  return np.array(self).mean()
1800
1860
 
1801
1861
  def std(self):
1802
- std_function = lambda u: (np.sum((u - u.mean())**2)
1803
- / len(self - 1))**0.5
1862
+ std_function = lambda u: (np.sum((u-u.mean())**2)/(len(self)-1))**0.5
1804
1863
  return self.function(std_function)
1805
1864
 
1806
1865
  # Attribute acronyms.
@@ -1812,11 +1871,14 @@ class RichArray(np.ndarray):
1812
1871
  are_integers = are_ints
1813
1872
  numbers_of_significant_figures = nums_sf
1814
1873
  minimum_exponents_for_scientific_notation = min_exps
1874
+ maximum_number_of_decimals = max_decs
1815
1875
  limits_for_extra_significant_figure = extra_sf_lims
1816
1876
  are_limits = are_lims
1817
1877
  are_intervals = are_intervs
1818
1878
  are_centereds = are_centrs
1819
1879
  are_constants = are_consts
1880
+ are_not_a_number = are_nans
1881
+ are_infinites = are_infs
1820
1882
  relative_uncertainties = rel_uncs
1821
1883
  signals_to_noises = signals_noises
1822
1884
  amplitudes = ampls
@@ -1905,6 +1967,8 @@ class RichDataFrame(pd.DataFrame):
1905
1967
  @property
1906
1968
  def min_exps(self): return self._property('min_exps')
1907
1969
  @property
1970
+ def max_decs(self): return self._property('max_decs')
1971
+ @property
1908
1972
  def extra_sf_lims(self): return self._property('extra_sf_lims')
1909
1973
  @property
1910
1974
  def are_lims(self): return self._property('are_lims')
@@ -1917,6 +1981,10 @@ class RichDataFrame(pd.DataFrame):
1917
1981
  @property
1918
1982
  def are_consts(self): return self._property('are_consts')
1919
1983
  @property
1984
+ def are_nans(self): return self._property('are_nans')
1985
+ @property
1986
+ def are_infs(self): return self._property('are_infs')
1987
+ @property
1920
1988
  def centers(self): return self._property('centers')
1921
1989
  @property
1922
1990
  def rel_uncs(self): return self._property2('rel_uncs')
@@ -1964,6 +2032,7 @@ class RichDataFrame(pd.DataFrame):
1964
2032
  abbreviations = {'is integer': 'is_int',
1965
2033
  'number of significant figures': 'num_sf',
1966
2034
  'minimum exponent for scientific notation': 'min_exp',
2035
+ 'maximum number of decimals': 'max_dec',
1967
2036
  'limit for extra significant figure': 'extra_sf_lim'}
1968
2037
  attributes = ['domain'] + list(abbreviations.values())
1969
2038
  for entry in abbreviations:
@@ -1984,6 +2053,7 @@ class RichDataFrame(pd.DataFrame):
1984
2053
  set_is_int = 'is_int' in params
1985
2054
  set_num_sf = 'num_sf' in params
1986
2055
  set_min_exp = 'min_exp' in params
2056
+ set_max_dec = 'max_dec' in params
1987
2057
  set_extra_sf_lim = 'extra_sf_lim' in params
1988
2058
  row_inds = self.index
1989
2059
  for col in self:
@@ -2002,6 +2072,9 @@ class RichDataFrame(pd.DataFrame):
2002
2072
  if set_min_exp and col in params['min_exp']:
2003
2073
  for i in row_inds:
2004
2074
  self[col][i].min_exp = params['min_exp'][col]
2075
+ if set_max_dec and col in params['max_dec']:
2076
+ for i in row_inds:
2077
+ self[col][i].max_dec = params['max_dec'][col]
2005
2078
  if set_extra_sf_lim and col in params['extra_sf_lim']:
2006
2079
  for i in row_inds:
2007
2080
  self[col][i].extra_sf_lim = params['extra_sf_lim'][col]
@@ -2060,7 +2133,8 @@ class RichDataFrame(pd.DataFrame):
2060
2133
  new_row = pd.DataFrame(new_row, idex=[0])
2061
2134
  return new_row
2062
2135
 
2063
- def latex(self, return_df=False, row_sep='\\tabularnewline', **kwargs):
2136
+ def latex(self, return_df=False, export_frame=True, export_index=True,
2137
+ row_sep='\\tabularnewline', **kwargs):
2064
2138
  """Return the content of the dataframe as a table in LaTeX format."""
2065
2139
  row_sep = ' ' + row_sep + ' \n'
2066
2140
  df = copy.copy(self)
@@ -2075,17 +2149,35 @@ class RichDataFrame(pd.DataFrame):
2075
2149
  if return_df:
2076
2150
  output = df
2077
2151
  else:
2152
+ columns = list(df.columns)
2153
+ num_columns = len(columns)
2078
2154
  text = ''
2155
+ if export_frame:
2156
+ text += '\\renewcommand*{\\arraystretch}{1.4}' + ' \n'
2157
+ text += ('\\begin{tabular}{' + 'l'*export_index
2158
+ + num_columns*'c' + '}' + ' \n')
2159
+ text += '\\hline \n'
2160
+ columns = ['{\\bf ' + column + '}' for column in columns]
2161
+ index_name = df.index.name if df.index.name is not None else ' '
2162
+ if export_index:
2163
+ columns = ['{\\bf ' + index_name + '}'] + columns
2164
+ if export_frame:
2165
+ text += ' & '.join(columns) + row_sep + '\\hline \n'
2079
2166
  rows = []
2080
- for (i,row) in df.iterrows():
2081
- cols = []
2167
+ for (ind,row) in df.iterrows():
2168
+ cols = [str(ind)] if export_index else []
2082
2169
  for (j,column) in enumerate(df):
2083
2170
  entry = str(row[column])
2084
2171
  if entry == 'nan':
2085
2172
  entry = '...'
2086
2173
  cols += [entry]
2087
2174
  rows += [' & '.join(cols)]
2088
- text = row_sep.join(rows)
2175
+ text += row_sep.join(rows)
2176
+ if export_frame:
2177
+ text += row_sep
2178
+ text += '\\hline \n'
2179
+ text += '\\end{tabular}' + ' \n'
2180
+ text += '\\renewcommand*{\\arraystretch}{1.0}' + ' \n'
2089
2181
  output = text
2090
2182
  return output
2091
2183
 
@@ -2118,6 +2210,8 @@ class RichDataFrame(pd.DataFrame):
2118
2210
  are_intervals = are_intervs
2119
2211
  are_centereds = are_centrs
2120
2212
  are_constants = are_consts
2213
+ are_not_a_number = are_nans
2214
+ are_infinites = are_infs
2121
2215
  relative_uncertainties = rel_uncs
2122
2216
  signals_to_noises = signals_noises
2123
2217
  amplitudes = ampls
@@ -2171,6 +2265,9 @@ class RichSeries(pd.Series):
2171
2265
  def min_exps(self):
2172
2266
  return pd.Series(self.values.view(RichArray).min_exps, self.index)
2173
2267
  @property
2268
+ def max_decs(self):
2269
+ return pd.Series(self.values.view(RichArray).max_decs, self.index)
2270
+ @property
2174
2271
  def extra_sf_lims(self):
2175
2272
  return pd.Series(self.values.view(RichArray).extra_sf_lim, self.index)
2176
2273
  @property
@@ -2189,6 +2286,12 @@ class RichSeries(pd.Series):
2189
2286
  def are_consts(self):
2190
2287
  return pd.Series(self.values.view(RichArray).are_consts, self.index)
2191
2288
  @property
2289
+ def are_nans(self):
2290
+ return pd.Series(self.values.view(RichArray).are_nans, self.index)
2291
+ @property
2292
+ def are_infs(self):
2293
+ return pd.Series(self.values.view(RichArray).are_infs, self.index)
2294
+ @property
2192
2295
  def centers(self):
2193
2296
  return pd.Series(self.values.view(RichArray).centers, self.index)
2194
2297
  @property
@@ -2250,10 +2353,13 @@ class RichSeries(pd.Series):
2250
2353
  are_integers = are_ints
2251
2354
  numbers_of_scientific_figures = nums_sf
2252
2355
  minimum_exponents_for_scientific_notation = min_exps
2356
+ maximum_numbers_of_decimals = max_decs
2253
2357
  are_limits = are_lims
2254
2358
  are_intervals = are_intervs
2255
2359
  are_centereds = are_centrs
2256
2360
  are_constants = are_consts
2361
+ are_not_a_number = are_nans
2362
+ are_infinites = are_infs
2257
2363
  relative_uncertainties = rel_uncs
2258
2364
  signals_to_noises = signals_noises
2259
2365
  amplitudes = ampls
@@ -2305,11 +2411,14 @@ class ComplexRichValue():
2305
2411
 
2306
2412
  num_sf = min(real.num_sf, imag.num_sf)
2307
2413
  min_exp = round(np.mean([real.min_exp, imag.min_exp]))
2414
+ max_dec = min(real.max_dec, imag.max_dec)
2308
2415
  extra_sf_lim = min(real.extra_sf_lim, imag.extra_sf_lim)
2309
2416
  real.num_sf = num_sf
2310
2417
  imag.num_sf = num_sf
2311
2418
  real.min_exp = min_exp
2312
2419
  imag.min_exp = min_exp
2420
+ real.max_dec = max_dec
2421
+ real.max_dec = max_dec
2313
2422
  real.extra_sf_lim = extra_sf_lim
2314
2423
  imag.extra_sf_lim = extra_sf_lim
2315
2424
 
@@ -2352,16 +2461,21 @@ class ComplexRichValue():
2352
2461
  self.imag.num_sf = x
2353
2462
 
2354
2463
  @property
2355
- def min_exp(self): return round(np.mean([self.real.min_exp,
2356
- self.imag.min_exp]))
2464
+ def min_exp(self): return round(np.mean([self.real.min_exp, self.imag.min_exp]))
2357
2465
  @min_exp.setter
2358
2466
  def min_exp(self, x):
2359
2467
  self.real.min_exp = x
2360
2468
  self.imag.min_exp = x
2469
+
2470
+ @property
2471
+ def max_dec(self): return min(self.real.max_dec, self.imag.max_dec)
2472
+ @max_dec.setter
2473
+ def max_dec(self, x):
2474
+ self.real.max_dec = x
2475
+ self.imag.max_dec = x
2361
2476
 
2362
2477
  @property
2363
- def extra_sf_lim(self): return max(self.real.extra_sf_lim,
2364
- self.imag.extra_sf_lim)
2478
+ def extra_sf_lim(self): return max(self.real.extra_sf_lim, self.imag.extra_sf_lim)
2365
2479
  @extra_sf_lim.setter
2366
2480
  def extra_sf_lim(self, x):
2367
2481
  self.real.extra_sf_lim = x
@@ -2663,7 +2777,7 @@ def add_rich_values(x, y):
2663
2777
  is_int = x.is_int and y.is_int
2664
2778
  domain = [x.domain[0] + y.domain[0], x.domain[1] + y.domain[1]]
2665
2779
  sigmas = defaultparams['sigmas to use approximate uncertainty propagation']
2666
- if x.is_exact or y.is_exact:
2780
+ if (x.is_exact or y.is_exact) and (x.is_interv or y.is_interv):
2667
2781
  z = list(np.array(x.interval()) + np.array(y.interval()))
2668
2782
  z = RichValue(z, domain=domain, is_int=is_int)
2669
2783
  elif (not (x.is_interv or y.is_interv)
@@ -2687,7 +2801,7 @@ def multiply_rich_values(x, y):
2687
2801
  is_int = x.is_int and y.is_int
2688
2802
  domain = propagate_domain(x.domain, y.domain, lambda a,b: a*b)
2689
2803
  sigmas = defaultparams['sigmas to use approximate uncertainty propagation']
2690
- if x.is_exact or y.is_exact:
2804
+ if (x.is_exact or y.is_exact) and (x.is_interv or y.is_interv):
2691
2805
  z = list(np.array(x.interval()) * np.array(y.interval()))
2692
2806
  z = RichValue(z, domain=domain, is_int=is_int)
2693
2807
  elif (not (x.is_interv or y.is_interv)
@@ -2933,7 +3047,7 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
2933
3047
  def parse_as_rich_value(text):
2934
3048
  """Obtain the properties of the input text as a rich value."""
2935
3049
  def parse_value(text):
2936
- """Parse input text as a value."""
3050
+ """Parse input text as a numeric value."""
2937
3051
  text = str(text)
2938
3052
  if any([char.isalpha() for char in text.replace(' e','')]):
2939
3053
  for short_name in abbreviations:
@@ -2992,8 +3106,24 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
2992
3106
  is_uplim, is_lolim = False, False
2993
3107
  text = (text.replace('+-', '+/-').replace(' -', '-')
2994
3108
  .replace(' +/-', '+/-').replace('+/- ', '+/-'))
2995
- if '+/-' in text:
2996
- x_dx, e = text.split(' ')
3109
+ x_dx, e = text.split(' ')
3110
+ if ')' in text:
3111
+ if text.count(')') == 1:
3112
+ x, dx = x_dx.split('(')
3113
+ dx = dx[:-1]
3114
+ dx1, dx2 = dx
3115
+ else:
3116
+ x, dx1, dx2 = x_dx.split('(')
3117
+ dx1 = dx1[:-1]
3118
+ dx2 = dx2[:-1]
3119
+ if dx1.startswith('+'):
3120
+ dx1, dx2 = dx2, dx1
3121
+ dx1 = dx1[1:]
3122
+ dx2 = dx2[1:]
3123
+ d = len(x.split('.')[1]) if '.' in x else 0
3124
+ dx1 = '{:f}'.format(float(dx1)*10**(-d))
3125
+ dx2 = '{:f}'.format(float(dx2)*10**(-d))
3126
+ elif '+/-' in text:
2997
3127
  x, dx = x_dx.split('+/-')
2998
3128
  text = '{}-{}+{} {}'.format(x, dx, dx, e)
2999
3129
  dx1, dx2 = dx, dx
@@ -3014,10 +3144,9 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
3014
3144
  else:
3015
3145
  x = text.split(' ')[0]
3016
3146
  dx1, dx2 = '0', '0'
3017
- e = text.split(' ')[1]
3018
- x = '{} {}'.format(x ,e)
3019
- dx1 = '{} {}'.format(dx1 ,e)
3020
- dx2 = '{} {}'.format(dx2 ,e)
3147
+ x = '{} {}'.format(x, e)
3148
+ dx1 = '{} {}'.format(dx1, e)
3149
+ dx2 = '{} {}'.format(dx2, e)
3021
3150
  x = parse_value(x)
3022
3151
  dx1 = parse_value(dx1)
3023
3152
  dx2 = parse_value(dx2)
@@ -3070,7 +3199,7 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
3070
3199
  unc = 0
3071
3200
  is_lolim, is_uplim, is_range = False, False, True
3072
3201
  min_exp = round(np.mean([me1, me2]))
3073
- extra_sf_lim = min(el1, el2)
3202
+ extra_sf_lim = max(el1, el2)
3074
3203
  return (main, unc, is_lolim, is_uplim, is_range, domain,
3075
3204
  min_exp, extra_sf_lim)
3076
3205
 
@@ -3203,7 +3332,7 @@ def rich_array(array, domain=None, is_int=None,
3203
3332
  rarray = RichArray(mains, uncs, are_lolims, are_uplims, are_ranges,
3204
3333
  domains, are_ints, variables, expressions)
3205
3334
  min_exp = round(np.mean(min_exps))
3206
- extra_sf_lim = min(extra_sf_lims)
3335
+ extra_sf_lim = max(extra_sf_lims)
3207
3336
  rarray.set_params({'min_exp': min_exp, 'extra_sf_lim': extra_sf_lim})
3208
3337
  return rarray
3209
3338
 
@@ -3272,8 +3401,10 @@ def rich_dataframe(df, domains=None, are_ints=None,
3272
3401
  domain = defaultparams['domain']
3273
3402
  if is_int is None:
3274
3403
  is_int = defaultparams['assume integers']
3275
- entry = rich_value(text, domain, is_int,
3276
- use_default_extra_sf_lim)
3404
+ try:
3405
+ entry = rich_value(text, domain, is_int, use_default_extra_sf_lim)
3406
+ except:
3407
+ entry = text
3277
3408
  if is_rich_value or is_number:
3278
3409
  df.at[i,col] = entry
3279
3410
  rdf = RichDataFrame(df)
@@ -3582,7 +3713,7 @@ def loguniform_distribution(low=-1, high=1, size=1,
3582
3713
  return distr
3583
3714
 
3584
3715
  def distr_with_rich_values(function, args, len_samples=None,
3585
- is_vectorizable=False):
3716
+ is_vectorizable=False, **kwargs):
3586
3717
  """
3587
3718
  Same as function_with_rich_values, but just returns the final distribution.
3588
3719
  """
@@ -3688,7 +3819,7 @@ def remove_zero_infs(interval, zero_log, inf_log):
3688
3819
  return new_interval
3689
3820
 
3690
3821
  def evaluate_distr(distr, domain=None, function=None, args=None,
3691
- len_samples=None, is_vectorizable=False, consider_intervs=True,
3822
+ len_samples=None, is_vectorizable=False, consider_intervs=None,
3692
3823
  is_domain_cyclic=False, lims_fraction=None, num_reps_lims=None,
3693
3824
  save_pdf=None, **kwargs):
3694
3825
  """
@@ -3774,10 +3905,17 @@ def evaluate_distr(distr, domain=None, function=None, args=None,
3774
3905
  return tuple(all_vars)
3775
3906
 
3776
3907
  if args is not None:
3908
+ if type(args) is np.ndarray:
3909
+ args = [rich_value(arg) for arg in args]
3777
3910
  if type(args) not in (tuple, list):
3778
3911
  args = [args]
3779
- args = [rich_value(arg) if type(arg) not in
3780
- (RichValue, ComplexRichValue) else arg for arg in args]
3912
+ if type(args[0]) is not RichArray:
3913
+ args = [rich_value(arg) if type(arg) not in
3914
+ (RichValue, ComplexRichValue) else arg for arg in args]
3915
+ if consider_intervs is None:
3916
+ consider_intervs = True
3917
+ if args is not None and all([arg.is_centr for arg in args]):
3918
+ consider_intervs = False
3781
3919
 
3782
3920
  distr = np.array(distr)
3783
3921
 
@@ -4076,6 +4214,7 @@ def function_with_rich_values(function, args, unc_function=None,
4076
4214
  args = [args]
4077
4215
  args = [rich_value(arg) if type(arg) not in (RichValue, ComplexRichValue)
4078
4216
  else arg for arg in args]
4217
+ args_copy = copy.copy(args)
4079
4218
 
4080
4219
  input_function = copy.copy(function)
4081
4220
  if type(function) is str:
@@ -4119,7 +4258,7 @@ def function_with_rich_values(function, args, unc_function=None,
4119
4258
 
4120
4259
  if len_samples is None:
4121
4260
  len_samples = int(len(args)**0.5 * defaultparams['size of samples'])
4122
- num_sf = min([arg.num_sf for arg in args])
4261
+ num_sf = int(np.median([arg.num_sf for arg in args]))
4123
4262
  min_exp = round(np.mean([arg.min_exp for arg in args]))
4124
4263
  extra_sf_lim = max([arg.extra_sf_lim for arg in args])
4125
4264
 
@@ -4136,9 +4275,6 @@ def function_with_rich_values(function, args, unc_function=None,
4136
4275
  use_analytic_propagation = False
4137
4276
 
4138
4277
  args_main = np.array([arg.main for arg in args])
4139
- # print()
4140
- # print(args)
4141
- # print(args[0].expression)
4142
4278
  with np.errstate(divide='ignore', invalid='ignore'):
4143
4279
  main = function(*args_main)
4144
4280
  output_size = np.array(main).size
@@ -4224,16 +4360,14 @@ def function_with_rich_values(function, args, unc_function=None,
4224
4360
 
4225
4361
  mains = [main] if output_size == 1 else main
4226
4362
  if unc_function is not None:
4227
- args_unc = [np.array(arg.unc) for arg in args]
4228
- uncs = unc_function(*args_main, *args_unc)
4363
+ uncs = []
4364
+ args_main = np.array([arg.main for arg in args_copy])
4365
+ for i in (0,1):
4366
+ args_unc = [arg.unc[i] for arg in args_copy]
4367
+ uncs += [unc_function(*args_main, *args_unc)]
4229
4368
  uncs = [uncs] if output_size == 1 else uncs
4230
- 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
4369
+ for k in range(output_size):
4370
+ uncs[k][1] = abs(uncs[k][1])
4237
4371
  else:
4238
4372
  inds_combs = list(itertools.product(*[[0,1,2]]*len(args)))
4239
4373
  comb_main = tuple([1]*len(args))
@@ -4261,6 +4395,9 @@ def function_with_rich_values(function, args, unc_function=None,
4261
4395
  real_k = RichValue(main_k.real, unc_k.real, domain=domain_k)
4262
4396
  imag_k = RichValue(main_k.imag, unc_k.imag, domain=domain_k)
4263
4397
  rval_k = ComplexRichValue(real_k, imag_k)
4398
+ rval_k.num_sf = num_sf
4399
+ rval_k.min_exp = min_exp
4400
+ rval_k.extra_sf_lim = extra_sf_lim
4264
4401
  output += [rval_k]
4265
4402
 
4266
4403
  else:
@@ -4336,6 +4473,43 @@ def function_with_rich_arrays(function, args, elementwise=False, **kwargs):
4336
4473
  output : rich array / rich value
4337
4474
  Result of the function.
4338
4475
  """
4476
+ if 'domain' in kwargs:
4477
+ domain = kwargs['domain']
4478
+ del kwargs['domain']
4479
+ else:
4480
+ domain = None
4481
+ distr = distr_with_rich_arrays(function, args, elementwise, **kwargs)
4482
+ if len(distr.shape) == 1:
4483
+ output = evaluate_distr(distr, domain, function, args, **kwargs)
4484
+ else:
4485
+ output_size = distr.shape[1]
4486
+ output = []
4487
+ for k in range(output_size):
4488
+ function_k = lambda *args: function(args)[k]
4489
+ rval_k = evaluate_distr(distr[:,k], domain, function_k, **kwargs)
4490
+ output += [rval_k]
4491
+ if type(args) not in (tuple, list):
4492
+ args = [args]
4493
+ for (i,arg) in enumerate(args):
4494
+ if type(arg) is not RichArray:
4495
+ args[i] = RichArray(arg)
4496
+ args_mains = [arg.mains for arg in args]
4497
+ if type(function) is not str:
4498
+ with np.errstate(divide='ignore', invalid='ignore'):
4499
+ main = function(*args_mains)
4500
+ else:
4501
+ main = distr[0,:]
4502
+ output_type = RichArray if type(main) is np.ndarray else type(main)
4503
+ if output_type is tuple and output_size > 1:
4504
+ output = tuple(output)
4505
+ elif output_type is RichArray:
4506
+ output = np.array(output).view(RichArray)
4507
+ return output
4508
+
4509
+ def distr_with_rich_arrays(function, args, elementwise=False, **kwargs):
4510
+ """
4511
+ Same as function_with_rich_arrays, but just returns the final distribution.
4512
+ """
4339
4513
  if type(args) not in (tuple, list):
4340
4514
  args = [args]
4341
4515
  args = [rich_array(arg) if type(arg) != RichArray else arg
@@ -4351,6 +4525,8 @@ def function_with_rich_arrays(function, args, elementwise=False, **kwargs):
4351
4525
  if 'len_samples' not in kwargs:
4352
4526
  kwargs['len_samples'] = int(len(args)**0.5
4353
4527
  * defaultparams['size of samples'])
4528
+ if 'consider_intervs' in kwargs:
4529
+ del kwargs['consider_intervs']
4354
4530
  if elementwise:
4355
4531
  same_shapes = True
4356
4532
  for arg in args[1:]:
@@ -4359,16 +4535,14 @@ def function_with_rich_arrays(function, args, elementwise=False, **kwargs):
4359
4535
  break
4360
4536
  if not same_shapes:
4361
4537
  raise Exception('Input arrays have different shapes.')
4362
- array = np.empty(0, RichValue)
4538
+ distr = []
4363
4539
  args_flat = np.array([arg.flatten() for arg in args])
4364
4540
  for i in range(args[0].size):
4365
4541
  args_i = np.array(args_flat)[:,i].tolist()
4366
- 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
4542
+ distr_i = distr_with_rich_values(function, args_i, **kwargs)
4543
+ distr += [distr_i]
4544
+ distr = np.array(distr).T
4545
+ output = distr
4372
4546
  else:
4373
4547
  if type(function) is str:
4374
4548
  variables = list(np.concatenate(tuple(arg.variables for arg in args)))
@@ -4410,7 +4584,7 @@ def function_with_rich_arrays(function, args, elementwise=False, **kwargs):
4410
4584
  alt_args = []
4411
4585
  for arg in args:
4412
4586
  alt_args += list(arg.flat)
4413
- output = function_with_rich_values(alt_function, alt_args, **kwargs)
4587
+ output = distr_with_rich_values(alt_function, alt_args, **kwargs)
4414
4588
  return output
4415
4589
 
4416
4590
  def fmean(array, function='None', inverse_function='None',
@@ -4524,12 +4698,12 @@ def errorbar(x, y, lims_factor=None, **kwargs):
4524
4698
  xa, ya = rich_array(x), rich_array(y)
4525
4699
  xc = rich_array([x]) if len(xa.shape) == 0 else xa
4526
4700
  yc = rich_array([y]) if len(ya.shape) == 0 else ya
4527
- if lims_factor is None:
4528
- lims_factor_x, lims_factor_y = None, None
4529
- elif type(lims_factor) in (float, int):
4701
+ if type(lims_factor) in (float, int):
4530
4702
  lims_factor_x, lims_factor_y = [lims_factor]*2
4531
4703
  elif type(lims_factor) in (list, tuple):
4532
4704
  lims_factor_x, lims_factor_y = lims_factor
4705
+ else:
4706
+ lims_factor_x, lims_factor_y = None, None
4533
4707
  if lims_factor_x is None:
4534
4708
  lims_factor_x = lim_factor(xc)
4535
4709
  if lims_factor_y is None:
@@ -4884,6 +5058,10 @@ def _log10(x):
4884
5058
  y = np.log10(x)
4885
5059
  return y
4886
5060
 
5061
+ # Abbreviations from NumPy.
5062
+ inf = np.inf
5063
+ nan = np.nan
5064
+
4887
5065
  # Functions for masking arrays.
4888
5066
  def isnan(x):
4889
5067
  x = rich_array(x) if type(x) is not RichArray else x
@@ -4979,6 +5157,7 @@ rich_df = rdataframe = rich_dataframe
4979
5157
  function = function_with_rich_values
4980
5158
  array_function = function_with_rich_arrays
4981
5159
  distribution = distr_with_rich_values
5160
+ array_distribution = distr_with_rich_arrays
4982
5161
  evaluate_distribution = evaluate_distr
4983
5162
  center_and_uncertainties = center_and_uncs
4984
5163
  is_not_a_number = is_nan = isnan
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: richvalues
3
- Version: 4.0.5
3
+ Version: 4.1.0
4
4
  Summary: Python library for working with uncertainties and upper/lower limits
5
5
  Home-page: https://github.com/andresmegias/richvalues/
6
6
  Author: Andrés Megías Toledano
@@ -15,7 +15,7 @@ License-File: LICENSE
15
15
 
16
16
  RichValues is a Python 3 library for working with numeric values with uncertainties, upper/lower limits and finite intervals, which may be called _rich values_.
17
17
 
18
- With it, one can import rich values written in plain text documents in an easily readable format, operate with them propagating the uncertainties automatically, and export them in the same formatting style as the import. It also allows to easily plot rich values and to make fits to any function, taking into account the uncertainties and the upper/limits or finite intervals. Moreover, correlations between variables are taken into account when performing calculations with rich values.
18
+ With it, one can import rich values written in plain text documents in an easily readable format, operate with them propagating the uncertainties automatically, and export them in the same formatting style as the import. It also allows to easily plot rich values and to make fits to any function, taking into account the uncertainties and the upper/lower limits or finite intervals. Moreover, correlations between variables are taken into account when performing calculations with rich values.
19
19
 
20
20
  The libraries NumPy, Pandas, SciPy and Matplotlib are required by RichValues. A user guide and a quick tutorial are available on GitHub: https://github.com/andresmegias/richvalues/.
21
21
 
@@ -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.0',
9
9
  license = 'BSD-3-Clause',
10
10
  author = 'Andrés Megías Toledano',
11
11
  description = 'Python library for working with uncertainties and upper/lower limits',
File without changes
File without changes