LLNL-PyDV 3.8.0__tar.gz → 3.9.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.4
2
2
  Name: LLNL-PyDV
3
- Version: 3.8.0
3
+ Version: 3.9.0
4
4
  Summary: PyDV: Python Data Visualizer
5
5
  License: BSD
6
6
  License-File: LICENSE
@@ -510,6 +510,9 @@ class Command(cmd.Cmd, object):
510
510
  def do_rdsina(self, line):
511
511
  self.do_readsina(line)
512
512
 
513
+ def do_rdsinah5(self, line):
514
+ self.do_readsinahdf5(line)
515
+
513
516
  def do_cur(self, line):
514
517
  self.do_curve(line)
515
518
 
@@ -636,6 +639,8 @@ class Command(cmd.Cmd, object):
636
639
  arg = 'readcsv'
637
640
  elif (arg == 'rdsina'):
638
641
  arg = 'readsina'
642
+ elif (arg == 'rdsinah5'):
643
+ arg = 'readsinahdf5'
639
644
  elif (arg == 'convol'):
640
645
  arg = 'convolve'
641
646
  elif (arg == 'convolb'):
@@ -1110,6 +1115,9 @@ class Command(cmd.Cmd, object):
1110
1115
  elif line[-1].endswith(".json"):
1111
1116
  self.do_readsina(" ".join(line))
1112
1117
  return
1118
+ elif line[-1].endswith(".hdf5") or line[-1].endswith(".h5") or line[-1].endswith(".hdf"):
1119
+ self.do_readsinahdf5(" ".join(line))
1120
+ return
1113
1121
 
1114
1122
  if n == 1:
1115
1123
  self.load(line[0])
@@ -1174,10 +1182,8 @@ class Command(cmd.Cmd, object):
1174
1182
 
1175
1183
  def do_readsina(self, line):
1176
1184
  """
1177
- Read all curves from Sina data file. PyDV assumes there is only one record in the Sina file, and if there are
1178
- more than one then PyDV only reads the first. PyDV also assumes there is only one independent variable per
1179
- curve_set; if there are more than one then PyDV may exhibit undefined behavior. The next available prefix
1180
- (see the prefix command) is automatically assigned the menu index of the first curve in each data file read.
1185
+ Read all curves from Sina data file. The next available prefix (see the prefix command) is automatically
1186
+ assigned the menu index of the first curve in each data file read.
1181
1187
 
1182
1188
  .. code::
1183
1189
 
@@ -1196,6 +1202,28 @@ class Command(cmd.Cmd, object):
1196
1202
  self.redraw = False
1197
1203
  self.plotter.updateDialogs()
1198
1204
 
1205
+ def do_readsinahdf5(self, line):
1206
+ """
1207
+ Read all curves from Sina hdf5 data file. The next available prefix (see the prefix command) is automatically
1208
+ assigned the menu index of the first curve in each data file read.
1209
+
1210
+ .. code::
1211
+
1212
+ [PyDV]: <readsinahdf5 | rdsinah5> <filename.hdf5>
1213
+
1214
+ Ex:
1215
+ [PyDV]: readsinahdf5 my_file.hdf5
1216
+ """
1217
+
1218
+ try:
1219
+ line = line.split()
1220
+ self.load_sinahdf5(line[0])
1221
+ except:
1222
+ pdvutil.print_own_docstring(self)
1223
+ finally:
1224
+ self.redraw = False
1225
+ self.plotter.updateDialogs()
1226
+
1199
1227
  def do_setxcolumn(self, line):
1200
1228
  """
1201
1229
  Set x column for reading column formatted data files (.gnu or .csv).
@@ -1613,18 +1641,6 @@ class Command(cmd.Cmd, object):
1613
1641
  [PyDV]: stats a:b
1614
1642
  [PyDV]: stats c d
1615
1643
  """
1616
-
1617
- def find_mode(array):
1618
-
1619
- try:
1620
- mode = scipy.stats.mode(array, keepdims=True)
1621
- except:
1622
- mode = scipy.stats.mode(array)
1623
- if mode.count[0] == 1 and len(array) != 1:
1624
- return numpy.nan, numpy.nan
1625
- else:
1626
- return mode.mode[0], mode.count[0]
1627
-
1628
1644
  if not line:
1629
1645
  return 0
1630
1646
 
@@ -1638,25 +1654,7 @@ class Command(cmd.Cmd, object):
1638
1654
  try:
1639
1655
  curvidx = pdvutil.getCurveIndex(line[i], self.plotlist)
1640
1656
  cur = self.plotlist[curvidx]
1641
- numx, countx = find_mode(cur.x)
1642
- numy, county = find_mode(cur.y)
1643
-
1644
- print('\nCurve ' + cur.plotname)
1645
- print('\n\t X:\t Y:')
1646
- print(f'\n\tlength: {len(cur.x):<15.10g}\t{len(cur.y):<15.10g}')
1647
- print(f'\tmean: {numpy.mean(cur.x):<15.10g}\t{numpy.mean(cur.y):<15.10g}')
1648
- print(f'\tmedian: {numpy.median(cur.x):<15.10g}\t{numpy.median(cur.y):<15.10g}')
1649
- print(f'\tmode: {numx:<15.10g}\t{numy:<15.10g}')
1650
- print(f'\t count: {countx:<15.10g}\t{county:<15.10g}')
1651
- print(f'\tstd: {numpy.std(cur.x):<15.10g}\t{numpy.std(cur.y):<15.10g}')
1652
- print(f'\tskew: {scipy.stats.skew(cur.x):<15.10g}\t{scipy.stats.skew(cur.y):<15.10g}')
1653
- print(f'\tkurtosis: {scipy.stats.kurtosis(cur.x):<15.10g}\t{scipy.stats.kurtosis(cur.y):<15.10g}') # noqae501
1654
- print(f'\tmin: {numpy.min(cur.x):<15.10g}\t{numpy.min(cur.y):<15.10g}')
1655
- print(f'\t25%: {numpy.quantile(cur.x,.25):<15.10g}\t{numpy.quantile(cur.y,.25):<15.10g}')
1656
- print(f'\t50%: {numpy.quantile(cur.x,.50):<15.10g}\t{numpy.quantile(cur.y,.50):<15.10g}')
1657
- print(f'\t75%: {numpy.quantile(cur.x,.75):<15.10g}\t{numpy.quantile(cur.y,.75):<15.10g}')
1658
- print(f'\tmax: {numpy.max(cur.x):<15.10g}\t{numpy.max(cur.y):<15.10g}')
1659
- print(f'\tsum: {numpy.sum(cur.x):<15.10g}\t{numpy.sum(cur.y):<15.10g}')
1657
+ pydvpy.stats(cur)
1660
1658
 
1661
1659
  except pdvutil.CurveIndexError:
1662
1660
  pass
@@ -9470,6 +9468,16 @@ class Command(cmd.Cmd, object):
9470
9468
  self.curvelist += curves
9471
9469
  self.filelist.append((fname, len(curves)))
9472
9470
 
9471
+ def load_sinahdf5(self, fname):
9472
+ """
9473
+ Load a Sina HDF5 data file, add parsed curves to the curvelist
9474
+ """
9475
+
9476
+ curves = pydvpy.readsinahdf5(fname, self.debug)
9477
+ if len(curves) > 0:
9478
+ self.curvelist += curves
9479
+ self.filelist.append((fname, len(curves)))
9480
+
9473
9481
  def loadrc(self):
9474
9482
  """
9475
9483
  Read in a resource definition file
@@ -233,13 +233,13 @@ class Plotter(QMainWindow):
233
233
  # Create or clear table
234
234
  if self._tableWidget is None:
235
235
  self._tableWidget = QTableWidget(rows, cols, self)
236
- self._tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
236
+ self._tableWidget.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
237
237
  self._tableWidget.setHorizontalHeaderLabels(headerLabels)
238
238
  self._tableWidget.setAlternatingRowColors(True)
239
- self._tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
239
+ self._tableWidget.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
240
240
 
241
241
  # Setup Right-click menu
242
- self._tableWidget.setContextMenuPolicy(Qt.ActionsContextMenu)
242
+ self._tableWidget.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu)
243
243
  deleteCurveAction = QAction("Delete selected curve(s)", self._tableWidget)
244
244
  deleteCurveAction.triggered.connect(self.__deleteCurve)
245
245
  self._tableWidget.addAction(deleteCurveAction)
@@ -257,7 +257,7 @@ class Plotter(QMainWindow):
257
257
  if c.edited:
258
258
  prefix = '*'
259
259
  plotnameItem = QTableWidgetItem(self.tr("%s%s" % (prefix, c.plotname)))
260
- plotnameItem.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
260
+ plotnameItem.setTextAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter)
261
261
  self._tableWidget.setItem(row, col, plotnameItem)
262
262
  col += 1
263
263
 
@@ -324,7 +324,7 @@ class Plotter(QMainWindow):
324
324
  vbox.addWidget(scroll)
325
325
 
326
326
  hbox = QHBoxLayout(self._listDialog)
327
- hbox.setAlignment(Qt.AlignCenter)
327
+ hbox.setAlignment(Qt.AlignmentFlag.AlignCenter)
328
328
 
329
329
  # Dismiss Button
330
330
  okButton = QPushButton(self._listDialog)
@@ -361,13 +361,13 @@ class Plotter(QMainWindow):
361
361
  # Create or clear table
362
362
  if self._menuTableWidget is None:
363
363
  self._menuTableWidget = QTableWidget(rows, cols, self)
364
- self._menuTableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
364
+ self._menuTableWidget.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
365
365
  self._menuTableWidget.setHorizontalHeaderLabels(headerLabels)
366
366
  self._menuTableWidget.setAlternatingRowColors(True)
367
- self._menuTableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
367
+ self._menuTableWidget.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
368
368
 
369
369
  # Setup Right-click menu
370
- self._menuTableWidget.setContextMenuPolicy(Qt.ActionsContextMenu)
370
+ self._menuTableWidget.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu)
371
371
  plotCurveAction = QAction("Plot selected curve(s)", self._menuTableWidget)
372
372
  plotCurveAction.triggered.connect(self.__plotMenuCurve)
373
373
  self._menuTableWidget.addAction(plotCurveAction)
@@ -456,7 +456,7 @@ class Plotter(QMainWindow):
456
456
  vbox.addWidget(scroll)
457
457
 
458
458
  hbox = QHBoxLayout(self._menuDialog)
459
- hbox.setAlignment(Qt.AlignCenter)
459
+ hbox.setAlignment(Qt.AlignmentFlag.AlignCenter)
460
460
 
461
461
  # Dismiss Button
462
462
  okButton = QPushButton(self._menuDialog)
@@ -560,7 +560,7 @@ class Plotter(QMainWindow):
560
560
  okButton.setMinimumSize(100, 20)
561
561
  okButton.setMaximumSize(100, 20)
562
562
  okButton.setText('OK')
563
- hbox.addWidget(okButton, Qt.AlignCenter)
563
+ hbox.addWidget(okButton, Qt.AlignmentFlag.AlignCenter)
564
564
  vbox.addLayout(hbox)
565
565
 
566
566
  copy_dialog.resize(300, 500)
@@ -66,6 +66,7 @@ import re
66
66
  import copy
67
67
  from multiprocessing import Pool, cpu_count
68
68
  import subprocess
69
+ import h5py
69
70
 
70
71
  from distutils.version import LooseVersion
71
72
 
@@ -566,6 +567,8 @@ def read(fname, gnu=False, xcol=0, verbose=False, pattern=None, matches=None):
566
567
  return readcsv(fname=fname, xcol=xcol, verbose=verbose)
567
568
  elif str(fname).endswith(".json"):
568
569
  return readsina(fname=fname, verbose=verbose)
570
+ elif str(fname).endswith(".hdf5") or str(fname).endswith(".h5") or str(fname).endswith(".hdf"):
571
+ return readsinahdf5(fname, verbose=verbose)
569
572
  elif gnu or str(fname).endswith(".gnu"):
570
573
  return __loadcolumns(fname, xcol)
571
574
  elif pdbLoaded:
@@ -743,7 +746,7 @@ def readcsv(fname, xcol=0, verbose=False):
743
746
  return curvelist
744
747
 
745
748
 
746
- def readsina(fname, verbose=False):
749
+ def readsina(fname, verbose=False, hdf5_path=None):
747
750
  """
748
751
  Load a Sina JSON data file, add parsed curves to a curvelist.
749
752
 
@@ -758,77 +761,97 @@ def readsina(fname, verbose=False):
758
761
  :type fname: str
759
762
  :param verbose: prints the error stacktrace when True
760
763
  :type verbose: bool
764
+ :param hdf5_path: File path for HDF5 sina file. Should not be set by user, only used internally, defaults to None.
765
+ :type hdf5_path: str, optional.
761
766
  :returns: list: the list of curves from the sina file
762
767
  """
763
- curves = {}
764
- listed_order = []
765
- try:
766
- # Try to load the order in which the user wants to load the curves into PyDV
767
- with open(fname, 'r') as fp:
768
- try:
769
- order_options = json.load(fp)['records'][0]['data']['SINA_timeplot_order']['value']
770
- except:
771
- order_options = []
772
-
773
- # Load the curve data from the curve_sets
774
- with open(fname, 'r') as fp:
768
+ def add_curve_set(curve_sets, record_id, order_options, library=''):
769
+
770
+ curves = {}
771
+ listed_order = []
772
+ for curve_set_name, curve_set in curve_sets.items():
773
+ for name_ind, v_ind in curve_set['independent'].items():
774
+ independent_name = name_ind
775
+ independent_value = v_ind['value']
776
+ for name, v in curve_set['dependent'].items():
777
+ # TODO: Save the name x and y names with the curves
778
+ dependent_variable_name = name
779
+ if order_options:
780
+ full_name = curve_set_name + '__SINA_DEP__' + dependent_variable_name
781
+ else:
782
+ full_name = curve_set_name + '__SINA_DEP__' + dependent_variable_name + \
783
+ '__SINA_INDEP__' + independent_name
784
+ dependent_variable_value = v['value']
785
+ curve_name = dependent_variable_name + ' vs ' + independent_name + " (" + \
786
+ curve_set_name + ")"
787
+ if library != '':
788
+ curve_name += ' ' + library
789
+ full_name += '__LIBRARY__' + library
790
+ c = makecurve(x=independent_value,
791
+ y=dependent_variable_value,
792
+ name=curve_name,
793
+ filename=fname if hdf5_path is None else hdf5_path,
794
+ xlabel=independent_name,
795
+ ylabel=dependent_variable_name,
796
+ title=curve_name,
797
+ record_id=record_id)
798
+ c.step = False
799
+ c.xticks_labels = {}
800
+ if verbose:
801
+ print(f"Appended curve: {curve_name}, len x,y: {len(c.x)},{len(c.y)}")
802
+ curves[full_name] = c
803
+ listed_order.append(full_name)
804
+
805
+ if order_options:
775
806
  try:
776
- sina_file = json.load(fp)
777
- record_id = sina_file['records'][0]['id']
778
- curve_sets = sina_file['records'][0]['curve_sets']
779
- library_data = sina_file['records'][0].get('library_data', {})
780
-
781
- def add_curve_set(curve_sets, curves, listed_order, library=''):
782
- for curve_set_name, curve_set in curve_sets.items():
783
- for name_ind, v_ind in curve_set['independent'].items():
784
- independent_name = name_ind
785
- independent_value = v_ind['value']
786
- for name, v in curve_set['dependent'].items():
787
- # TODO: Save the name x and y names with the curves
788
- dependent_variable_name = name
789
- if order_options:
790
- full_name = curve_set_name + '__SINA_DEP__' + dependent_variable_name
791
- else:
792
- full_name = curve_set_name + '__SINA_DEP__' + dependent_variable_name + \
793
- '__SINA_INDEP__' + independent_name
794
- dependent_variable_value = v['value']
795
- curve_name = dependent_variable_name + ' vs ' + independent_name + " (" + \
796
- curve_set_name + ")"
797
- if library != '':
798
- curve_name += ' ' + library
799
- full_name += '__LIBRARY__' + library
800
- c = makecurve(x=independent_value,
801
- y=dependent_variable_value,
802
- name=curve_name,
803
- filename=fname,
804
- xlabel=independent_name,
805
- ylabel=dependent_variable_name,
806
- title=curve_name,
807
- record_id=record_id)
808
- c.step = False
809
- c.xticks_labels = {}
810
- if verbose:
811
- print("Appended curve: {}, len x,y: {},{}"
812
- .format(curve_name, len(c.x), len(c.y)))
813
- curves[full_name] = c
814
- listed_order.append(full_name)
815
- return curves, listed_order
816
-
817
- curves, listed_order = add_curve_set(curve_sets, curves, listed_order)
818
-
819
- for library in library_data:
820
- if 'curve_sets' in library_data[library]:
821
- curve_sets = library_data[library]['curve_sets']
822
- curves, listed_order = add_curve_set(curve_sets, curves, listed_order, library=library)
807
+ curves_lst_temp = [curves[name] for name in order_options]
823
808
  except KeyError:
824
- print('readsina: Sina file {} is malformed'.format(fname))
809
+ print('readsina: mismatch between dependent variable names in the curve_sets and the '
810
+ 'ordering specified in SINA_timeplot_order. Using default ordering instead.')
811
+ curves_lst_temp = [curves[name] for name in listed_order]
825
812
  if verbose:
826
- traceback.print_exc(file=sys.stdout)
827
- return []
813
+ traceback.print_exc(File=sys.stdout)
814
+ else:
815
+ curves_lst_temp = [curves[name] for name in listed_order]
816
+
817
+ return curves_lst_temp
818
+
819
+ def cycle_thru_recs(sina_file):
820
+ curves_lst = []
821
+
822
+ for rec in sina_file['records']:
828
823
 
829
- # Try to load the order in which the user wants to load the curves into PyDV
830
- if not order_options:
831
- order_options = listed_order
824
+ record_id = rec.get('id', rec.get("local_id", ""))
825
+ curve_sets = rec.get('curve_sets', {})
826
+ library_data = rec.get('library_data', {})
827
+ order_options = rec.get('data', {}).get('SINA_timeplot_order', {}).get('value', [])
828
+
829
+ curves_lst_temp = add_curve_set(curve_sets, record_id, order_options)
830
+ curves_lst.extend(curves_lst_temp)
831
+
832
+ for library in library_data:
833
+ if 'curve_sets' in library_data[library]:
834
+ curve_sets = library_data[library].get('curve_sets', {})
835
+ order_options = library_data[library].get('data',
836
+ {}).get('SINA_timeplot_order',
837
+ {}).get('value', [])
838
+ curves_lst_temp = add_curve_set(curve_sets, record_id, order_options, library=library)
839
+ curves_lst.extend(curves_lst_temp)
840
+ return curves_lst
841
+
842
+ try:
843
+ # Load the curve data from the curve_sets
844
+ try:
845
+ if not isinstance(fname, dict):
846
+ with open(fname, 'r') as fp:
847
+ curves_lst = cycle_thru_recs(json.load(fp))
848
+ else:
849
+ curves_lst = cycle_thru_recs(fname)
850
+ except KeyError:
851
+ print('readsina: Sina file {} is malformed'.format(fname))
852
+ if verbose:
853
+ traceback.print_exc(file=sys.stdout)
854
+ return []
832
855
 
833
856
  except IOError:
834
857
  print('readsina: could not load file: {}'.format(fname))
@@ -836,17 +859,75 @@ def readsina(fname, verbose=False):
836
859
  traceback.print_exc(file=sys.stdout)
837
860
  return []
838
861
 
839
- try:
840
- curves_lst = [curves[name] for name in order_options]
841
- except KeyError:
842
- print('readsina: mismatch between dependent variable names in the curve_sets and the '
843
- 'ordering specified in SINA_timeplot_order. Using default ordering instead.')
844
- if verbose:
845
- traceback.print_exc(File=sys.stdout)
846
- curves_lst = [curves[name] for name in listed_order]
847
862
  return curves_lst
848
863
 
849
864
 
865
+ def readsinahdf5(hdf5_path, verbose=False):
866
+ # def load_document_hdf5(hdf5_path): Taken from sina/utils.py
867
+ """
868
+ Retrieves records and relationships from HDF5
869
+ """
870
+ reconstructed_doc = {}
871
+
872
+ def coerce_numpy_to_json(val):
873
+ # There's no single quick way to do this when numpy and hdf5 combine,
874
+ # so we have a manual method...
875
+ if isinstance(val, bytes):
876
+ val = val.decode("utf-8")
877
+ if isinstance(val, h5py.Empty):
878
+ val = dict()
879
+ if isinstance(val, np.integer):
880
+ val = int(val)
881
+ elif isinstance(val, np.floating):
882
+ val = float(val)
883
+ elif isinstance(val, np.ndarray):
884
+ is_word = len(np.shape(val)) == 1 and isinstance(val[0], bytes)
885
+ val = [x.decode("utf-8") if isinstance(x, bytes)
886
+ else x for x in val.tolist()]
887
+ if is_word:
888
+ val = ''.join(val)
889
+ elif np.shape(val)[0] == 1:
890
+ val = val[0]
891
+ return val
892
+
893
+ def add_arbitrary_path_to_dict(some_path, val):
894
+ chunk = reconstructed_doc
895
+ layers = some_path.split("/")
896
+ for depth, layer in enumerate(layers):
897
+ if not layer:
898
+ continue
899
+ if layer not in chunk:
900
+ chunk[layer] = dict()
901
+ if depth == len(layers) - 1:
902
+ if isinstance(val, list):
903
+ chunk[layer] = [coerce_numpy_to_json(x) for x in val]
904
+ else:
905
+ chunk[layer] = coerce_numpy_to_json(val)
906
+ else:
907
+ chunk = chunk[layer]
908
+
909
+ def yoink_dataset_or_recurse(path, chunk):
910
+ if isinstance(chunk, h5py.Group):
911
+ for key, val in chunk.items():
912
+ # Recovery for common wonky HDF5 issue
913
+ if (isinstance(val, h5py.Group) and '0' in val.keys() and key in ("value", "tags")):
914
+ add_arbitrary_path_to_dict(path + "/" + key, [chunk[key][x][()] for x in val])
915
+ else:
916
+ yoink_dataset_or_recurse(path + "/" + key, val)
917
+ else:
918
+ add_arbitrary_path_to_dict(path, chunk[()])
919
+ with h5py.File(hdf5_path, 'r') as src:
920
+ yoink_dataset_or_recurse("", src)
921
+ # Now we have to (temporarily!) smooth the object->list thing between our hdf5
922
+ # and JSON entries...
923
+ reconstructed_doc["records"] = ([x for x in reconstructed_doc["records"].values()]
924
+ if "records" in reconstructed_doc else list())
925
+ # reconstructed_doc["relationships"] = ([x for x in reconstructed_doc["relationships"].values()]
926
+ # if "relationships" in reconstructed_doc else list())
927
+
928
+ return readsina(reconstructed_doc, hdf5_path=hdf5_path)
929
+
930
+
850
931
  ########################################################
851
932
  ################## Math Functions ##################### # noqa e266
852
933
  ########################################################
@@ -2046,8 +2127,9 @@ def xmax(curvelist, max):
2046
2127
  curves = _convert_to_curvelist(curvelist)
2047
2128
 
2048
2129
  for c in curves:
2049
- c.x = c.x[np.where(c.x <= float(max))]
2050
- c.y = c.y[np.where(c.x <= float(max))]
2130
+ mask = np.where(c.x <= float(max))
2131
+ c.x = c.x[mask]
2132
+ c.y = c.y[mask]
2051
2133
 
2052
2134
 
2053
2135
  def xmin(curvelist, min):
@@ -2063,8 +2145,9 @@ def xmin(curvelist, min):
2063
2145
  curves = _convert_to_curvelist(curvelist)
2064
2146
 
2065
2147
  for c in curves:
2066
- c.x = c.x[np.where(c.x >= float(min))]
2067
- c.y = c.y[np.where(c.x >= float(min))]
2148
+ mask = np.where(c.x >= float(min))
2149
+ c.x = c.x[mask]
2150
+ c.y = c.y[mask]
2068
2151
 
2069
2152
 
2070
2153
  def xminmax(curvelist, min, max):
@@ -2082,8 +2165,9 @@ def xminmax(curvelist, min, max):
2082
2165
  curves = _convert_to_curvelist(curvelist)
2083
2166
 
2084
2167
  for c in curves:
2085
- c.x = c.x[np.where(np.logical_and(c.x >= float(min), c.x <= float(max)))]
2086
- c.y = c.y[np.where(np.logical_and(c.x >= float(min), c.x <= float(max)))]
2168
+ mask = np.where(np.logical_and(c.x >= float(min), c.x <= float(max)))
2169
+ c.x = c.x[mask]
2170
+ c.y = c.y[mask]
2087
2171
 
2088
2172
 
2089
2173
  def ymax(curvelist, max):
@@ -2099,8 +2183,9 @@ def ymax(curvelist, max):
2099
2183
  curves = _convert_to_curvelist(curvelist)
2100
2184
 
2101
2185
  for c in curves:
2102
- c.x = c.x[np.where(c.y <= float(max))]
2103
- c.y = c.y[np.where(c.y <= float(max))]
2186
+ mask = np.where(c.y <= float(max))
2187
+ c.x = c.x[mask]
2188
+ c.y = c.y[mask]
2104
2189
 
2105
2190
 
2106
2191
  def ymin(curvelist, min):
@@ -2116,8 +2201,9 @@ def ymin(curvelist, min):
2116
2201
  curves = _convert_to_curvelist(curvelist)
2117
2202
 
2118
2203
  for c in curves:
2119
- c.x = c.x[np.where(c.y >= float(min))]
2120
- c.y = c.y[np.where(c.y >= float(min))]
2204
+ mask = np.where(c.y >= float(min))
2205
+ c.x = c.x[mask]
2206
+ c.y = c.y[mask]
2121
2207
 
2122
2208
 
2123
2209
  def yminmax(curvelist, min, max):
@@ -2135,8 +2221,9 @@ def yminmax(curvelist, min, max):
2135
2221
  curves = _convert_to_curvelist(curvelist)
2136
2222
 
2137
2223
  for c in curves:
2138
- c.x = c.x[np.where(np.logical_and(c.y >= float(min), c.y <= float(max)))]
2139
- c.y = c.y[np.where(np.logical_and(c.y >= float(min), c.y <= float(max)))]
2224
+ mask = np.where(np.logical_and(c.y >= float(min), c.y <= float(max)))
2225
+ c.x = c.x[mask]
2226
+ c.y = c.y[mask]
2140
2227
 
2141
2228
 
2142
2229
  def yn(curvelist, n):
@@ -3184,7 +3271,7 @@ def fit(c, n=1, logx=False, logy=False):
3184
3271
  if logy:
3185
3272
  y = np.log10(y)
3186
3273
 
3187
- coeffs = scipy.polyfit(x, y, n)
3274
+ coeffs = np.polyfit(x, y, n)
3188
3275
  if len(coeffs) == 2:
3189
3276
  print("slope = ", coeffs[0], " intercept = ", coeffs[1])
3190
3277
  else:
@@ -3200,7 +3287,7 @@ def fit(c, n=1, logx=False, logy=False):
3200
3287
  oString = "%dth " % n
3201
3288
 
3202
3289
  x = np.array(x)
3203
- y = scipy.polyval(coeffs, x)
3290
+ y = np.polyval(coeffs, x)
3204
3291
 
3205
3292
  if logx:
3206
3293
  x = 10.0**x
@@ -3324,6 +3411,45 @@ def getnumpoints(curve):
3324
3411
  return len(curve.x)
3325
3412
 
3326
3413
 
3414
+ def stats(curve):
3415
+ """
3416
+ Print statistics of the given curve.
3417
+
3418
+ :param curve: The given curve
3419
+ """
3420
+
3421
+ def find_mode(array):
3422
+
3423
+ try:
3424
+ mode = scipy.stats.mode(array, keepdims=True)
3425
+ except:
3426
+ mode = scipy.stats.mode(array)
3427
+ if mode.count[0] == 1 and len(array) != 1:
3428
+ return np.nan, np.nan
3429
+ else:
3430
+ return mode.mode[0], mode.count[0]
3431
+
3432
+ numx, countx = find_mode(curve.x)
3433
+ numy, county = find_mode(curve.y)
3434
+
3435
+ print('\nCurve ' + curve.plotname)
3436
+ print('\n\t X:\t Y:')
3437
+ print(f'\n\tlength: {len(curve.x):<15.10g}\t{len(curve.y):<15.10g}')
3438
+ print(f'\tmean: {np.mean(curve.x):<15.10g}\t{np.mean(curve.y):<15.10g}')
3439
+ print(f'\tmedian: {np.median(curve.x):<15.10g}\t{np.median(curve.y):<15.10g}')
3440
+ print(f'\tmode: {numx:<15.10g}\t{numy:<15.10g}')
3441
+ print(f'\t count: {countx:<15.10g}\t{county:<15.10g}')
3442
+ print(f'\tstd: {np.std(curve.x):<15.10g}\t{np.std(curve.y):<15.10g}')
3443
+ print(f'\tskew: {scipy.stats.skew(curve.x):<15.10g}\t{scipy.stats.skew(curve.y):<15.10g}')
3444
+ print(f'\tkurtosis: {scipy.stats.kurtosis(curve.x):<15.10g}\t{scipy.stats.kurtosis(curve.y):<15.10g}') # noqae501
3445
+ print(f'\tmin: {np.min(curve.x):<15.10g}\t{np.min(curve.y):<15.10g}')
3446
+ print(f'\t25%: {np.quantile(curve.x,.25):<15.10g}\t{np.quantile(curve.y,.25):<15.10g}')
3447
+ print(f'\t50%: {np.quantile(curve.x,.50):<15.10g}\t{np.quantile(curve.y,.50):<15.10g}')
3448
+ print(f'\t75%: {np.quantile(curve.x,.75):<15.10g}\t{np.quantile(curve.y,.75):<15.10g}')
3449
+ print(f'\tmax: {np.max(curve.x):<15.10g}\t{np.max(curve.y):<15.10g}')
3450
+ print(f'\tsum: {np.sum(curve.x):<15.10g}\t{np.sum(curve.y):<15.10g}')
3451
+
3452
+
3327
3453
  def getrange(curvelist):
3328
3454
  """
3329
3455
  Get the range of the curve or list of curves.
@@ -0,0 +1 @@
1
+ 01.15.2026
@@ -0,0 +1 @@
1
+ 3.9.0
@@ -1,7 +1,7 @@
1
1
  [tool]
2
2
  [tool.poetry]
3
3
  name = "LLNL-PyDV"
4
- version = "3.8.0"
4
+ version = "3.9.0"
5
5
  description = "PyDV: Python Data Visualizer"
6
6
  license = "BSD"
7
7
  classifiers = [
@@ -64,7 +64,7 @@ build-backend = "poetry.core.masonry.api"
64
64
  line-length = 79
65
65
 
66
66
  [tool.bumpver]
67
- current_version = "3.8.0"
67
+ current_version = "3.9.0"
68
68
  version_pattern = "MAJOR.MINOR.PATCH"
69
69
  commit_message = "bump version {old_version} -> {new_version}"
70
70
  commit = true
@@ -1 +0,0 @@
1
- 09.02.2025
@@ -1 +0,0 @@
1
- 3.8.0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes