LLNL-PyDV 3.4.3__py3-none-any.whl

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.
pydv/pydvpy.py ADDED
@@ -0,0 +1,4491 @@
1
+ # Copyright (c) 2011-2024, Lawrence Livermore National Security, LLC.
2
+ # Produced at the Lawrence Livermore National Laboratory
3
+ # Written by Mason Kwiat, Douglas S. Miller, and Kevin Griffin, Ephraim Rusu
4
+ # e-mail: rusu1@llnl.gov
5
+ # LLNL-CODE-507071
6
+ # All rights reserved.
7
+
8
+ # This file is part of PDV. For details, see <URL describing code and
9
+ # how to download source>. Please also read "Additional BSD Notice".
10
+
11
+ # Redistribution and use in source and binary forms, with or without
12
+ # modification, are permitted provided that the following conditions
13
+ # are met:
14
+
15
+ # Redistributions of source code must retain the above copyright
16
+ # notice, this list of conditions and the disclaimer below.
17
+ # Redistributions in binary form must reproduce the above copyright
18
+ # notice, this list of conditions and the disclaimer (as noted below)
19
+ # in the documentation and/or other materials provided with the
20
+ # distribution. Neither the name of the LLNS/LLNL nor the names of
21
+ # its contributors may be used to endorse or promote products derived
22
+ # from this software without specific prior written permission.
23
+
24
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27
+ # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE
28
+ # LIVERMORE NATIONAL SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR
29
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
32
+ # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
33
+ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
34
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
35
+ # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36
+ # SUCH DAMAGE.
37
+
38
+ # Additional BSD Notice
39
+
40
+ # 1. This notice is required to be provided under our contract with
41
+ # the U.S. Department of Energy (DOE). This work was produced at
42
+ # Lawrence Livermore National Laboratory under Contract
43
+ # No. DE-AC52-07NA27344 with the DOE.
44
+
45
+ # 2. Neither the United States Government nor Lawrence Livermore
46
+ # National Security, LLC nor any of their employees, makes any
47
+ # warranty, express or implied, or assumes any liability or
48
+ # responsibility for the accuracy, completeness, or usefulness of any
49
+ # information, apparatus, product, or process disclosed, or represents
50
+ # that its use would not infringe privately-owned rights.
51
+
52
+ # 3. Also, reference herein to any specific commercial products,
53
+ # process, or services by trade name, trademark, manufacturer or
54
+ # otherwise does not necessarily constitute or imply its endorsement,
55
+ # recommendation, or favoring by the United States Government or
56
+ # Lawrence Livermore National Security, LLC. The views and opinions
57
+ # of authors expressed herein do not necessarily state or reflect
58
+ # those of the United States Government or Lawrence Livermore National
59
+ # Security, LLC, and shall not be used for advertising or product
60
+ # endorsement purposes.
61
+
62
+
63
+ """
64
+ A python interface for PyDV functionality.
65
+
66
+ .. module: pydvpy
67
+ .. moduleauthor:: Ephraim Rusu <rusu1@llnl.gov>
68
+
69
+ >>> import pydv.pydvpy as pydvif
70
+ """
71
+
72
+ import json
73
+ import os
74
+ import traceback
75
+ import sys
76
+ import re
77
+ import copy
78
+ import random as sysrand
79
+
80
+ from distutils.version import LooseVersion
81
+
82
+ import numpy as np
83
+ import scipy
84
+ import scipy.integrate
85
+ import scipy.special
86
+ import scipy.signal
87
+ import scipy.misc
88
+
89
+ import matplotlib.pyplot as plt
90
+
91
+ try:
92
+ from matplotlib import style
93
+ stylesLoaded = True
94
+ except:
95
+ stylesLoaded = False
96
+
97
+ # HPC Import
98
+ try:
99
+ import curve
100
+
101
+ # Package Import
102
+ except ImportError:
103
+ from pydv import curve
104
+
105
+ try:
106
+ import pact.pdb as pdb
107
+ pdbLoaded = True
108
+ except:
109
+ pdbLoaded = False
110
+
111
+ try:
112
+ import gnuplotlib as gp # noqaf401
113
+ import time # noqaf401
114
+ except:
115
+ pass
116
+
117
+
118
+ def span(xmin, xmax, numpts=100):
119
+ """
120
+ Generates a straight line of slope 1 and y intercept 0 in the specified domain with an optional number
121
+ of points.
122
+
123
+ >>> c = pydvif.span(1, 10)
124
+
125
+ :param xmin: The minimum x value
126
+ :type xmin: float
127
+ :param xmax: The maximum x value
128
+ :type xmax: float
129
+ :param numpts: The number of points used to plot the line
130
+ :type numpts: int
131
+ :returns: curve -- the curve object representing the straight line.
132
+ """
133
+ spacing = (float(xmax) - float(xmin)) / (float(numpts) - 1.0)
134
+ fxmin = float(xmin)
135
+ x = []
136
+ for i in range(numpts):
137
+ x.append(fxmin)
138
+ fxmin += spacing
139
+ x = np.array(x)
140
+ y = np.array(x)
141
+ c = makecurve(x, y, f'Straight Line (m: 1.0 b: 0.0 xmin: {xmin} xmax: {xmax})')
142
+
143
+ return c
144
+
145
+
146
+ def makecurve(x, y, name='Curve', fname='', xlabel='', ylabel='', title='', record_id='',
147
+ step=False, xticks_labels=None):
148
+ """
149
+ Generate a curve from two lists of numbers.
150
+
151
+ >>> c1 = pydvif.makecurve([1, 2, 3, 4], [5, 10, 15, 20])
152
+
153
+ >>> c2 = pydvif.makecurve([1, 2, 3, 4], [7, 8, 9, 10], 'Line')
154
+
155
+ :param x: list of x values
156
+ :type x: list
157
+ :param y: list of y values
158
+ :type y: list
159
+ :param name: the name of the new curve
160
+ :type name: str
161
+ :param fname: the name of the file containing this curves data.
162
+ :type fname: str
163
+ :returns: curve -- the curve generated from the x and y list of values.
164
+ """
165
+ if len(x) != len(y):
166
+ print(f"Curve {name} doesn't have the same length: len(x)={len(x)} and len(y)={len(y)} ")
167
+ name += " !!!ERROR:len(x)!=len(y)!!!"
168
+ c = curve.Curve(fname, name, record_id, xlabel, ylabel, title, step, xticks_labels)
169
+ c.x = np.array(x, dtype=float)
170
+ c.y = np.array(y, dtype=float)
171
+
172
+ return c
173
+
174
+
175
+ def get_styles():
176
+ """
177
+ Get the list of available plot styles.
178
+
179
+ :return: list -- the list of available style names or an empty list if no styles exist.
180
+ """
181
+ if stylesLoaded:
182
+ return plt.style.available
183
+
184
+ return list()
185
+
186
+
187
+ def create_plot(curvelist, **kwargs):
188
+ """
189
+ Create a plot from of the curves in curvelist. The available keyword arguments are:
190
+ * Filename: fname='myFile'
191
+ * Save Format: ftype='pdf'
192
+ * Plot Title: title='My Title'
193
+ * X-Axis Label: xlabel='X'
194
+ * Y-Axis Label: ylabel='Y'
195
+ * Show/Hide Plot Legend: legend=True
196
+ * Plot Style: stylename='ggplot'
197
+ * Show X-Axis in log scale: xls=True
198
+ * Show Y-Axis in log scale: yls=True
199
+ * Set the width of the figure in inches: fwidth=1.2
200
+ * Set the height of the figure in inches: fheight=2.1
201
+
202
+ >>> curves = pydvif.read('testData.txt')
203
+
204
+ >>> plot1, fig1, ax1 = pydvif.create_plot(curves, fname='myPlot1')
205
+
206
+ >>> plot2, fig2, ax2 = pydvif.create_plot(curves, fname='myPlot2', ftype='pdf',
207
+ fwidth=10.1, fheight=11.3, title='My Plot',
208
+ xlabel='X', ylabel='Y', legend=True,
209
+ stylename='ggplot')
210
+
211
+ :param curvelist: The curve or list of curves to plot
212
+ :type curvelist: list
213
+ :param kwargs: The keyword arguments to modify the plot.
214
+ :type kwargs: dict
215
+ :return: matplotlib.pyplot, matplotlib.pyplot.figure, and matplotlib.pyplot.axes
216
+ """
217
+ fname = None
218
+ ftype = 'png'
219
+ title = ''
220
+ xlabel = ''
221
+ ylabel = ''
222
+ legend = False
223
+ stylename = 'ggplot'
224
+ xls = False
225
+ yls = False
226
+ fwidth = None
227
+ fheight = None
228
+
229
+ # Process kwargs
230
+ for key, val in list(kwargs.items()):
231
+ if key == 'fname':
232
+ fname = val
233
+ elif key == 'ftype':
234
+ ftype = val
235
+ elif key == 'title':
236
+ title = val
237
+ elif key == 'xlabel':
238
+ xlabel = val
239
+ elif key == 'ylabel':
240
+ ylabel = val
241
+ elif key == 'legend':
242
+ legend = val
243
+ elif key == 'stylename':
244
+ stylename = val
245
+ elif key == 'xls':
246
+ xls = val
247
+ elif key == 'yls':
248
+ yls = val
249
+ elif key == 'fwidth':
250
+ fwidth = val
251
+ elif key == 'fheight':
252
+ fheight = val
253
+
254
+ if stylesLoaded:
255
+ styles = get_styles()
256
+
257
+ try:
258
+ idx = styles.index(stylename)
259
+ style.use(styles[idx])
260
+ except:
261
+ if len(styles) > 0:
262
+ style.use(styles[0])
263
+
264
+ plt.clf()
265
+ plt.cla()
266
+ axis = plt.gca()
267
+
268
+ if (xls):
269
+ axis.set_xscale('log', nonposx='clip')
270
+ if (yls):
271
+ axis.set_yscale('log', nonposy='clip')
272
+
273
+ curves = list()
274
+
275
+ if isinstance(curvelist, list):
276
+ curves.extend(curvelist)
277
+ else:
278
+ curves.append(curvelist)
279
+
280
+ for cur in curves:
281
+ if not cur.hidden:
282
+ xdat = np.array(cur.x)
283
+ ydat = np.array(cur.y)
284
+
285
+ if (yls):
286
+ for i in range(len(ydat)):
287
+ if (ydat[i] < 0):
288
+ ydat[i] = 1e-301 # custom ydata clipping
289
+ if (xls):
290
+ for i in range(len(xdat)):
291
+ if (xdat[i] < 0):
292
+ xdat[i] = 1e-301 # custom xdata clipping
293
+
294
+ if cur.ebar is not None:
295
+ c = plt.errorbar(xdat, ydat, yerr=[cur.ebar[0], cur.ebar[1]],
296
+ xerr=[cur.ebar[2], cur.ebar[3]], fmt='-')
297
+ elif cur.erange is not None:
298
+ c = plt.plot(xdat, ydat)
299
+ plt.fill_between(xdat, ydat - cur.erange[0], ydat + cur.erange[1],
300
+ alpha=0.4, color=c[0].get_color())
301
+ else:
302
+ c = plt.plot(xdat, ydat)
303
+
304
+ if cur.linespoints:
305
+ plt.setp(c[0], marker=cur.marker, markersize=cur.markersize, linestyle=cur.linestyle)
306
+ elif cur.scatter:
307
+ plt.setp(c[0], marker=cur.marker, markersize=cur.markersize, linestyle=' ')
308
+ else:
309
+ plt.setp(c[0], linestyle=cur.linestyle)
310
+
311
+ if cur.linewidth:
312
+ plt.setp(c[0], lw=cur.linewidth)
313
+ plt.setp(c[0], mew=cur.linewidth)
314
+
315
+ plt.setp(c[0], label=cur.name)
316
+
317
+ if cur.color != '':
318
+ plt.setp(c, color=cur.color)
319
+ else:
320
+ cur.color = c[0].get_color()
321
+
322
+ if cur.dashes is not None:
323
+ c[0].set_dashes(cur.dashes)
324
+
325
+ if legend:
326
+ plt.legend(fancybox=True, numpoints=1, loc=1, ncol=1).get_frame().set_alpha(0.5)
327
+
328
+ plt.xlabel(xlabel)
329
+ plt.ylabel(ylabel)
330
+ plt.title(title)
331
+
332
+ # Change figure size
333
+ figure = plt.gcf()
334
+ if fwidth is not None:
335
+ figure.set_figwidth(float(fwidth), True)
336
+ if fheight is not None:
337
+ figure.set_figheight(float(fheight), True)
338
+
339
+ if fname is not None:
340
+ try:
341
+ plt.savefig(fname + '.' + ftype, format=ftype)
342
+ except:
343
+ print('Error: Could not save image to ' + fname + ' of type ' + ftype)
344
+
345
+ return plt, figure, axis
346
+
347
+
348
+ def save(fname, curvelist, verbose=False, save_labels=False):
349
+ """
350
+ Saves the given Curve or list of Curves to a file named fname.
351
+
352
+ >>> curves = list()
353
+
354
+ >>> curves.append(pydvif.makecurve([1, 2, 3, 4], [5, 10, 15, 20]))
355
+
356
+ >>> pydvif.save('myfile.txt', curves) OR
357
+
358
+ >>> pydvif.save('myfile.txt', curves[0])
359
+
360
+ :param fname: ULTRA filename
361
+ :type fname: str
362
+ :param curvelist: The curve or list of curves to save
363
+ :type curvelist: Curve or list
364
+ :param verbose: prints the error stacktrace when True
365
+ :type verbose: bool
366
+ """
367
+ curves = list()
368
+
369
+ if isinstance(curvelist, list):
370
+ curves.extend(curvelist)
371
+ else:
372
+ curves.append(curvelist)
373
+
374
+ try:
375
+ f = open(fname, 'w')
376
+ for cur in curves:
377
+ if save_labels:
378
+ print('# ' + cur.name + ' # xlabel ' + cur.xlabel + ' # ylabel ' + cur.ylabel + '\n')
379
+ f.write('# ' + cur.name + ' # xlabel ' + cur.xlabel + ' # ylabel ' + cur.ylabel + '\n')
380
+ else:
381
+ f.write('# ' + cur.name + '\n')
382
+ for dex in range(len(cur.x)):
383
+ f.write(' ' + str(cur.x[dex]) + ' ' + str(cur.y[dex]) + '\n')
384
+ except:
385
+ print('Error: Can not write to: ' + fname)
386
+ if verbose:
387
+ traceback.print_exc(file=sys.stdout)
388
+ finally:
389
+ if f:
390
+ f.close()
391
+
392
+
393
+ def savecsv(fname, curvelist, verbose=False):
394
+ """
395
+ Saves the Curve or list of Curves to file in comma separated values (csv) format. Assumes
396
+ all curves have the same x basis.
397
+
398
+ >>> curves = list()
399
+
400
+ >>> curves.append(pydvif.makecurve([1, 2, 3, 4], [5, 10, 15, 20]))
401
+
402
+ >>> pydvif.savecsv('myfile.csv', curves)
403
+
404
+ :param fname: ULTRA filename
405
+ :type fname: str
406
+ :param curvelist: The Curve or list of Curves to save
407
+ :type curvelist: list
408
+ :param verbose: prints the error stacktrace when True
409
+ :type verbose: bool
410
+ """
411
+ curves = list()
412
+
413
+ if isinstance(curvelist, list):
414
+ curves.extend(curvelist)
415
+ else:
416
+ curves.append(curvelist)
417
+
418
+ try:
419
+ f = open(fname, 'w')
420
+ s = '# time'
421
+ for cur in curves:
422
+ s += ', ' + cur.name
423
+ s += '\n'
424
+ f.write(s)
425
+ for i in range(len(curvelist[0].x)):
426
+ s = str(curvelist[0].x[i])
427
+ for j in range(len(curvelist)):
428
+ s += ', ' + str(curvelist[j].y[i])
429
+ s += '\n'
430
+ f.write(s)
431
+ except:
432
+ print('Error: Can not write to: ' + fname)
433
+ if verbose:
434
+ traceback.print_exc(file=sys.stdout)
435
+ finally:
436
+ if f:
437
+ f.close()
438
+
439
+
440
+ def read(fname, gnu=False, xcol=0, verbose=False, pattern=None, matches=None):
441
+ """
442
+ Read the file and add parsed curves to a curvelist
443
+
444
+ >>> curves = pydvif.read('testData.txt')
445
+
446
+ >>> curves = pydvif.read('testData.txt', False, 0, False, '*_name', 20)
447
+
448
+ :param fname: ULTRA filename
449
+ :type fname: str
450
+ :param gnu: optional, flag to determine if the file is a column oriented (.gnu) file.
451
+ :type gnu: bool
452
+ :param xcol: optional, x-column number for column oriented (.gnu) files
453
+ :type xcol: int
454
+ :param verbose: optional, prints the error stacktrace when True
455
+ :type verbose: bool
456
+ :param pattern: optional, the regular expression pattern
457
+ :type pattern: str
458
+ :param matches: optional, maximum number of times to match pattern, if specified
459
+ :type matches: int
460
+ :returns: list -- the list of curves from the file matching pattern, if specified
461
+
462
+ """
463
+ def bundle_curve(_curve, build_x, build_y):
464
+
465
+ _curve.xticks_labels = {}
466
+
467
+ # Numerical data
468
+ try:
469
+ float(build_x[0])
470
+
471
+ # X tick label data
472
+ except:
473
+
474
+ xticks = list(set(build_x))
475
+ xticks.sort()
476
+ xticks_dict = {}
477
+
478
+ for i, xtick in enumerate(xticks):
479
+ xticks_dict[xtick] = i
480
+
481
+ build_x = [xticks_dict[xtick] for xtick in build_x]
482
+
483
+ _curve.xticks_labels = xticks_dict
484
+
485
+ # Step Data
486
+ if len(build_x) != len(build_y):
487
+ build_y.append(build_y[-1])
488
+
489
+ _curve.x = np.array(build_x, dtype=float).repeat(2)[1:]
490
+ _curve.y = np.array(build_y, dtype=float).repeat(2)[:-1]
491
+ _curve.step = True
492
+ _curve.step_original_x = np.array(build_x, dtype=float)
493
+ _curve.step_original_y = np.array(build_y[:-1], dtype=float)
494
+ # Numerical Data
495
+ else:
496
+ _curve.x = np.array(build_x, dtype=float)
497
+ _curve.y = np.array(build_y, dtype=float)
498
+ _curve.step = False
499
+
500
+ return _curve
501
+
502
+ curve_list = list()
503
+ regex = None
504
+
505
+ if pattern:
506
+ regex = re.compile(r"%s" % pattern)
507
+ fname = os.path.expanduser(fname)
508
+ _, ext = os.path.splitext(fname)
509
+ try:
510
+ if gnu or ext == '.gnu':
511
+ return __loadcolumns(fname, xcol)
512
+
513
+ if pdbLoaded:
514
+ try:
515
+ fpdb = pdb.open(fname, 'r')
516
+ return __loadpdb(fname, fpdb)
517
+ except:
518
+ pass
519
+
520
+ match_count = 0
521
+ build_list_x = list()
522
+ build_list_y = list()
523
+ current = None
524
+ new_curve = True
525
+ potential_curve_name = ""
526
+ xlabels = {}
527
+ ylabels = {}
528
+ xlabel = ''
529
+ ylabel = ''
530
+ with open(fname, 'r') as f:
531
+ for line in f:
532
+ labels = False
533
+ split_line = re.split(r'[ \t]+', str.strip(line))
534
+
535
+ # No space between curvename and hashtag #mycurve
536
+ try: # Exponential numbers and single text will cause issues
537
+ if re.search('[a-zA-Z]', split_line[0]):
538
+ split_line_2 = re.split(r'#', str.strip(line))
539
+ split_line = [None] * 2
540
+ split_line[0] = '#'
541
+ split_line[1] = split_line_2[1]
542
+ except:
543
+ split_line = re.split(r'[ \t]+', str.strip(line))
544
+
545
+ # Check for labels
546
+ split_line_3 = re.split(r'#', str.strip(line))
547
+ for split in split_line_3:
548
+
549
+ if re.search('[a-zA-Z]', split):
550
+ if 'xlabel' in split:
551
+ xlabel = split.replace('xlabel', '').strip()
552
+ labels = True
553
+ if 'ylabel' in split:
554
+ ylabel = split.replace('ylabel', '').strip()
555
+ labels = True
556
+
557
+ # Contains x and/or y labels
558
+ if labels:
559
+ split_line = [None] * 2
560
+ split_line[0] = '#'
561
+ split_line[1] = split_line_3[1].strip()
562
+ xlabels[split_line[1]] = xlabel
563
+ ylabels[split_line[1]] = ylabel
564
+ xlabel = ''
565
+ ylabel = ''
566
+
567
+ if not split_line or not split_line[0]:
568
+ continue
569
+ elif split_line[0] in {'##', 'end', 'End', 'END'}:
570
+ continue
571
+ elif split_line[0] == '#':
572
+ # We may have just finished buiding a curve, so we need to
573
+ # add it to the list of curves.
574
+ # If this is the first curve, then current will be None, so
575
+ # we won't add anything.
576
+ # If there is a sequence of lines that start with # before
577
+ # getting to the actual data, then the new_curve flag will
578
+ # keep us from adding all those comments as curves.
579
+ if current and not new_curve:
580
+ # Need this since it will add last match below and outside loop
581
+ if matches and match_count >= matches:
582
+ break
583
+
584
+ curve_list.append(bundle_curve(current, build_list_x, build_list_y))
585
+ build_list_x = list()
586
+ build_list_y = list()
587
+
588
+ # Begin setup of new curve
589
+ new_curve = True
590
+ potential_curve_name = ' '.join(split_line[1:])
591
+ else:
592
+ if new_curve:
593
+ curve_name = potential_curve_name
594
+ new_curve = False
595
+ if regex:
596
+ if regex.search(curve_name):
597
+ match_count += 1
598
+ current = curve.Curve(fname, curve_name,
599
+ xlabel=xlabels.get(curve_name, ''),
600
+ ylabel=ylabels.get(curve_name, ''))
601
+
602
+ # Step Data
603
+ if len(split_line) == 1:
604
+ build_list_x.append(split_line[0])
605
+ # Numerical Data
606
+ elif len(split_line) == 2:
607
+ build_list_x.append(split_line[0])
608
+ build_list_y.append(split_line[-1])
609
+ # Label Data and Paired Data
610
+ else:
611
+ try: # Paired Data
612
+ float(split_line[0])
613
+ build_list_x += split_line[::2]
614
+ build_list_y += split_line[1::2]
615
+ except: # Label Data
616
+ build_list_x.append(" ".join(split_line[:-1]))
617
+ build_list_y.append(split_line[-1])
618
+ else:
619
+ current = None
620
+ else:
621
+ current = curve.Curve(fname, curve_name,
622
+ xlabel=xlabels.get(curve_name, ''),
623
+ ylabel=ylabels.get(curve_name, ''))
624
+
625
+ # Step Data
626
+ if len(split_line) == 1:
627
+ build_list_x.append(split_line[0])
628
+ # Numerical Data
629
+ elif len(split_line) == 2:
630
+ build_list_x.append(split_line[0])
631
+ build_list_y.append(split_line[-1])
632
+ # Label Data and Paired Data
633
+ else:
634
+ try: # Paired Data
635
+ float(split_line[0])
636
+ build_list_x += split_line[::2]
637
+ build_list_y += split_line[1::2]
638
+ except: # Label Data
639
+ build_list_x.append(" ".join(split_line[:-1]))
640
+ build_list_y.append(split_line[-1])
641
+
642
+ elif current and not new_curve: # add data to current curve
643
+
644
+ # Step Data
645
+ if len(split_line) == 1:
646
+ build_list_x.append(split_line[0])
647
+ # Numerical Data
648
+ elif len(split_line) == 2:
649
+ build_list_x.append(split_line[0])
650
+ build_list_y.append(split_line[-1])
651
+ # Label Data and Paired Data
652
+ else:
653
+ try: # Paired Data
654
+ float(split_line[0])
655
+ build_list_x += split_line[::2]
656
+ build_list_y += split_line[1::2]
657
+ except: # Label Data
658
+ build_list_x.append(" ".join(split_line[:-1]))
659
+ build_list_y.append(split_line[-1])
660
+
661
+ if current and build_list_x and build_list_y:
662
+ curve_list.append(bundle_curve(current, build_list_x, build_list_y))
663
+
664
+ except IOError:
665
+ print('could not load file: {}'.format(fname))
666
+ if verbose:
667
+ traceback.print_exc(file=sys.stdout)
668
+ except ValueError:
669
+ print('invalid pydv file: {}'.format(fname))
670
+ if verbose:
671
+ traceback.print_exc(file=sys.stdout)
672
+
673
+ return curve_list
674
+
675
+
676
+ def filtercurves(curvelist, pattern):
677
+ """
678
+ Filters the list of curves based on the regular expression pattern.
679
+
680
+ >>> curves = pydvif.filtercurves(curves, "*_name")
681
+
682
+ :param curvelist: the list of curves
683
+ :type curvelist: Curve
684
+ :param pattern: the regular expression pattern
685
+ :type pattern: str
686
+ :return: list -- The list of filtered curves from curvelist based on the regular expression pattern
687
+ """
688
+ results = list()
689
+ regex = re.compile(r"%s" % pattern)
690
+
691
+ for c in curvelist:
692
+ if regex.search(c.name) is not None:
693
+ results.append(c)
694
+
695
+ return results
696
+
697
+
698
+ def readcsv(fname, xcol=0, verbose=False):
699
+ """
700
+ Load a csv (comma separated values) data file, add parsed curves to
701
+ a curvelist. '#' is the comment character. First uncommented line must
702
+ be the column labels. We assume the first column is the x-data, every
703
+ other column is y-data. We also assume all columns are the same length.
704
+
705
+ >>> curves = readcsv('testData.csv')
706
+
707
+ :param fname: csv filename
708
+ :type fname: str
709
+ :param xcol: x-column number for column oriented (.gnu) files
710
+ :type xcol: int
711
+ :param verbose: prints the error stacktrace when True
712
+ :type verbose: bool
713
+ :returns: list -- the list of curves from the csv file
714
+ """
715
+
716
+ curvelist = list()
717
+
718
+ try:
719
+ f = open(fname, 'r')
720
+ except IOError:
721
+ print('readcsv: could not load file: ' + fname)
722
+ if verbose:
723
+ traceback.print_exc(file=sys.stdout)
724
+ return curvelist
725
+
726
+ try:
727
+ lines = f.readlines()
728
+ iLine = 0
729
+ for line in lines:
730
+ if line[0] != '#':
731
+ break
732
+ iLine += 1
733
+ if iLine == 0 and False: # FIXME make condition to catch no labels
734
+ print('WARNING: columns have no labels, labels will be assigned...someday')
735
+ alllabels = lines[iLine] # this line has the labels on it.
736
+ colLabels = alllabels.split(',')
737
+ colLabels = [w.strip() for w in colLabels]
738
+ for w in colLabels: # if someone made labels with quotes, kill the quotes
739
+ if '"' in w:
740
+ w.replace('"', '')
741
+ # check that we have a label for every column
742
+ if len(colLabels) != len(lines[iLine].split(',')) and iLine > 0:
743
+ raise RuntimeError('Sorry, right now PDV requires you to have a label for every column.')
744
+ # We assume some column is the x-data, every other column
745
+ # is y-data
746
+ iLine += 1 # go to next line after header labels
747
+ # CSV Data is in x and y pairs
748
+ if xcol == 'paired':
749
+ xcol = 0
750
+ paired = True
751
+ # CSV Data has a single shared x column
752
+ else:
753
+ xcol = int(xcol)
754
+ paired = False
755
+ numcurves = len(lines[iLine].split(',')) - 1
756
+
757
+ # Make the curves, append them to self.curvelist.
758
+ # First, get data into lists of numbers
759
+ # numDataLines = len(lines) - iLine
760
+ localCurves = []
761
+ for i in range(numcurves + 1):
762
+ localCurves.append([]) # FIGURE OUT COOL WAY TO DO THIS LATER: localCurves = (numcurves+1)*[[]]
763
+ # turn the strings into numbers
764
+ for line in lines[iLine:]:
765
+ nums = [np.nan if not n or n == '\n' else float(n) for n in line.split(',')]
766
+ # print 'nums = ', nums, 'numcurves = ', numcurves
767
+ assert len(nums) == numcurves + 1
768
+ if xcol >= numcurves:
769
+ print('xcolumn is %d, larger than the number of curves' % xcol,
770
+ 'in the file, use "setxcolumn" to fix that')
771
+ for colID in range(numcurves + 1):
772
+ localCurves[colID].append(nums[colID])
773
+ # convert lists to numpy arrays
774
+ for colID in range(numcurves):
775
+ localCurves[colID] = np.array(localCurves[colID])
776
+ # Make Curve objects, add to self.curvelist
777
+ if paired:
778
+ for colID in range(0, numcurves + 1, 2):
779
+ colLabels[colID] = colLabels[colID][:-4] # ' [x]'
780
+ x = np.array(localCurves[colID])
781
+ x = x[~np.isnan(x)]
782
+ y = np.array(localCurves[colID + 1])
783
+ y = y[~np.isnan(y)]
784
+ c = makecurve(x, y, colLabels[colID], fname)
785
+ print("Appended curve: ", colLabels[colID], len(c.x), len(c.y))
786
+ curvelist.append(c)
787
+ else:
788
+ for colID in range(numcurves + 1):
789
+ if colID != xcol:
790
+ c = makecurve(localCurves[xcol], localCurves[colID], colLabels[colID], fname)
791
+ print("Appended curve: ", colLabels[colID], len(c.x), len(c.y))
792
+ curvelist.append(c)
793
+ # tidy up
794
+ f.close()
795
+ # anticipate failure!
796
+ except ValueError as e:
797
+ print(e)
798
+ print('readcsv: invalid pydv file: ' + fname)
799
+ if verbose:
800
+ traceback.print_exc(file=sys.stdout)
801
+
802
+ return curvelist
803
+
804
+
805
+ def readsina(fname, verbose=False):
806
+ """
807
+ Load a Sina JSON data file, add parsed curves to a curvelist.
808
+
809
+ We assume JSON conforming to the Sina schema, with each curve defined in a curve_set. We assume
810
+ there is only one record, and if there are more then we only read the first one. We also assume
811
+ only one independent variable per curve_set; if there are more than one, then PyDV may exhibit
812
+ undefined behavior. Can also read curve_sets within libraries in library_data.
813
+
814
+ >>> curves = readsina('testData.json')
815
+
816
+ :param fname: Sina JSON filename
817
+ :type fname: str
818
+ :param verbose: prints the error stacktrace when True
819
+ :type verbose: bool
820
+ :returns: list: the list of curves from the sina file
821
+ """
822
+ curves = {}
823
+ listed_order = []
824
+ try:
825
+ # Load the curve data from the curve_sets
826
+ with open(fname, 'r') as fp:
827
+ try:
828
+ sina_file = json.load(fp)
829
+ record_id = sina_file['records'][0]['id']
830
+ curve_sets = sina_file['records'][0]['curve_sets']
831
+ library_data = sina_file['records'][0].get('library_data', {})
832
+
833
+ def add_curve_set(curve_sets, curves, listed_order, library=''):
834
+ for curve_set_name, curve_set in curve_sets.items():
835
+ independent_dict = next(iter(curve_set['independent'].items()))
836
+ independent_name = independent_dict[0]
837
+ independent_value = independent_dict[1]['value']
838
+ for name, v in curve_set['dependent'].items():
839
+ # TODO: Save the name x and y names with the curves
840
+ dependent_variable_name = name
841
+ full_name = curve_set_name + '__SINA_DEP__' + dependent_variable_name
842
+ dependent_variable_value = v['value']
843
+ curve_name = dependent_variable_name + ' vs ' + independent_name + " (" + \
844
+ curve_set_name + ")"
845
+ if library != '':
846
+ curve_name += ' ' + library
847
+ full_name += '__LIBRARY__' + library
848
+ c = makecurve(x=independent_value, y=dependent_variable_value,
849
+ name=curve_name, fname=fname, xlabel=independent_name,
850
+ ylabel=dependent_variable_name, title=curve_name, record_id=record_id)
851
+ c.step = False
852
+ c.xticks_labels = {}
853
+ print("Appended curve: {}, len x,y: {},{}"
854
+ .format(dependent_variable_name, len(c.x), len(c.y)))
855
+ curves[full_name] = c
856
+ listed_order.append(full_name)
857
+ return curves, listed_order
858
+
859
+ curves, listed_order = add_curve_set(curve_sets, curves, listed_order)
860
+
861
+ for library in library_data:
862
+ if 'curve_sets' in library_data[library]:
863
+ curve_sets = library_data[library]['curve_sets']
864
+ curves, listed_order = add_curve_set(curve_sets, curves, listed_order, library=library)
865
+ except KeyError:
866
+ print('readsina: Sina file {} is malformed'.format(fname))
867
+ if verbose:
868
+ traceback.print_exc(file=sys.stdout)
869
+ return []
870
+
871
+ # Try to load the order in which the user wants to load the curves into PyDV
872
+ with open(fname, 'r') as fp:
873
+ try:
874
+ order_options = json.load(fp)['records'][0]['data']['SINA_timeplot_order']['value']
875
+ except:
876
+ order_options = listed_order
877
+
878
+ except IOError:
879
+ print('readsina: could not load file: {}'.format(fname))
880
+ if verbose:
881
+ traceback.print_exc(file=sys.stdout)
882
+ return []
883
+
884
+ try:
885
+ curves_lst = [curves[name] for name in order_options]
886
+ except KeyError:
887
+ print('readsina: mismatch between dependent variable names in the curve_sets and the '
888
+ 'ordering specified in SINA_timeplot_order. Using default ordering instead.')
889
+ if verbose:
890
+ traceback.print_exc(File=sys.stdout)
891
+ curves_lst = [curves[name] for name in listed_order]
892
+ return curves_lst
893
+
894
+
895
+ ########################################################
896
+ ################## Math Functions ##################### # noqa e266
897
+ ########################################################
898
+
899
+ def cos(curvelist):
900
+ """
901
+ Take the cosine of y values of a Curve or list of Curves.
902
+
903
+ >>> curves = pydvif.read('testData.txt')
904
+
905
+ >>> pydvif.cos(curves) OR
906
+
907
+ >>> pydvif.cos(curves[0])
908
+
909
+ :param curvelist: The Curve or list of Curves
910
+ :type curvelist: Curve or list
911
+ """
912
+ curves = list()
913
+
914
+ if isinstance(curvelist, list):
915
+ curves.extend(curvelist)
916
+ else:
917
+ curves.append(curvelist)
918
+
919
+ for cur in curves:
920
+ cur.y = np.cos(cur.y)
921
+
922
+
923
+ def cosx(curvelist):
924
+ """
925
+ Take the cosine of x values of a Curve or list of Curves.
926
+
927
+ >>> curves = pydvif.read('testData.txt')
928
+
929
+ >>> pydvif.cosx(curves) OR
930
+
931
+ >>> pydvif.cosx(curves[0])
932
+
933
+ :param curvelist: The Curve or list of Curves
934
+ :type curvelist: Curve or list
935
+ """
936
+ curves = list()
937
+
938
+ if isinstance(curvelist, list):
939
+ curves.extend(curvelist)
940
+ else:
941
+ curves.append(curvelist)
942
+
943
+ for cur in curves:
944
+ cur.x = np.cos(cur.x)
945
+
946
+
947
+ def cosh(curvelist):
948
+ """
949
+ Take the hyperbolic cosine of y values of a Curve or list of Curves.
950
+
951
+ >>> curves = pydvif.read('testData.txt')
952
+
953
+ >>> pydvif.cosh(curves) OR
954
+
955
+ >>> pydvif.cosh(curves[0])
956
+
957
+ :param curvelist: The Curve or list of curves
958
+ :type curvelist: Curve or list
959
+ """
960
+ curves = list()
961
+
962
+ if isinstance(curvelist, list):
963
+ curves.extend(curvelist)
964
+ else:
965
+ curves.append(curvelist)
966
+
967
+ for cur in curves:
968
+ cur.y = np.cosh(cur.y)
969
+
970
+
971
+ def coshx(curvelist):
972
+ """
973
+ Take the hyperbolic cosine of x values of a Curve or list of Curves.
974
+
975
+ >>> curves = pydvif.read('testData.txt')
976
+
977
+ >>> pydvif.coshx(curves) OR
978
+
979
+ >>> pydvif.coshx(curves[0])
980
+
981
+ :param curvelist: The Curve or list of curves
982
+ :type curvelist: Curve or list
983
+ """
984
+ curves = list()
985
+
986
+ if isinstance(curvelist, list):
987
+ curves.extend(curvelist)
988
+ else:
989
+ curves.append(curvelist)
990
+
991
+ for cur in curves:
992
+ cur.x = np.cosh(cur.x)
993
+
994
+
995
+ def acosh(curvelist):
996
+ """
997
+ Take the hyperbolic arccosine of y values of a Curve or list of Curves.
998
+
999
+ >>> curves = pydvif.read('testData.txt')
1000
+
1001
+ >>> pydvif.acosh(curves) OR
1002
+
1003
+ >>> pydvif.acosh(curves[0])
1004
+
1005
+ :param curvelist: The Curve or list of curves
1006
+ :type curvelist: Curve or list
1007
+ """
1008
+ curves = list()
1009
+
1010
+ if isinstance(curvelist, list):
1011
+ curves.extend(curvelist)
1012
+ else:
1013
+ curves.append(curvelist)
1014
+
1015
+ for cur in curves:
1016
+ cur.y = np.arccosh(cur.y)
1017
+
1018
+
1019
+ def acoshx(curvelist):
1020
+ """
1021
+ Take the hyperbolic arccosine of x values of a Curve or list of Curves.
1022
+
1023
+ >>> curves = pydvif.read('testData.txt')
1024
+
1025
+ >>> pydvif.acoshx(curves) OR
1026
+
1027
+ >>> pydvif.acoshx(curves[0])
1028
+
1029
+ :param curvelist: The Curve or list of curves
1030
+ :type curvelist: Curve or list
1031
+ """
1032
+ curves = list()
1033
+
1034
+ if isinstance(curvelist, list):
1035
+ curves.extend(curvelist)
1036
+ else:
1037
+ curves.append(curvelist)
1038
+
1039
+ for cur in curves:
1040
+ cur.x = np.arccosh(cur.x)
1041
+
1042
+
1043
+ def acos(curvelist):
1044
+ """
1045
+ Take the arccosine of y values of a Curve or list of Curves
1046
+
1047
+ >>> curves = pydvif.read('testData.txt')
1048
+
1049
+ >>> pydvif.acos(curves) OR
1050
+
1051
+ >>> pydvif.acos(curves[0])
1052
+
1053
+ :param curvelist: The Curve or list of curves
1054
+ :type curvelist: Curve or list
1055
+ """
1056
+ curves = list()
1057
+
1058
+ if isinstance(curvelist, list):
1059
+ curves.extend(curvelist)
1060
+ else:
1061
+ curves.append(curvelist)
1062
+
1063
+ for cur in curves:
1064
+ cur.y = np.arccos(cur.y)
1065
+
1066
+
1067
+ def acosx(curvelist):
1068
+ """
1069
+ Take the arccosine of x values of a Curve or list of Curves.
1070
+
1071
+ >>> curves = pydvif.read('testData.txt')
1072
+
1073
+ >>> pydvif.acosx(curves) OR
1074
+
1075
+ >>> pydvif.acosx(curves[0])
1076
+
1077
+ :param curvelist: The Curve or list of curves
1078
+ :type curvelist: Curve or list
1079
+ """
1080
+ curves = list()
1081
+
1082
+ if isinstance(curvelist, list):
1083
+ curves.extend(curvelist)
1084
+ else:
1085
+ curves.append(curvelist)
1086
+
1087
+ for cur in curves:
1088
+ cur.x = np.arccos(cur.x)
1089
+
1090
+
1091
+ def sin(curvelist):
1092
+ """
1093
+ Take the sine of y values of a single curve or multiple curves in list.
1094
+
1095
+ >>> curves = pydvif.read('testData.txt')
1096
+
1097
+ >>> pydvif.sin(curves)
1098
+
1099
+ :param curvelist: A single curve or a list of curves
1100
+ :type curvelist: curve or list
1101
+ """
1102
+ if isinstance(curvelist, list):
1103
+ for c in curvelist:
1104
+ c.y = np.sin(c.y)
1105
+ else:
1106
+ curvelist.y = np.sin(curvelist.y)
1107
+
1108
+
1109
+ def sinx(curvelist):
1110
+ """
1111
+ Take the sine of x values of a single curve or multiple curves in list.
1112
+
1113
+ >>> curves = pydvif.read('testData.txt')
1114
+
1115
+ >>> pydvif.sinx(curves)
1116
+
1117
+ :param curvelist: A single curve or a list of curves
1118
+ :type curvelist: curve or list
1119
+ """
1120
+
1121
+ if isinstance(curvelist, list):
1122
+ for c in curvelist:
1123
+ c.x = np.sin(c.x)
1124
+ else:
1125
+ curvelist.x = np.sin(curvelist.x)
1126
+
1127
+
1128
+ def sinh(curvelist):
1129
+ """
1130
+ Take the hyperbolic sine of y values of a single curve or multiple curves in list.
1131
+
1132
+ >>> curves = pydvif.read('testData.txt')
1133
+
1134
+ >>> pydvif.sinh(curves)
1135
+
1136
+ :param curvelist: A single curve or a list of curves
1137
+ :type curvelist: curve or list
1138
+ """
1139
+
1140
+ if isinstance(curvelist, list):
1141
+ for c in curvelist:
1142
+ c.y = np.sinh(c.y)
1143
+ else:
1144
+ curvelist.y = np.sinh(curvelist.y)
1145
+
1146
+
1147
+ def sinhx(curvelist):
1148
+ """
1149
+ Take the hyperbolic sine of x values of a single curve or multiple curves in list.
1150
+
1151
+ >>> curves = pydvif.read('testData.txt')
1152
+
1153
+ >>> pydvif.sinhx(curves)
1154
+
1155
+ :param curvelist: A single curve or a list of curves
1156
+ :type curvelist: curve or list
1157
+ """
1158
+
1159
+ if isinstance(curvelist, list):
1160
+ for c in curvelist:
1161
+ c.x = np.sinh(c.x)
1162
+ else:
1163
+ curvelist.x = np.sinh(curvelist.x)
1164
+
1165
+
1166
+ def asinh(curvelist):
1167
+ """
1168
+ Take the hyperbolic arcsine of y values of a single curve or curves in a list.
1169
+
1170
+ >>> curves = pydvif.read('testData.txt')
1171
+
1172
+ >>> pydvif.asinh(curves)
1173
+
1174
+ :param curvelist: A single curve or a list of curves
1175
+ :type curvelist: curve or list
1176
+ """
1177
+
1178
+ if isinstance(curvelist, list):
1179
+ for c in curvelist:
1180
+ c.y = np.asinh(c.y)
1181
+ else:
1182
+ curvelist.y = np.asinh(curvelist.y)
1183
+
1184
+
1185
+ def asinhx(curvelist):
1186
+ """
1187
+ Take the hyperbolic arcsine of x values of a single curve or curves in a list.
1188
+
1189
+ >>> curves = pydvif.read('testData.txt')
1190
+
1191
+ >>> pydvif.asinhx(curves)
1192
+
1193
+ :param curvelist: A single curve or a list of curves
1194
+ :type curvelist: curve or list
1195
+ """
1196
+
1197
+ if isinstance(curvelist, list):
1198
+ for c in curvelist:
1199
+ c.x = np.asinh(c.x)
1200
+ else:
1201
+ curvelist.x = np.asinh(curvelist.x)
1202
+
1203
+
1204
+ def asin(curvelist):
1205
+ """
1206
+ Take the arcsine of y values of a single curve or curves in a list.
1207
+
1208
+ >>> curves = pydvif.read('testData.txt')
1209
+
1210
+ >>> pydvif.asin(curves)
1211
+
1212
+ :param curvelist: A single curve or a list of curves
1213
+ :type curvelist: curve or list
1214
+ """
1215
+ if isinstance(curvelist, list):
1216
+ for c in curvelist:
1217
+ c.y = np.asin(c.y)
1218
+ else:
1219
+ curvelist.y = np.asin(curvelist.y)
1220
+
1221
+
1222
+ def asinx(curvelist):
1223
+ """
1224
+ Take the arcsine of x values of a single curve or curves in a list.
1225
+
1226
+ >>> curves = pydvif.read('testData.txt')
1227
+
1228
+ >>> pydvif.asinx(curves)
1229
+
1230
+ :param curvelist: A single curve or a list of curves
1231
+ :type curvelist: curve or list
1232
+ """
1233
+
1234
+ if isinstance(curvelist, list):
1235
+ for c in curvelist:
1236
+ c.x = np.asin(c.x)
1237
+ else:
1238
+ curvelist.x = np.asin(curvelist.x)
1239
+
1240
+
1241
+ def tan(curvelist):
1242
+ """
1243
+ Take the tangent of y values of a single curve or multiple curves in list.
1244
+
1245
+ >>> curves = pydvif.read('testData.txt')
1246
+
1247
+ >>> pydvif.tan(curves)
1248
+
1249
+ :param curvelist: A single curve or a list of curves
1250
+ :type curvelist: curve or list
1251
+ """
1252
+
1253
+ if isinstance(curvelist, list):
1254
+ for c in curvelist:
1255
+ c.y = np.tan(c.y)
1256
+ else:
1257
+ curvelist.y = np.tan(curvelist.y)
1258
+
1259
+
1260
+ def tanx(curvelist):
1261
+ """
1262
+ Take the tangent of x values of a single curve or multiple curves in list.
1263
+
1264
+ >>> curves = pydvif.read('testData.txt')
1265
+
1266
+ >>> pydvif.tanx(curves)
1267
+
1268
+ :param curvelist: A single curve or a list of curves
1269
+ :type curvelist: curve or list
1270
+ """
1271
+
1272
+ if isinstance(curvelist, list):
1273
+ for c in curvelist:
1274
+ c.x = np.tan(c.x)
1275
+ else:
1276
+ curvelist.x = np.tan(curvelist.x)
1277
+
1278
+
1279
+ def tanh(curvelist):
1280
+ """
1281
+ Take the hyperbolic tangent of y values of a single curve or multiple curves in list.
1282
+
1283
+ >>> curves = pydvif.read('testData.txt')
1284
+
1285
+ >>> pydvif.tanh(curves)
1286
+
1287
+ :param curvelist: A single curve or a list of curves
1288
+ :type curvelist: curve or list
1289
+ """
1290
+
1291
+ if isinstance(curvelist, list):
1292
+ for c in curvelist:
1293
+ c.y = np.tanh(c.y)
1294
+ else:
1295
+ curvelist.y = np.tanh(curvelist.y)
1296
+
1297
+
1298
+ def tanhx(curvelist):
1299
+ """
1300
+ Take the hyperbolic tangent of x values of a single curve or multiple curves in list.
1301
+
1302
+ >>> curves = pydvif.read('testData.txt')
1303
+
1304
+ >>> pydvif.tanhx(curves)
1305
+
1306
+ :param curvelist: A single curve or a list of curves
1307
+ :type curvelist: curve or list
1308
+ """
1309
+
1310
+ if isinstance(curvelist, list):
1311
+ for c in curvelist:
1312
+ c.x = np.tanh(c.x)
1313
+ else:
1314
+ curvelist.x = np.tanh(curvelist.x)
1315
+
1316
+
1317
+ def atan(curvelist):
1318
+ """
1319
+ Take the arctangent of y values of a single curve or curves in a list.
1320
+
1321
+ >>> curves = pydvif.read('testData.txt')
1322
+
1323
+ >>> pydvif.atan(curves)
1324
+
1325
+ :param curvelist: A single curve or a list of curves
1326
+ :type curvelist: curve or list
1327
+ """
1328
+
1329
+ if isinstance(curvelist, list):
1330
+ for c in curvelist:
1331
+ c.y = np.atan(c.y)
1332
+ else:
1333
+ curvelist.y = np.atan(curvelist.y)
1334
+
1335
+
1336
+ def atanx(curvelist):
1337
+ """
1338
+ Take the arctangent of x values of a single curve or curves in a list.
1339
+
1340
+ >>> curves = pydvif.read('testData.txt')
1341
+
1342
+ >>> pydvif.atanx(curves)
1343
+
1344
+ :param curvelist: A single curve or a list of curves
1345
+ :type curvelist: curve or list
1346
+ """
1347
+
1348
+ if isinstance(curvelist, list):
1349
+ for c in curvelist:
1350
+ c.x = np.atan(c.x)
1351
+ else:
1352
+ curvelist.x = np.atan(curvelist.x)
1353
+
1354
+
1355
+ def atanh(curvelist):
1356
+ """
1357
+ Take the hyperbolic arctangent of y values of a single curve or curves in a list.
1358
+
1359
+ >>> curves = pydvif.read('testData.txt')
1360
+
1361
+ >>> pydvif.atanh(curves)
1362
+
1363
+ :param curvelist: A single curve or a list of curves
1364
+ :type curvelist: curve or list
1365
+ """
1366
+
1367
+ if isinstance(curvelist, list):
1368
+ for c in curvelist:
1369
+ c.y = np.atanh(c.y)
1370
+ else:
1371
+ curvelist.y = np.atanh(curvelist.y)
1372
+
1373
+
1374
+ def atanhx(curvelist):
1375
+ """
1376
+ Take the hyperbolic arctangent of x values of a single curve or curves in a list.
1377
+
1378
+ >>> curves = pydvif.read('testData.txt')
1379
+
1380
+ >>> pydvif.atanhx(curves)
1381
+
1382
+ :param curvelist: A single curve or a list of curves
1383
+ :type curvelist: curve or list
1384
+ """
1385
+
1386
+ if isinstance(curvelist, list):
1387
+ for c in curvelist:
1388
+ c.x = np.atanh(c.x)
1389
+ else:
1390
+ curvelist.x = np.atanh(curvelist.x)
1391
+
1392
+
1393
+ def atan2(c1, c2, t=None):
1394
+ """
1395
+ Perform the atan2 method for a pair of curves.
1396
+
1397
+ >>> curves = pydvif.read('testData.txt')
1398
+
1399
+ >>> pydvif.atan2(curves[0], curves[1]) OR
1400
+
1401
+ >>> pydvif.atan2(curves[0], curves[1], tuple(['A', 'B']))
1402
+
1403
+ :param c1: the first curve
1404
+ :type c1: curve
1405
+ :param c2: the second curve
1406
+ :type c2: curve
1407
+ :param t: A tuple containing exactly two values to insert into the name string for the new curve
1408
+ :type t: tuple
1409
+ :return: curve -- a new curve with the results from this operation
1410
+ """
1411
+ if t is None:
1412
+ t = tuple([c1.name, c2.name])
1413
+
1414
+ c = curve.Curve('', 'atan2(%s,%s)' % t)
1415
+ c.x = np.array(c1.x)
1416
+ c.y = np.arctan2(c1.y, c2.y)
1417
+
1418
+ return c
1419
+
1420
+
1421
+ def add(curvelist):
1422
+ """
1423
+ Add one or more curves.
1424
+
1425
+ >>> curves = pydvif.read('testData.txt')
1426
+
1427
+ >>> c = pydvif.add(curves)
1428
+
1429
+ :param curvelist: The list of curves
1430
+ :type curvelist: list
1431
+ :returns: curve -- the curve containing the sum of the curves in curvelist
1432
+ """
1433
+
1434
+ numcurves = len(curvelist)
1435
+ if numcurves > 1:
1436
+ name = curvelist[0].name
1437
+ sendline = 'curvelist[' + str(0) + ']'
1438
+ for i in range(1, numcurves):
1439
+ name += ' + ' + curvelist[i].name
1440
+ sendline += '+ curvelist[' + str(i) + ']'
1441
+
1442
+ c = eval(sendline)
1443
+ c.name = name
1444
+
1445
+ if c.x is None or len(c.x) < 2:
1446
+ print('Error: curve overlap is insufficient')
1447
+ return 0
1448
+
1449
+ return c
1450
+ elif numcurves == 1:
1451
+ return curvelist[0]
1452
+ else:
1453
+ return curvelist
1454
+
1455
+
1456
+ def subtract(curvelist):
1457
+ """
1458
+ Take difference of curves.
1459
+
1460
+ >>> curves = pydvif.read('testData.txt')
1461
+
1462
+ >>> c = pydvif.subtract(curves)
1463
+
1464
+ :param curvelist: The list of curves
1465
+ :type curvelist: list
1466
+ :returns: curve -- the curve containing the difference of the curves
1467
+ """
1468
+
1469
+ numcurves = len(curvelist)
1470
+ if numcurves > 1:
1471
+ name = curvelist[0].name
1472
+ sendline = 'curvelist[' + str(0) + ']'
1473
+ for i in range(1, numcurves):
1474
+ name += ' - ' + curvelist[i].name
1475
+ sendline += '- curvelist[' + str(i) + ']'
1476
+
1477
+ c = eval(sendline)
1478
+ c.name = name
1479
+
1480
+ if c.x is None or len(c.x) < 2:
1481
+ print('Error: curve overlap is insufficient')
1482
+ return 0
1483
+
1484
+ return c
1485
+ elif numcurves == 1:
1486
+ return curvelist[0]
1487
+ else:
1488
+ return curvelist
1489
+
1490
+
1491
+ def multiply(curvelist):
1492
+ """
1493
+ Take product of curves.
1494
+
1495
+ >>> curves = pydvif.read('testData.txt')
1496
+
1497
+ >>> c = pydvif.multiply(curves)
1498
+
1499
+ :param curvelist: The list of curves
1500
+ :type curvelist: list
1501
+ :returns: Curve -- the curve containing the product of the curves
1502
+ """
1503
+ numcurves = len(curvelist)
1504
+ if numcurves > 1:
1505
+ name = __toCurveString(curvelist[0])
1506
+ sendline = 'curvelist[' + str(0) + ']'
1507
+ for i in range(1, numcurves):
1508
+ name += ' * ' + __toCurveString(curvelist[i])
1509
+ sendline += '* curvelist[' + str(i) + ']'
1510
+
1511
+ c = eval(sendline)
1512
+ c.name = name
1513
+
1514
+ if c.x is None or len(c.x) < 2:
1515
+ print('Error: curve overlap is insufficient')
1516
+ return 0
1517
+
1518
+ return c
1519
+ elif numcurves == 1:
1520
+ return curvelist[0]
1521
+ else:
1522
+ return curvelist
1523
+
1524
+
1525
+ def divide(curvelist):
1526
+ """
1527
+ Take quotient of curves.
1528
+
1529
+ >>> curves = pydvif.read('testData.txt')
1530
+
1531
+ >>> c = pydvif.divide(curves)
1532
+
1533
+ :param curvelist: The list of curves
1534
+ :type curvelist: list
1535
+ :returns: curve -- the curve containing the quotient of the curves
1536
+ """
1537
+ numcurves = len(curvelist)
1538
+ if numcurves > 1:
1539
+ name = __toCurveString(curvelist[0])
1540
+ sendline = 'curvelist[' + str(0) + ']'
1541
+ for i in range(1, numcurves):
1542
+ name += ' / ' + __toCurveString(curvelist[i])
1543
+ sendline += '/ curvelist[' + str(i) + ']'
1544
+
1545
+ c = eval(sendline)
1546
+ c.name = name
1547
+
1548
+ if c.x is None or len(c.x) < 2:
1549
+ print('Error: curve overlap is insufficient')
1550
+ return 0
1551
+
1552
+ return c
1553
+ elif numcurves == 1:
1554
+ return curvelist[0]
1555
+ else:
1556
+ return curvelist
1557
+
1558
+
1559
+ def divx(curvelist, value):
1560
+ """
1561
+ Divide x values of the curve(s) by a constant value.
1562
+
1563
+ >>> curves = pydvif.read('testData.txt')
1564
+
1565
+ >>> pydvif.divx(curves, 4)
1566
+
1567
+ :param curvelist: The curve or curvelist
1568
+ :type curvelist: Curve or list
1569
+ :param value: The divisor
1570
+ :type value: float
1571
+ """
1572
+ curves = list()
1573
+
1574
+ if isinstance(curvelist, list):
1575
+ curves.extend(curvelist)
1576
+ else:
1577
+ curves.append(curvelist)
1578
+
1579
+ for c in curves:
1580
+ if float(value) == 0:
1581
+ value = 1.e-10
1582
+ c.x /= float(value)
1583
+
1584
+
1585
+ def divy(curvelist, value):
1586
+ """
1587
+ Divide y values of the curve(s) by a constant value.
1588
+
1589
+ >>> curves = pydvif.read('testData.txt')
1590
+
1591
+ >>> pydvif.divy(curves, 4)
1592
+
1593
+ :param curvelist: The curve or curvelist
1594
+ :type curvelist: Curve or list
1595
+ :param value: The divisor
1596
+ :type value: float
1597
+ """
1598
+ curves = list()
1599
+
1600
+ if isinstance(curvelist, list):
1601
+ curves.extend(curvelist)
1602
+ else:
1603
+ curves.append(curvelist)
1604
+
1605
+ for c in curves:
1606
+ if float(value) == 0:
1607
+ value = 1.e-10
1608
+ c.y /= float(value)
1609
+
1610
+
1611
+ def dx(curvelist, value):
1612
+ """
1613
+ Shift x values of a curve or list of curves by a constant value.
1614
+
1615
+ >>> curves = pydvif.read('testData.txt')
1616
+
1617
+ >>> pydvif.dx(curves, 4) OR
1618
+
1619
+ >>> pydvif.dx(curves[0], 4)
1620
+
1621
+
1622
+ :param curvelist: A curve or curvelist
1623
+ :type curvelist: Curve or list
1624
+ :param value: The amount to shift the x values by
1625
+ :type value: float
1626
+ """
1627
+ curves = list()
1628
+
1629
+ if isinstance(curvelist, list):
1630
+ curves.extend(curvelist)
1631
+ else:
1632
+ curves.append(curvelist)
1633
+
1634
+ for c in curves:
1635
+ c.x += float(value)
1636
+
1637
+
1638
+ def dy(curvelist, value):
1639
+ """
1640
+ Shift y values of a curve or list of curves by a constant value.
1641
+
1642
+ >>> curves = pydvif.read('testData.txt')
1643
+
1644
+ >>> pydvif.dy(curves, 4) OR
1645
+
1646
+ >>> pydvif.dy(curves[0], 4)
1647
+
1648
+
1649
+ :param curvelist: A curve or curvelist
1650
+ :type curvelist: Curve or list
1651
+ :param value: The amount to shift the y values by
1652
+ :type value: float
1653
+ """
1654
+ curves = list()
1655
+
1656
+ if isinstance(curvelist, list):
1657
+ curves.extend(curvelist)
1658
+ else:
1659
+ curves.append(curvelist)
1660
+
1661
+ for c in curves:
1662
+ c.y += float(value)
1663
+
1664
+
1665
+ def mx(curvelist, value):
1666
+ """
1667
+ Scale x values of a curve or list of curves by a constant value.
1668
+
1669
+ >>> curves = pydvif.read('testData.txt')
1670
+
1671
+ >>> pydvif.mx(curves, 4) OR
1672
+
1673
+ >>> pydvif.mx(curves[0], 4)
1674
+
1675
+
1676
+ :param curvelist: A curve or curvelist
1677
+ :type curvelist: Curve or list
1678
+ :param value: The amount to scale the x values by
1679
+ :type value: float
1680
+ """
1681
+ curves = list()
1682
+
1683
+ if isinstance(curvelist, list):
1684
+ curves.extend(curvelist)
1685
+ else:
1686
+ curves.append(curvelist)
1687
+
1688
+ for c in curves:
1689
+ c.x *= float(value)
1690
+
1691
+
1692
+ def my(curvelist, value):
1693
+ """
1694
+ Scale y values of a curve or list of curves by a constant value.
1695
+
1696
+ >>> curves = pydvif.read('testData.txt')
1697
+
1698
+ >>> pydvif.my(curves, 4) OR
1699
+
1700
+ >>> pydvif.my(curves[0], 4)
1701
+
1702
+
1703
+ :param curvelist: A curve or curvelist
1704
+ :type curvelist: Curve or list
1705
+ :param value: The amount to scale the y values by
1706
+ :type value: float
1707
+ """
1708
+ curves = list()
1709
+
1710
+ if isinstance(curvelist, list):
1711
+ curves.extend(curvelist)
1712
+ else:
1713
+ curves.append(curvelist)
1714
+
1715
+ for c in curves:
1716
+ c.y *= float(value)
1717
+
1718
+
1719
+ def l1(c1, c2, xmin=None, xmax=None):
1720
+ """
1721
+ Make a new curve that is the L1 norm of curve c1 and curve c2.
1722
+ The L1-norm is the integral(\|c1 - c2\|) over the interval [xmin, xmax]. # noqa w605
1723
+
1724
+ >>> c = pydvif.l1(curve1, curve2)
1725
+
1726
+ >>> c2 = pydvif.l1(curve1, curve2, 1.1, 10.9)
1727
+
1728
+ :param c1: The first curve
1729
+ :type c1: Curve
1730
+ :param c2: The second curve
1731
+ :type c2: Curve
1732
+ :param xmin: the minimum x value to perform the L1 norm
1733
+ :type xmin: float
1734
+ :param xmax: the maximum x value to perform the L1 norm
1735
+ :type xmax: float
1736
+ :returns Curve: A new curve that is the L1 norm of c1 and c2
1737
+ """
1738
+ c = c1 - c2
1739
+ c.y = np.abs(c.y)
1740
+
1741
+ if xmin is not None and xmax is not None:
1742
+ if xmax <= xmin:
1743
+ raise RuntimeError("xmin > xmax or xmin == xmax in l1")
1744
+ else:
1745
+ xmin = np.min(c.x)
1746
+ xmax = np.max(c.x)
1747
+
1748
+ d = integrate(c, xmin, xmax)
1749
+ d[0].name = "L1 of " + __toCurveString(c1) + " and " + __toCurveString(c2)
1750
+
1751
+ return d[0]
1752
+
1753
+
1754
+ def l2(c1, c2, xmin=None, xmax=None):
1755
+ """
1756
+ Make a new curve that is the L2 norm of curve c1 and curve c2.
1757
+ The L2-norm is (integral((c1 - c2)**2)**(1/2) over the interval [xmin, xmax].
1758
+
1759
+ >>> c = pydvif.l2(curve1, curve2)
1760
+
1761
+ >>> c2 = pydvif.l2(curve1, curve2, 3.1, 30.9)
1762
+
1763
+ :param c1: The first curve
1764
+ :type c1: Curve
1765
+ :param c2: The second curve
1766
+ :type c2: Curve
1767
+ :param xmin: the minimum x value to perform the L2 norm
1768
+ :type xmin: float
1769
+ :param xmax: the maximum x value to perform the L2 norm
1770
+ :type xmax: float
1771
+ :returns Curve: A new curve that is the L2 norm of c1 and c2
1772
+ """
1773
+ c = c1 - c2
1774
+ c.y = np.abs(c.y)
1775
+ c = c**2.0
1776
+
1777
+ if xmin is not None and xmax is not None:
1778
+ if xmax <= xmin:
1779
+ raise RuntimeError("xmin > xmax or xmin == xmax in l2")
1780
+ else:
1781
+ xmin = np.min(c.x)
1782
+ xmax = np.max(c.x)
1783
+
1784
+ d = integrate(c, xmin, xmax)
1785
+ d[0] = d[0]**(0.5)
1786
+ d[0].name = "L2 of " + __toCurveString(c1) + " and " + __toCurveString(c2)
1787
+
1788
+ return d[0]
1789
+
1790
+
1791
+ def norm(c1, c2, p, xmin=None, xmax=None):
1792
+ """
1793
+ Make a new curve that is the p-norm of curve c1 and curve c2.
1794
+
1795
+ >>> curves = pydvif.read('testData.txt')
1796
+
1797
+ >>> c = pydvif.norm(curves[0], curves[1], 'inf')
1798
+
1799
+ >>> curves.append(c)
1800
+
1801
+ :param c1: The first curve
1802
+ :type c1: Curve
1803
+ :param c2: The second curve
1804
+ :type c2: Curve
1805
+ :param p: the order (e.g., 'inf', '3', '5')
1806
+ :type p: str
1807
+ :param xmin: the minimum x value to perform the p-norm
1808
+ :type xmin: float
1809
+ :param xmax: the maximum x value to perform the p-norm
1810
+ :type xmax: float
1811
+ :returns Curve: A new curve that is the p-norm of c1 and c2
1812
+ """
1813
+ c = c1 - c2
1814
+ c.y = np.abs(c.y)
1815
+
1816
+ if p.lower() != "inf":
1817
+ N = int(p)
1818
+ c = c**N
1819
+
1820
+ if xmin is not None and xmax is not None:
1821
+ if xmax <= xmin:
1822
+ raise RuntimeError("xmin > xmax or xmin == xmax in norm")
1823
+ else:
1824
+ xmin = np.min(c.x)
1825
+ xmax = np.max(c.x)
1826
+
1827
+ if p.lower() == "inf":
1828
+ Linf = 0.0
1829
+ for xi, yi in zip(c.x, c.y):
1830
+ if xmin <= xi <= xmax:
1831
+ Linf = max(Linf, yi)
1832
+ d = c
1833
+ d.y = np.array([Linf] * c.y.shape[0])
1834
+ d.name = "Linf of " + __toCurveString(c1) + " and " + __toCurveString(c2)
1835
+
1836
+ return d
1837
+ else:
1838
+ d = integrate(c, xmin, xmax)
1839
+ d[0] = d[0]**(1.0 / N)
1840
+ d[0].name = "L%d of " % N + __toCurveString(c1) + " and " + __toCurveString(c2)
1841
+
1842
+ return d[0]
1843
+
1844
+
1845
+ def abs(curvelist):
1846
+ """
1847
+ Take the absolute value of the y values of the Curve or list of curves.
1848
+
1849
+ >>> curves = pydvif.read('testData.txt')
1850
+
1851
+ >>> pydvif.abs(curves) OR
1852
+
1853
+ >>> pydvif.abs(curves[0])
1854
+
1855
+ :param curvelist: the Curve or list of curves
1856
+ :type curvelist: Curve or list
1857
+ """
1858
+ curves = list()
1859
+
1860
+ if isinstance(curvelist, list):
1861
+ curves.extend(curvelist)
1862
+ else:
1863
+ curves.append(curvelist)
1864
+
1865
+ for cur in curves:
1866
+ cur.y = np.abs(cur.y)
1867
+
1868
+
1869
+ def absx(curvelist):
1870
+ """
1871
+ Take the absolute value of the x values of the Curve or list of curves.
1872
+
1873
+ >>> curves = pydvif.read('testData.txt')
1874
+
1875
+ >>> pydvif.absx(curves) OR
1876
+
1877
+ >>> pydvif.absx(curves[0])
1878
+
1879
+ :param curvelist: the Curve or list of curves
1880
+ :type curvelist: Curve or list
1881
+ """
1882
+ curves = list()
1883
+
1884
+ if isinstance(curvelist, list):
1885
+ curves.extend(curvelist)
1886
+ else:
1887
+ curves.append(curvelist)
1888
+
1889
+ for cur in curves:
1890
+ cur.x = np.abs(cur.x)
1891
+
1892
+
1893
+ def log(curvelist, keep=True):
1894
+ """
1895
+ Take the natural logarithm of y values of the Curve or list of curves.
1896
+
1897
+ >>> curves = pydvif.read('testData.txt')
1898
+
1899
+ >>> pydvif.log(curves) OR
1900
+
1901
+ >>> pydvif.log(curves[0])
1902
+
1903
+ :param curvelist: the Curve or list of curves
1904
+ :type curvelist: Curve or list
1905
+ :param keep: flag to determine whether or not to discard zero or negative y-values before taking the log.
1906
+ keep is True by default.
1907
+ :type keep: optional, boolean
1908
+ """
1909
+ curves = list()
1910
+
1911
+ if isinstance(curvelist, list):
1912
+ curves.extend(curvelist)
1913
+ else:
1914
+ curves.append(curvelist)
1915
+
1916
+ for c in curves:
1917
+ if not keep:
1918
+ skiplist = np.where(c.y <= 0)[0]
1919
+ if len(skiplist) > 0:
1920
+ c.y = np.delete(c.y, skiplist)
1921
+ c.x = np.delete(c.x, skiplist)
1922
+
1923
+ c.y = np.log(c.y)
1924
+ if c.name[:3] == 'exp':
1925
+ c.name = c.name[4:-1] # Pop off the exp( from the front and the ) from the back
1926
+ else:
1927
+ c.name = 'log(' + c.name + ')'
1928
+
1929
+
1930
+ def logx(curvelist, keep=True):
1931
+ """
1932
+ Take the natural logarithm of x values of the Curve or list of curves.
1933
+
1934
+ >>> curves = pydvif.read('testData.txt')
1935
+
1936
+ >>> pydvif.logx(curves) OR
1937
+
1938
+ >>> pydvif.logx(curves[0])
1939
+
1940
+ :param curvelist: the Curve or list of curves
1941
+ :type curvelist: Curve or list
1942
+ :param keep: flag to determine whether or not to discard zero or negative x-values before taking the log.
1943
+ keep is True by default.
1944
+ :type keep: optional, boolean
1945
+ """
1946
+ curves = list()
1947
+
1948
+ if isinstance(curvelist, list):
1949
+ curves.extend(curvelist)
1950
+ else:
1951
+ curves.append(curvelist)
1952
+
1953
+ for c in curves:
1954
+ if not keep:
1955
+ skiplist = np.where(c.x <= 0)[0]
1956
+ if len(skiplist) > 0:
1957
+ c.y = np.delete(c.y, skiplist)
1958
+ c.x = np.delete(c.x, skiplist)
1959
+
1960
+ c.x = np.log(c.x)
1961
+ if c.name[:4] == 'expx':
1962
+ c.name = c.name[5:-1] # Pop off the expx( from the front and the ) from the back
1963
+ else:
1964
+ c.name = 'logx(' + c.name + ')'
1965
+
1966
+
1967
+ def log10(curvelist, keep=True):
1968
+ """
1969
+ Take the base 10 logarithm of y values of a Curve or list of curves.
1970
+
1971
+ >>> curves = pydvif.read('testData.txt')
1972
+
1973
+ >>> pydvif.log10(curves) OR
1974
+
1975
+ >>> pydvif.log10(curves[0])
1976
+
1977
+ :param curvelist: the Curve or list of curves
1978
+ :type curvelist: Curve or list
1979
+ :param keep: flag to determine whether or not to discard zero
1980
+ or negative y-values before taking the base 10 logarithm.
1981
+ keep is True by default.
1982
+ :type keep: optional, boolean
1983
+ """
1984
+ curves = list()
1985
+
1986
+ if isinstance(curvelist, list):
1987
+ curves.extend(curvelist)
1988
+ else:
1989
+ curves.append(curvelist)
1990
+
1991
+ for c in curves:
1992
+ if not keep:
1993
+ skiplist = np.where(c.y <= 0)[0]
1994
+ if len(skiplist) > 0:
1995
+ c.y = np.delete(c.y, skiplist)
1996
+ c.x = np.delete(c.x, skiplist)
1997
+
1998
+ c.y = np.log10(c.y)
1999
+ c.name = 'log10(' + c.name + ')'
2000
+
2001
+
2002
+ def log10x(curvelist, keep=True):
2003
+ """
2004
+ Take the base 10 logarithm of x values of a Curve or list of curves.
2005
+
2006
+ >>> curves = pydvif.read('testData.txt')
2007
+
2008
+ >>> pydvif.log10x(curves) OR
2009
+
2010
+ >>> pydvif.log10x(curves[0])
2011
+
2012
+ :param curvelist: the Curve or list of curves
2013
+ :type curvelist: Curve or list
2014
+ :param keep: flag to determine whether or not to discard zero
2015
+ or negative y-values before taking the base 10 logarithm.
2016
+ keep is True by default.
2017
+ :type keep: optional, boolean
2018
+ """
2019
+ curves = list()
2020
+
2021
+ if isinstance(curvelist, list):
2022
+ curves.extend(curvelist)
2023
+ else:
2024
+ curves.append(curvelist)
2025
+
2026
+ for c in curves:
2027
+ if not keep:
2028
+ skiplist = np.where(c.x <= 0)[0]
2029
+ if len(skiplist) > 0:
2030
+ c.y = np.delete(c.y, skiplist)
2031
+ c.x = np.delete(c.x, skiplist)
2032
+
2033
+ c.x = np.log10(c.x)
2034
+ c.name = 'log10x(' + c.name + ')'
2035
+
2036
+
2037
+ def exp(curvelist):
2038
+ """
2039
+ Exponentiate y values of the Curve or list of curves (e**y).
2040
+
2041
+ >>> curves = pydvif.read('testData.txt')
2042
+
2043
+ >>> pydvif.exp(curves) OR
2044
+
2045
+ >>> pydvif.exp(curves[0])
2046
+
2047
+ :param curvelist: the Curve or list of curves
2048
+ :type curvelist: Curve or list
2049
+ """
2050
+ curves = list()
2051
+
2052
+ if isinstance(curvelist, list):
2053
+ curves.extend(curvelist)
2054
+ else:
2055
+ curves.append(curvelist)
2056
+
2057
+ for cur in curves:
2058
+ cur.y = np.exp(cur.y)
2059
+
2060
+
2061
+ def expx(curvelist):
2062
+ """
2063
+ Exponentiate x values of the Curve or list of curves (e**x).
2064
+
2065
+ >>> curves = pydvif.read('testData.txt')
2066
+
2067
+ >>> pydvif.expx(curves) OR
2068
+
2069
+ >>> pydvif.expx(curves[0])
2070
+
2071
+ :param curvelist: the Curve or list of curves
2072
+ :type curvelist: Curve or list
2073
+ """
2074
+ curves = list()
2075
+
2076
+ if isinstance(curvelist, list):
2077
+ curves.extend(curvelist)
2078
+ else:
2079
+ curves.append(curvelist)
2080
+
2081
+ for cur in curves:
2082
+ cur.x = np.exp(cur.x)
2083
+
2084
+
2085
+ def powa(curvelist, a):
2086
+ """
2087
+ Raise a fixed value, a, to the power of the y values of the Curve or list of curves. y = a^y
2088
+
2089
+ >>> curves = pydvif.read('testData.txt')
2090
+
2091
+ >>> pydvif.powa(curves, 2) OR
2092
+
2093
+ >>> pydvif.powa(curves[0], 2)
2094
+
2095
+ :param curvelist: the Curve or list of curves
2096
+ :type curvelist: Curve or list
2097
+ :param a: the fixed value
2098
+ :type a: float
2099
+ """
2100
+ curves = list()
2101
+
2102
+ if isinstance(curvelist, list):
2103
+ curves.extend(curvelist)
2104
+ else:
2105
+ curves.append(curvelist)
2106
+
2107
+ for cur in curves:
2108
+ cur.y = np.power(float(a), cur.y)
2109
+
2110
+
2111
+ def powax(curvelist, a):
2112
+ """
2113
+ Raise a fixed value, a, to the power of the x values of the Curve or curves. x = a^x
2114
+
2115
+ >>> curves = pydvif.read('testData.txt')
2116
+
2117
+ >>> pydvif.powax(curves, 4.2) OR
2118
+
2119
+ >>> pydvif.powax(curves[0], 4.2)
2120
+
2121
+ :param curvelist: the Curve or list of curves
2122
+ :type curvelist: Curve or list
2123
+ :param a: the fixed value
2124
+ :type a: float
2125
+ """
2126
+ curves = list()
2127
+
2128
+ if isinstance(curvelist, list):
2129
+ curves.extend(curvelist)
2130
+ else:
2131
+ curves.append(curvelist)
2132
+
2133
+ for cur in curves:
2134
+ cur.x = np.power(float(a), cur.x)
2135
+
2136
+
2137
+ def powr(curvelist, a):
2138
+ """
2139
+ Raise a the y values of a curve or list of curves to a fixed power, y = y^a.
2140
+
2141
+ >>> curves = pydvif.read('testData.txt')
2142
+
2143
+ >>> pydvif.powr(curves, 4.2) OR
2144
+
2145
+ >>> pydvif.powr(curves[0], 4.2)
2146
+
2147
+ :param curvelist: the curve or list of curves
2148
+ :type curvelist: curve or list
2149
+ :param a: the fixed value
2150
+ :type a: float
2151
+ """
2152
+ if isinstance(curvelist, list):
2153
+ for c in curvelist:
2154
+ c.y = np.power(c.y, float(a))
2155
+ else:
2156
+ curvelist.y = np.power(curvelist.y, float(a))
2157
+
2158
+
2159
+ def powrx(curvelist, a):
2160
+ """
2161
+ Raise a the x values of a curve or list of curves to a fixed power, x = x^a.
2162
+
2163
+ >>> curves = pydvif.read('testData.txt')
2164
+
2165
+ >>> pydvif.powrx(curves, 4.2) OR
2166
+
2167
+ >>> pydvif.powrx(curves[0], 4.2)
2168
+
2169
+ :param curvelist: the curve or list of curves
2170
+ :type curvelist: curve or list
2171
+ :param a: the fixed value
2172
+ :type a: float
2173
+ """
2174
+
2175
+ if isinstance(curvelist, list):
2176
+ for c in curvelist:
2177
+ c.x = np.power(c.x, float(a))
2178
+ else:
2179
+ curvelist.x = np.power(curvelist.x, float(a))
2180
+
2181
+
2182
+ def sqr(curvelist):
2183
+ """
2184
+ Take the square of the y values in a curve or list of curves.
2185
+
2186
+ :param curvelist: the curve or list of curves
2187
+ :type curvelist: curve or list
2188
+ """
2189
+
2190
+ if isinstance(curvelist, list):
2191
+ for c in curvelist:
2192
+ c.y = np.square(c.y)
2193
+ else:
2194
+ curvelist.y = np.square(curvelist.y)
2195
+
2196
+
2197
+ def sqrx(curvelist):
2198
+ """
2199
+ Take the square of the x values in a curve or list of curves.
2200
+
2201
+ :param curvelist: the curve or list of curves
2202
+ :type curvelist: curve or list
2203
+ """
2204
+
2205
+ if isinstance(curvelist, list):
2206
+ for c in curvelist:
2207
+ c.x = np.square(c.x)
2208
+ else:
2209
+ curvelist.x = np.square(curvelist.x)
2210
+
2211
+
2212
+ def sqrt(curvelist):
2213
+ """
2214
+ Take the square root of the y values in a curve or list of curves.
2215
+
2216
+ :param curvelist: the curve or list of curves
2217
+ :type curvelist: curve or list
2218
+ """
2219
+
2220
+ if isinstance(curvelist, list):
2221
+ for c in curvelist:
2222
+ c.y = np.sqrt(c.y)
2223
+ else:
2224
+ curvelist.y = np.sqrt(curvelist.y)
2225
+
2226
+
2227
+ def sqrtx(curvelist):
2228
+ """
2229
+ Take the square root of the x values in a curve or list of curves.
2230
+
2231
+ :param curvelist: the curve or list of curves
2232
+ :type curvelist: curve or list
2233
+ """
2234
+
2235
+ if isinstance(curvelist, list):
2236
+ for c in curvelist:
2237
+ c.x = np.sqrt(c.x)
2238
+ else:
2239
+ curvelist.x = np.sqrt(curvelist.x)
2240
+
2241
+
2242
+ def xmax(curvelist, limit):
2243
+ """
2244
+ Filter out points in the curve or list of curves whose x values are greater than limit.
2245
+
2246
+ :param curvelist: The curve or list of curves
2247
+ :type curvelist: curve or list
2248
+ :param limit: The maximum value
2249
+ :type limit: float
2250
+ """
2251
+
2252
+ curves = list()
2253
+
2254
+ if isinstance(curvelist, list):
2255
+ curves = curvelist
2256
+ else:
2257
+ curves.append(curvelist)
2258
+
2259
+ for c in curves:
2260
+ nx = []
2261
+ ny = []
2262
+
2263
+ for i in range(len(c.x)):
2264
+ if c.x[i] <= float(limit):
2265
+ nx.append(c.x[i])
2266
+ ny.append(c.y[i])
2267
+
2268
+ c.x = np.array(nx)
2269
+ c.y = np.array(ny)
2270
+
2271
+
2272
+ def xmin(curvelist, min):
2273
+ """
2274
+ Filter out points in the curve or list of curves whose x values are less than min.
2275
+
2276
+ :param curvelist: The curve or list of curves
2277
+ :type curvelist: curve or list
2278
+ :param min: The minimum value
2279
+ :type min: float
2280
+ """
2281
+
2282
+ curves = list()
2283
+
2284
+ if isinstance(curvelist, list):
2285
+ curves = curvelist
2286
+ else:
2287
+ curves.append(curvelist)
2288
+
2289
+ for c in curves:
2290
+ nx = []
2291
+ ny = []
2292
+
2293
+ for i in range(len(c.x)):
2294
+ if c.x[i] >= float(min):
2295
+ nx.append(c.x[i])
2296
+ ny.append(c.y[i])
2297
+
2298
+ c.x = np.array(nx)
2299
+ c.y = np.array(ny)
2300
+
2301
+
2302
+ def xminmax(curvelist, min, max):
2303
+ """
2304
+ Filter out points in the curve or list of curves whose x values are
2305
+ less than min or greater than max.
2306
+
2307
+ :param curvelist: The curve or list of curves
2308
+ :type curvelist: curve or list
2309
+ :param min: The minimum value
2310
+ :type min: float
2311
+ :param max: The maximum value
2312
+ :type max: float
2313
+ """
2314
+ curves = list()
2315
+
2316
+ if isinstance(curvelist, list):
2317
+ curves = curvelist
2318
+ else:
2319
+ curves.append(curvelist)
2320
+
2321
+ for c in curves:
2322
+ nx = []
2323
+ ny = []
2324
+
2325
+ for i in range(len(c.x)):
2326
+ if float(min) <= c.x[i] <= float(max):
2327
+ nx.append(c.x[i])
2328
+ ny.append(c.y[i])
2329
+
2330
+ c.x = np.array(nx)
2331
+ c.y = np.array(ny)
2332
+
2333
+
2334
+ def ymax(curvelist, max):
2335
+ """
2336
+ Filter out points in the curve or list of curves whose y values are greater than limit.
2337
+
2338
+ :param curvelist: The curve or list of curves
2339
+ :type curvelist: curve or list
2340
+ :param max: The maximum value
2341
+ :type max: float
2342
+ """
2343
+
2344
+ curves = list()
2345
+
2346
+ if isinstance(curvelist, list):
2347
+ curves = curvelist
2348
+ else:
2349
+ curves.append(curvelist)
2350
+
2351
+ for c in curves:
2352
+ nx = []
2353
+ ny = []
2354
+
2355
+ for i in range(len(c.y)):
2356
+ if c.y[i] <= float(max):
2357
+ nx.append(c.x[i])
2358
+ ny.append(c.y[i])
2359
+
2360
+ c.x = np.array(nx)
2361
+ c.y = np.array(ny)
2362
+
2363
+
2364
+ def ymin(curvelist, min):
2365
+ """
2366
+ Filter out points in the curve or list of curves whose y values are less than min.
2367
+
2368
+ :param curvelist: The curve or list of curves
2369
+ :type curvelist: curve or list
2370
+ :param min: The minimum value
2371
+ :type min: float
2372
+ """
2373
+
2374
+ curves = list()
2375
+
2376
+ if isinstance(curvelist, list):
2377
+ curves = curvelist
2378
+ else:
2379
+ curves.append(curvelist)
2380
+
2381
+ for c in curves:
2382
+ nx = []
2383
+ ny = []
2384
+
2385
+ for i in range(len(c.y)):
2386
+ if c.y[i] >= float(min):
2387
+ nx.append(c.x[i])
2388
+ ny.append(c.y[i])
2389
+
2390
+ c.x = np.array(nx)
2391
+ c.y = np.array(ny)
2392
+
2393
+
2394
+ def yminmax(curvelist, min, max):
2395
+ """
2396
+ Filter out points in the curve or list of curves whose y values are
2397
+ less than min or greater than max.
2398
+
2399
+ :param curvelist: The curve or list of curves
2400
+ :type curvelist: curve or list
2401
+ :param min: The minimum value
2402
+ :type min: float
2403
+ :param max: The maximum value
2404
+ :type max: float
2405
+ """
2406
+ curves = list()
2407
+
2408
+ if isinstance(curvelist, list):
2409
+ curves.extend(curvelist)
2410
+ else:
2411
+ curves.append(curvelist)
2412
+
2413
+ for c in curves:
2414
+ nx = []
2415
+ ny = []
2416
+
2417
+ for i in range(len(c.y)):
2418
+ if float(min) <= c.y[i] <= float(max):
2419
+ nx.append(c.x[i])
2420
+ ny.append(c.y[i])
2421
+
2422
+ c.x = np.array(nx)
2423
+ c.y = np.array(ny)
2424
+
2425
+
2426
+ def yn(curvelist, n):
2427
+ """
2428
+ Take the Bessel function of the second kind of order n for the y values of
2429
+ curves in curvelist.
2430
+
2431
+ :param curvelist: The curve or list of curves
2432
+ :type curvelist: curve or list
2433
+ :param n: The order
2434
+ :type n: int
2435
+ """
2436
+ # scipy.special.errprint(1)
2437
+ curves = list()
2438
+
2439
+ if isinstance(curvelist, list):
2440
+ curves.extend(curvelist)
2441
+ else:
2442
+ curves.append(curvelist)
2443
+
2444
+ for c in curves:
2445
+ c.y = scipy.special.yn(int(n), c.y)
2446
+
2447
+
2448
+ def ynx(curvelist, n):
2449
+ """
2450
+ Take the Bessel function of the second kind of order n for the x values of
2451
+ curves in curvelist.
2452
+
2453
+ :param curvelist: The curve or list of curves
2454
+ :type curvelist: curve or list
2455
+ :param n: The order
2456
+ :type n: int
2457
+ """
2458
+ # scipy.special.errprint(1)
2459
+ curves = list()
2460
+
2461
+ if isinstance(curvelist, list):
2462
+ curves.extend(curvelist)
2463
+ else:
2464
+ curves.append(curvelist)
2465
+
2466
+ for c in curves:
2467
+ c.x = scipy.special.yn(int(n), c.x)
2468
+
2469
+
2470
+ def y0(curvelist):
2471
+ """
2472
+ Take the Bessel function of the second kind of the zeroth order for the y values of
2473
+ curves in curvelist.
2474
+
2475
+ :param curvelist: The curve or list of curves
2476
+ :type curvelist: curve or list
2477
+ """
2478
+ # scipy.special.errprint(1)
2479
+ curves = list()
2480
+
2481
+ if isinstance(curvelist, list):
2482
+ curves.extend(curvelist)
2483
+ else:
2484
+ curves.append(curvelist)
2485
+
2486
+ for c in curves:
2487
+ c.y = scipy.special.y0(c.y)
2488
+
2489
+
2490
+ def y0x(curvelist):
2491
+ """
2492
+ Take the Bessel function of the second kind of the zeroth order for the x values of
2493
+ curves in curvelist.
2494
+
2495
+ :param curvelist: The curve or list of curves
2496
+ :type curvelist: curve or list
2497
+ """
2498
+ # scipy.special.errprint(1)
2499
+ curves = list()
2500
+
2501
+ if isinstance(curvelist, list):
2502
+ curves.extend(curvelist)
2503
+ else:
2504
+ curves.append(curvelist)
2505
+
2506
+ for c in curves:
2507
+ c.x = scipy.special.y0(c.x)
2508
+
2509
+
2510
+ def y1(curvelist):
2511
+ """
2512
+ Take the Bessel function of the second kind of the first order for the y values of
2513
+ curves in curvelist.
2514
+
2515
+ :param curvelist: The curve or list of curves
2516
+ :type curvelist: curve or list
2517
+ """
2518
+ # scipy.special.errprint(1)
2519
+ curves = list()
2520
+
2521
+ if isinstance(curvelist, list):
2522
+ curves.extend(curvelist)
2523
+ else:
2524
+ curves.append(curvelist)
2525
+
2526
+ for c in curves:
2527
+ c.y = scipy.special.y1(c.y)
2528
+
2529
+
2530
+ def y1x(curvelist):
2531
+ """
2532
+ Take the Bessel function of the second kind of the first order for the x values of
2533
+ curves in curvelist.
2534
+
2535
+ :param curvelist: The curve or list of curves
2536
+ :type curvelist: curve or list
2537
+ """
2538
+ # scipy.special.errprint(1)
2539
+ curves = list()
2540
+
2541
+ if isinstance(curvelist, list):
2542
+ curves.extend(curvelist)
2543
+ else:
2544
+ curves.append(curvelist)
2545
+
2546
+ for c in curves:
2547
+ c.x = scipy.special.y1(c.x)
2548
+
2549
+
2550
+ def jn(curvelist, n):
2551
+ """
2552
+ Take the Bessel function of the first kind of the nth order for the y values of
2553
+ curves in curvelist.
2554
+
2555
+ :param curvelist: The curve or list of curves
2556
+ :type curvelist: curve or list
2557
+ :param n: The order
2558
+ :type n: float
2559
+ """
2560
+ # scipy.special.errprint(1)
2561
+ curves = list()
2562
+
2563
+ if isinstance(curvelist, list):
2564
+ curves.extend(curvelist)
2565
+ else:
2566
+ curves.append(curvelist)
2567
+
2568
+ for c in curves:
2569
+ c.y = scipy.special.jn(float(n), c.y)
2570
+
2571
+
2572
+ def jnx(curvelist, n):
2573
+ """
2574
+ Take the Bessel function of the first kind of the nth order for the x values of
2575
+ curves in curvelist.
2576
+
2577
+ :param curvelist: The curve or list of curves
2578
+ :type curvelist: curve or list
2579
+ :param n: The order
2580
+ :type n: float
2581
+ """
2582
+ # scipy.special.errprint(1)
2583
+ curves = list()
2584
+
2585
+ if isinstance(curvelist, list):
2586
+ curves.extend(curvelist)
2587
+ else:
2588
+ curves.append(curvelist)
2589
+
2590
+ for c in curves:
2591
+ c.x = scipy.special.jn(int(n), c.x)
2592
+
2593
+
2594
+ def j0(curvelist):
2595
+ """
2596
+ Take the Bessel function of the first kind of the zeroth order for the y values of
2597
+ curves in curvelist.
2598
+
2599
+ :param curvelist: The curve or list of curves
2600
+ :type curvelist: curve or list
2601
+ """
2602
+ # scipy.special.errprint(1)
2603
+ curves = list()
2604
+
2605
+ if isinstance(curvelist, list):
2606
+ curves.extend(curvelist)
2607
+ else:
2608
+ curves.append(curvelist)
2609
+
2610
+ for c in curves:
2611
+ c.y = scipy.special.j0(c.y)
2612
+
2613
+
2614
+ def j0x(curvelist):
2615
+ """
2616
+ Take the Bessel function of the first kind of the zeroth order for the x values of
2617
+ curves in curvelist.
2618
+
2619
+ :param curvelist: The curve or list of curves
2620
+ :type curvelist: curve or list
2621
+ """
2622
+ # scipy.special.errprint(1)
2623
+ curves = list()
2624
+
2625
+ if isinstance(curvelist, list):
2626
+ curves.extend(curvelist)
2627
+ else:
2628
+ curves.append(curvelist)
2629
+
2630
+ for c in curves:
2631
+ c.x = scipy.special.j0(c.x)
2632
+
2633
+
2634
+ def j1(curvelist):
2635
+ """
2636
+ Take the Bessel function of the first kind of the first order for the y values of
2637
+ curves in curvelist.
2638
+
2639
+ :param curvelist: The curve or list of curves
2640
+ :type curvelist: curve or list
2641
+ """
2642
+ # scipy.special.errprint(1)
2643
+ curves = list()
2644
+
2645
+ if isinstance(curvelist, list):
2646
+ curves.extend(curvelist)
2647
+ else:
2648
+ curves.append(curvelist)
2649
+
2650
+ for c in curves:
2651
+ c.y = scipy.special.j1(c.y)
2652
+
2653
+
2654
+ def j1x(curvelist):
2655
+ """
2656
+ Take the Bessel function of the first kind of the first order for the x values of
2657
+ curves in curvelist.
2658
+
2659
+ :param curvelist: The curve or list of curves
2660
+ :type curvelist: curve or list
2661
+ """
2662
+ # scipy.special.errprint(1)
2663
+ curves = list()
2664
+
2665
+ if isinstance(curvelist, list):
2666
+ curves.extend(curvelist)
2667
+ else:
2668
+ curves.append(curvelist)
2669
+
2670
+ for c in curves:
2671
+ c.x = scipy.special.j1(c.x)
2672
+
2673
+
2674
+ def recip(curvelist):
2675
+ """
2676
+ Take the reciprocal of the y values of the curve or list of curves.
2677
+
2678
+ >>> curves = pydvif.read('testData.txt')
2679
+
2680
+ >>> pydvif.recip(curves[1])
2681
+
2682
+ >>> pydvif.create_plot(curves, legend=True, stylename='ggplot')
2683
+
2684
+ :param curvelist: The curve or list of curves
2685
+ :type curvelist: Curve or list
2686
+ """
2687
+ curves = list()
2688
+
2689
+ if isinstance(curvelist, list):
2690
+ curves.extend(curvelist)
2691
+ else:
2692
+ curves.append(curvelist)
2693
+
2694
+ for c in curves:
2695
+ c.y = np.reciprocal(c.y)
2696
+
2697
+
2698
+ def recipx(curvelist):
2699
+ """
2700
+ Take the reciprocal of the x values of the curve or list of curves.
2701
+
2702
+ >>> curves = pydvif.read('testData.txt')
2703
+
2704
+ >>> pydvif.dx(curves, 2)
2705
+
2706
+ >>> pydvif.recipx(curves)
2707
+
2708
+ >>> pydvif.create_plot(curves, legend=True, stylename='ggplot')
2709
+
2710
+ :param curvelist: The curve or list of curves
2711
+ :type curvelist: Curve or list
2712
+ :return:
2713
+ """
2714
+ curves = list()
2715
+
2716
+ if isinstance(curvelist, list):
2717
+ curves.extend(curvelist)
2718
+ else:
2719
+ curves.append(curvelist)
2720
+
2721
+ for c in curves:
2722
+ c.x = np.reciprocal(c.x)
2723
+
2724
+
2725
+ def integrate(curvelist, low=None, high=None):
2726
+ """
2727
+ Take the integral of the curve or curves in curvelist.
2728
+
2729
+ :param curvelist: A curve or list of curves
2730
+ :type curvelist: curve or list
2731
+ :param low: The lower limit
2732
+ :type low: float
2733
+ :param high: The maximum limit
2734
+ :type high: float
2735
+ :return: list -- the list of integrated curves
2736
+ """
2737
+ curves = list()
2738
+ ncurves = list()
2739
+
2740
+ if isinstance(curvelist, list):
2741
+ curves.extend(curvelist)
2742
+ else:
2743
+ curves.append(curvelist)
2744
+
2745
+ for c in curves:
2746
+ nc = c.copy()
2747
+ nc.plotname = ''
2748
+ nc.color = ''
2749
+
2750
+ if low is None:
2751
+ nc.name = 'Integrate ' + c.plotname
2752
+ else:
2753
+ nc.name = 'Integrate %s [%.1f,%.1f]' % (c.plotname, low, high)
2754
+
2755
+ if low is None:
2756
+ low = min(nc.x)
2757
+
2758
+ if high is None:
2759
+ high = max(nc.x)
2760
+
2761
+ r = __get_sub_range(nc.x, low, high)
2762
+ nc.x = nc.x[r[0]:r[1] + 1]
2763
+ nc.y = nc.y[r[0]:r[1] + 1]
2764
+ nc.y = np.array(scipy.integrate.cumtrapz(nc.y, nc.x, initial=0.0))
2765
+
2766
+ ncurves.append(nc)
2767
+
2768
+ return ncurves
2769
+
2770
+
2771
+ def alpha(ac, ig, res, npts=-1):
2772
+ if npts == -1:
2773
+ npts = len(ac.y)
2774
+
2775
+ ai = curve.Curve.__mul__(ac, ig)
2776
+ num = convolveb(ai, res, npts)
2777
+ denom = convolveb(ig, res, npts)
2778
+ alpha_measured = curve.Curve.__div__(num, denom)
2779
+
2780
+ alpha_measured.name = "Measured alpha"
2781
+ alpha_measured.plotname = ''
2782
+ return alpha_measured
2783
+
2784
+
2785
+ def gaussian(amp, wid, center, num=100, nsd=3):
2786
+ """
2787
+ Generate a gaussian function.
2788
+
2789
+ >>> curve = pydvif.gaussian(5, 10, 0)
2790
+
2791
+ >>> pydvif.create_plot(curve, legend=True, stylename='ggplot')
2792
+
2793
+ :param amp: amplitude
2794
+ :type amp: float
2795
+ :param wid: width
2796
+ :type wid: float
2797
+ :param center: center
2798
+ :type center: float
2799
+ :param num: optional, number of points
2800
+ :type num: int
2801
+ :param nsd: optional, number of half-widths
2802
+ :type nsd: float
2803
+ :return: Curve -- representing the gaussian function
2804
+ """
2805
+ crv_min = center - (nsd * wid)
2806
+ crv_max = center + (nsd * wid)
2807
+ cc = span(crv_min, crv_max, num)
2808
+
2809
+ dd = cc.y - center
2810
+ cc.y = dd * dd * -1
2811
+ cc.y = np.exp(cc.y / (wid * wid))
2812
+ cc.y = cc.y * amp
2813
+
2814
+ cc.name = f"Gaussian (a: {amp} w: {wid} c: {center})"
2815
+ return cc
2816
+
2817
+
2818
+ def getymax(c, xmin=None, xmax=None):
2819
+ """
2820
+ Get the maximum y-value for the curve within the specified domain.
2821
+
2822
+ :param c: the curve
2823
+ :type Curve:
2824
+ :param xmin: the minimum x-value for the sub-domain
2825
+ :type xmin: float, optional
2826
+ :param xmax: the maximum x-value for the sub-domain
2827
+ :type xmax: float, optional
2828
+ :return: str -- curve name
2829
+ list -- a list of tuples where each tuple contains the x-value and
2830
+ the max y-value.
2831
+ """
2832
+ try:
2833
+ if xmin is not None:
2834
+ r = __get_sub_range(c.x, xmin, xmax)
2835
+ ymax = max(c.y[r[0]:r[1] + 1])
2836
+ else:
2837
+ ymax = max(c.y)
2838
+ r = [0, len(c.x) - 1]
2839
+ except:
2840
+ pass
2841
+
2842
+ if r[0] >= r[1]:
2843
+ # User range is in between actual curve points
2844
+ # c.x val1 val2 c.x
2845
+ xl = c.x[0] if xmin is None else xmin
2846
+ xr = c.x[-1] if xmax is None else xmax
2847
+ range_x = np.linspace(xl, xr, num=1000)
2848
+ y_interp = np.interp(range_x, c.x, c.y)
2849
+ ymax = max(y_interp)
2850
+
2851
+ # User range has only one curve point in between
2852
+ # val1 c.x val2
2853
+ if r[0] == r[1] and c.y[r[0]] > ymax: # Local max
2854
+ ymax = c.y[r[0]]
2855
+ xy_pairs_at_max = getx(c, ymax, xmin, xmax)
2856
+
2857
+ return __toCurveString(c), xy_pairs_at_max
2858
+
2859
+
2860
+ def getymin(c, xmin=None, xmax=None):
2861
+ """
2862
+ Get the minimum y-value for the curve within the specified domain.
2863
+
2864
+ :param c: the curve
2865
+ :type Curve:
2866
+ :param xmin: the minimum x-value for the sub-domain
2867
+ :type xmin: float, optional
2868
+ :param xmax: the maximum x-value for the sub-domain
2869
+ :type xmax: float, optional
2870
+ :return: str -- curve name
2871
+ list -- a list of tuples where each tuple contains the x-value and
2872
+ the min y-value.
2873
+ """
2874
+ try:
2875
+ if xmin is not None:
2876
+ r = __get_sub_range(c.x, xmin, xmax)
2877
+ ymin = min(c.y[r[0]:r[1] + 1])
2878
+ else:
2879
+ ymin = min(c.y)
2880
+ r = [0, len(c.x) - 1]
2881
+ except:
2882
+ pass
2883
+
2884
+ if r[0] >= r[1]:
2885
+ # User range is in between actual curve points
2886
+ # c.x val1 val2 c.x
2887
+ xl = c.x[0] if xmin is None else xmin
2888
+ xr = c.x[-1] if xmax is None else xmax
2889
+ range_x = np.linspace(xl, xr, num=1000)
2890
+ y_interp = np.interp(range_x, c.x, c.y)
2891
+ ymin = min(y_interp)
2892
+
2893
+ # User range has only one curve point in between
2894
+ # val1 c.x val2
2895
+ if r[0] == r[1] and c.y[r[0]] < ymin: # Local min
2896
+ ymin = c.y[r[0]]
2897
+
2898
+ xy_pairs_at_min = getx(c, ymin, xmin, xmax)
2899
+
2900
+ return __toCurveString(c), xy_pairs_at_min
2901
+
2902
+
2903
+ def cumsum(c1):
2904
+ """
2905
+ Creates a new curve which is the cumulative sum of the original curve
2906
+
2907
+ :param c1: The original curve
2908
+ :type c1: Curve
2909
+
2910
+ :return: Curve -- the cumulative sum of the original curve
2911
+ """
2912
+ nc = curve.Curve('', 'cumsum(' + __toCurveString(c1) + ')')
2913
+
2914
+ nc.x = c1.x
2915
+ nc.y = np.cumsum(c1.y)
2916
+
2917
+ return nc
2918
+
2919
+
2920
+ def correlate(c1, c2, mode='valid'):
2921
+ """
2922
+ Computes the cross-correlation of two 1D sequences (c1.y and c2.y) as defined by numpy.correlate.
2923
+
2924
+ :param c1: The first curve with 1D input sequence c1.y
2925
+ :type c1: Curve
2926
+ :param c2: The second curve with 1D input sequence c2.y
2927
+ :type c2: Curve
2928
+ :param mode:
2929
+ full:
2930
+ By default, mode is 'full'. This returns the convolution
2931
+ at each point of overlap, with an output shape of (N+M-1,). At
2932
+ the end-points of the convolution, the signals do not overlap
2933
+ completely, and boundary effects may be seen.
2934
+
2935
+ same:
2936
+ Mode 'same' returns output of length ``max(M, N)``. Boundary
2937
+ effects are still visible.
2938
+
2939
+ valid:
2940
+ Mode 'valid' returns output of length
2941
+ ``max(M, N) - min(M, N) + 1``. The convolution product is only given
2942
+ for points where the signals overlap completely. Values outside
2943
+ the signal boundary have no effect.
2944
+ :type mode: 'full'(default), 'same' or 'valid'
2945
+ :return: Curve -- the cross-correlation of c1.y and c2.y
2946
+ """
2947
+ nc = curve.Curve('', 'correlate(' + __toCurveString(c1) + ', ' + __toCurveString(c2) + ')')
2948
+
2949
+ ic1, step = curve.interp1d(c1, len(c1.x), True)
2950
+ c2npts = (max(c2.x) - min(c2.x)) / step
2951
+ ic2 = curve.interp1d(c2, c2npts)
2952
+
2953
+ y = np.correlate(ic1.y, ic2.y, mode)
2954
+ start = min([min(ic1.x), min(ic2.x)])
2955
+ stop = max([max(ic1.x), max(ic2.x)])
2956
+ nc.x = np.linspace(start, stop, num=len(y))
2957
+ nc.y = np.array(y)
2958
+
2959
+ return nc
2960
+
2961
+
2962
+ def theta(xmin, x0, xmax, numpts=100):
2963
+ """
2964
+ Generate a unit step distribution.
2965
+
2966
+ :param xmin: The left most point
2967
+ :type xmin: Union[int,float]
2968
+ :param x0: The step point
2969
+ :type x0: Union[int,float]
2970
+ :param xmax: The right most point
2971
+ :type xmax: Union[int,float]
2972
+ :param numpts: Number of points, defaults to 100
2973
+ :type numpts: Union[int,float], optional
2974
+ :return: The curve
2975
+ :rtype: curve.Curve
2976
+ """
2977
+
2978
+ numpts = round(numpts / 2)
2979
+
2980
+ firstx = np.linspace(xmin, x0, num=numpts)
2981
+ firsty = [0] * len(firstx)
2982
+
2983
+ secondx = np.linspace(x0, xmax, num=numpts)
2984
+ secondy = [1] * len(secondx)
2985
+
2986
+ x = np.concatenate((firstx, secondx), axis=None)
2987
+ y = firsty + secondy
2988
+
2989
+ c = makecurve(x, y, f'Theta {xmin} {x0} {xmax}')
2990
+
2991
+ return c
2992
+
2993
+
2994
+ def normalize(c):
2995
+ """
2996
+ Normalize a curve.
2997
+
2998
+ :param c: The curve to normalize
2999
+ :type c: curve.Curve
3000
+ :return: The normalized curve
3001
+ :rtype: curve.Curve
3002
+ """
3003
+ norm_c = c.normalize()
3004
+ c = makecurve(norm_c.x, norm_c.y, f'Normalized {norm_c.plotname}')
3005
+ return c
3006
+
3007
+
3008
+ def hypot(c1, c2):
3009
+ """
3010
+ Calculate harmonic average of two curves, sqrt(a^2+b^2).
3011
+
3012
+ :param c1: The first curve
3013
+ :type c1: curve.Curve
3014
+ :param c2: The second curve
3015
+ :type c2: curve.Curve
3016
+ :return: The harmonic average of two curves, sqrt(a^2+b^2)
3017
+ :rtype: curve.Curve
3018
+ """
3019
+
3020
+ if not np.array_equal(c1.x, c2.x):
3021
+ raise ValueError('Curves must have the same x values')
3022
+
3023
+ y = np.sqrt(c1.y**2 + c2.y**2)
3024
+ c = makecurve(c1.x, y, f'hypot {__toCurveString(c1)} {__toCurveString(c2)}')
3025
+
3026
+ return c
3027
+
3028
+
3029
+ def convolve(c1, c2, npts=100, norm=True, debug=False):
3030
+ print("Use convolvec for (g*h)(x) = Int(-inf, inf, dt*g(t)*h(x-t))")
3031
+ print("Use convolveb for (g*h)(x) = Int(-inf, inf, dt*g(t)*h(x-t)) / Int(-inf, inf, dt*h(t))")
3032
+ return
3033
+
3034
+
3035
+ def convolvec(c1, c2, npts=100, npts_interp=100, debug=False):
3036
+ """
3037
+ Computes the convolution of the two given curves:
3038
+ -
3039
+ - ``(g*h)(x) = Int(-inf, inf, dt*g(t)*h(x-t))``
3040
+ -
3041
+ This computes the integrals directly which avoid padding and aliasing
3042
+ problems associated with FFT methods (it is however slower).
3043
+
3044
+ :param c1: (N,) The first curve g(t)
3045
+ :type c1: Curve
3046
+ :param c2: (M,) The second curve h(t)
3047
+ :type c2: Curve
3048
+ :param npts: the number of points to divide the combined domain of the curves to give delx
3049
+ :type npts: int
3050
+ :param npts_interp: the number of points to interpolate at each delx step
3051
+ :type npts_interp: int
3052
+ :param debug: Used only in CLI, plots curves and c2 h(x-t) as it moves
3053
+ :type debug: bool
3054
+ :return: Curve -- the convolution of the two curves c1 and c2 using integration and no normalization
3055
+ """
3056
+
3057
+ return convolve_int(c1, c2, False, npts, npts_interp, debug)
3058
+
3059
+
3060
+ def convolveb(c1, c2, npts=100, npts_interp=100, debug=False):
3061
+ """
3062
+ Computes the convolution of the two given curves:
3063
+ -
3064
+ - ``(g*h)(x) = Int(-inf, inf, dt*g(t)*h(x-t)) / Int(-inf, inf, dt*h(t))``
3065
+ -
3066
+ This computes the integrals directly which avoid padding and aliasing
3067
+ problems associated with FFT methods (it is however slower).
3068
+
3069
+ :param c1: (N,) The first curve g(t)
3070
+ :type c1: Curve
3071
+ :param c2: (M,) The second curve h(t)
3072
+ :type c2: Curve
3073
+ :param npts: the number of points to divide the combined domain of the curves to give delx
3074
+ :type npts: int
3075
+ :param npts_interp: the number of points to interpolate at each delx step
3076
+ :type npts_interp: int
3077
+ :param debug: Used only in CLI, plots curves and c2 h(x-t) as it moves
3078
+ :type debug: bool
3079
+ :return: Curve -- the convolution of the two curves c1 and c2 using integration and normalizing by c2
3080
+ """
3081
+
3082
+ return convolve_int(c1, c2, True, npts, npts_interp, debug)
3083
+
3084
+
3085
+ def convolve_int(c1, c2, norm=True, npts=100, npts_interp=100, debug=False):
3086
+ """
3087
+ Computes the convolution of the two given curves:
3088
+ -
3089
+ - norm=False: ``(g*h)(x) = Int(-inf, inf, dt*g(t)*h(x-t))``
3090
+ - norm=True : ``(g*h)(x) = Int(-inf, inf, dt*g(t)*h(x-t)) / Int(-inf, inf, dt*h(t))``
3091
+ -
3092
+ This computes the integrals directly which avoid padding and aliasing
3093
+ problems associated with FFT methods (it is however slower).
3094
+
3095
+ :param c1: (N,) The first curve g(t)
3096
+ :type c1: Curve
3097
+ :param c2: (M,) The second curve h(t)
3098
+ :type c2: Curve
3099
+ :param norm: if true then normalize c2 h(t) before integration. Used in convolc
3100
+ :type norm: bool
3101
+ :param npts: the number of points to divide the combined domain of the curves to give delx
3102
+ :type npts: int
3103
+ :param npts_interp: the number of points to interpolate at each delx step
3104
+ :type npts_interp: int
3105
+ :param debug: Used only in CLI, plots curves and c2 h(x-t) as it moves
3106
+ :type debug: bool
3107
+ :return: nc: Curve -- the convolution of the two curves c1 and c2
3108
+ """
3109
+
3110
+ c1_copy = copy.deepcopy(c1) # g(t)
3111
+ c2_copy = copy.deepcopy(c2) # h(t)
3112
+
3113
+ c2_original = copy.deepcopy(c2)
3114
+
3115
+ c2_copy.x = np.flip(c2_copy.x) * float(-1)
3116
+ c2_copy.y = np.flip(c2_copy.y)
3117
+
3118
+ dom_c1 = getdomain(c1_copy)
3119
+ dom_c2 = getdomain(c2_copy)
3120
+
3121
+ # Start of g(t)
3122
+ xmn = dom_c1[0][1]
3123
+ # End of g(t) + domain of h(t)
3124
+ xmx = dom_c1[0][2] + (dom_c2[0][2] - dom_c2[0][1])
3125
+
3126
+ # Moving end of h(t) to start of g(t)
3127
+ c2_copy.x += float(xmn) - dom_c2[0][2]
3128
+
3129
+ # Delta x is domain of combined domains
3130
+ delx = (xmx - xmn) / (npts)
3131
+
3132
+ def _integ(cr1, cr2, xcur, xval, yval, iter):
3133
+
3134
+ while iter < npts:
3135
+
3136
+ # Current overlap of g(t) and h(t)
3137
+ overlap = list(cr1.x[np.where(np.logical_and(cr1.x >= cr2.x[0], cr1.x <= cr2.x[-1]))])
3138
+ overlap.extend(list(cr2.x[np.where(np.logical_and(cr2.x >= xmn, cr2.x <= cr1.x[-1]))]))
3139
+ overlap = list(set(overlap))
3140
+ overlap.sort()
3141
+
3142
+ # np.linespace() between first and last overlap
3143
+ overlap_interp = np.linspace(overlap[0], overlap[-1], npts_interp) if overlap else overlap
3144
+
3145
+ # Adding np.linespace() points to original overlap points
3146
+ overlap.extend(overlap_interp)
3147
+ overlap = list(set(overlap))
3148
+ overlap.sort()
3149
+
3150
+ new_y1 = np.interp(overlap, cr1.x, cr1.y)
3151
+ new_y2 = np.interp(overlap, cr2.x, cr2.y)
3152
+ new_y = new_y1 * new_y2
3153
+
3154
+ # if debug:
3155
+ # time.sleep(.5)
3156
+ # gp.plot((cr1.x, cr1.y, dict(legend='g(t)')),
3157
+ # (c2_original.x, c2_original.y, dict(legend='h(x)')),
3158
+ # (cr2.x, cr2.y, dict(legend='h(x-t)')),
3159
+ # (overlap, new_y, dict(legend='g(t)*h(x-t)')),
3160
+ # xmin=xmn - (dom_c2[0][2] - dom_c2[0][1]) * 1.5,
3161
+ # xmax=xmx * 1.5)
3162
+
3163
+ area = scipy.integrate.trapezoid(new_y, overlap)
3164
+
3165
+ cr2.x += delx
3166
+ xval.append(xcur)
3167
+ yval.append(area)
3168
+ iter += 1
3169
+ xcur += delx
3170
+ # return _integ(cr1, cr2, xcur + delx, xval, yval, iter)
3171
+
3172
+ return xval, yval
3173
+
3174
+ x, y = _integ(c1_copy, c2_copy, float(xmn) - dom_c2[0][2], [], [], 0)
3175
+
3176
+ namestr = f'Conv {c1.plotname} * {c2.plotname}'
3177
+ if norm:
3178
+ namestr = f'(Conv {c1.plotname} * {c2.plotname})/Area({c2.plotname})'
3179
+ area0 = scipy.integrate.trapezoid(c2_original.y, c2_original.x)
3180
+ y /= area0
3181
+
3182
+ nc = makecurve(x, y, namestr)
3183
+
3184
+ return nc
3185
+
3186
+
3187
+ def fft(c, n=None, axis=-1, norm=None):
3188
+ """
3189
+ Compute the one-dimensional discrete Fourier Transform for the x- or y-values of c.
3190
+
3191
+ This function computes the one-dimensional *n*-point discrete Fourier
3192
+ Transform (DFT) with the efficient Fast Fourier Transform (FFT)
3193
+ algorithm [CT].
3194
+
3195
+ Raises IndexError: if `axes` is larger than the last axis of `a`.
3196
+
3197
+ Notes: FFT (Fast Fourier Transform) refers to a way the discrete Fourier
3198
+ Transform (DFT) can be calculated efficiently, by using symmetries in the
3199
+ calculated terms. The symmetry is highest when `n` is a power of 2, and
3200
+ the transform is therefore most efficient for these sizes.
3201
+
3202
+ The DFT is defined, with the conventions used in this implementation, in
3203
+ the documentation for the `numpy.fft` module.
3204
+
3205
+ Citation: Cooley, James W., and John W. Tukey, 1965, "An algorithm for the
3206
+ machine calculation of complex Fourier series," *Math. Comput.*
3207
+ 19: 297-301.
3208
+
3209
+ >>> curves = pydvif.read('testData.txt')
3210
+
3211
+ >>> realcurve, imagcurve = pydvif.fft(curves[0])
3212
+
3213
+ :param c: Curve with x- or y-values as input array, can be complex.
3214
+ :type c: Curve
3215
+ :param n: Length of the transformed axis of the output. If `n` is smaller than
3216
+ the length of the input, the input is cropped. If it is larger, the input is padded with zeros.
3217
+ If `n` is not given, the length of the input along the axis specified by `axis` is used.
3218
+ :type n: int, optional
3219
+ :param axis: Axis over which to compute the FFT. If not given, the last axis is used.
3220
+ :type axis: int, optional
3221
+ :param norm: Normalization mode (see `numpy.fft`). Default is None.
3222
+ :type norm: None, "ortho", optional
3223
+ :return: Curve tuple -- Two curves with the real and imaginary parts.
3224
+ """
3225
+
3226
+ nc1 = curve.Curve('', 'Real part FFT ' + __toCurveString(c))
3227
+ nc2 = curve.Curve('', 'Imaginary part FFT ' + __toCurveString(c))
3228
+
3229
+ numpy1_10 = LooseVersion(np.__version__) >= LooseVersion("1.10.0")
3230
+ cnorm = c.normalize()
3231
+ clen = len(c.x)
3232
+
3233
+ if numpy1_10:
3234
+ complex_array = np.fft.fft(cnorm.y, n, axis, norm)
3235
+ complex_array = np.fft.fftshift(complex_array)
3236
+ else:
3237
+ complex_array = np.fft.fft(cnorm.y, n, axis)
3238
+ complex_array = np.fft.fftshift(complex_array)
3239
+
3240
+ val = 1.0 / (float(max(cnorm.x) - min(cnorm.x)) / 2.0)
3241
+ nc1.x = np.fft.fftfreq(clen, d=val)
3242
+ nc1.x = np.fft.fftshift(nc1.x)
3243
+ nc1.y = complex_array.real
3244
+
3245
+ nc2.x = np.array(nc1.x)
3246
+ nc2.y = complex_array.imag
3247
+
3248
+ my(nc2, -1)
3249
+
3250
+ return nc1, nc2
3251
+
3252
+
3253
+ def derivative(c, eo=1):
3254
+ """
3255
+ Take the derivative of the curve.
3256
+
3257
+ >>> curves = pydvif.read('testData.txt')
3258
+
3259
+ >>> newCurve = pydvif.derivative(curves[0])
3260
+
3261
+ :param c: The curve
3262
+ :type c: Curve
3263
+ :param eo: edge_order, gradient is calculated using N-th order accurate differences at the boundaries.
3264
+ Default: 1.
3265
+ :type eo: int, optional
3266
+ :return: A new curve representing the derivate of c
3267
+ """
3268
+ nc = curve.Curve('', 'Derivative ' + __toCurveString(c))
3269
+
3270
+ nc.x = c.x
3271
+ nc.y = np.gradient(c.y, c.x, edge_order=eo)
3272
+
3273
+ return nc
3274
+
3275
+
3276
+ def diffMeasure(c1, c2, tol=1e-8):
3277
+ """
3278
+ Compare two curves. For the given curves a fractional difference measure and its average are computed.
3279
+
3280
+ >>> curves = pydvif.read('testData.txt')
3281
+
3282
+ >>> c1, c2 = pydvif.diffMeasure(curves[0], curves[1])
3283
+
3284
+ >>> curves.append(c1)
3285
+
3286
+ >>> curves.append(c2)
3287
+
3288
+ >>> pydvif.create_plot(curves, legend=True)
3289
+
3290
+ :param c1: The first curve
3291
+ :type c1: Curve
3292
+ :param c2: The second curve
3293
+ :type c2: Curve
3294
+ :param tol: The tolerance
3295
+ :type tol: float
3296
+ :return: tuple -- Two curves representing the fractional difference measure and its average
3297
+ """
3298
+ cdiff = curve.Curve('', 'FD = $|$' + __toCurveString(c1) + ' - ' + __toCurveString(c2) + # noqaw504
3299
+ '$|$/($|$' + __toCurveString(c1) + '$|$ + $|$' + __toCurveString(c2) + '$|$)')
3300
+ ic1, ic2 = curve.getinterp(c1, c2)
3301
+ f1 = tol * (np.max(ic1.y) - np.min(ic1.y))
3302
+ f2 = tol * (np.max(ic2.y) - np.min(ic2.y))
3303
+ ydiff = np.abs(ic1.y - ic2.y)
3304
+ yden = (np.abs(ic1.y) + f1) + (np.abs(ic2.y) + f2)
3305
+ dx = np.max(ic1.x) - np.min(ic1.x)
3306
+ cdiff.x = np.array(ic1.x)
3307
+ cdiff.y = np.array(ydiff / yden)
3308
+ cdiff.y[np.isnan(cdiff.y)] = 0 # corner case where both curves are all zeros since f1 and f2 will also be 0
3309
+
3310
+ cint = curve.Curve('', 'Integral(FD)/dX')
3311
+ yint = scipy.integrate.cumtrapz(cdiff.y, cdiff.x, initial=0.0)
3312
+ cint.x = np.array(ic1.x)
3313
+ cint.y = np.array(yint / dx)
3314
+
3315
+ return cdiff, cint
3316
+
3317
+
3318
+ ########################################################
3319
+ ################## Curve Related ##################### # noqa e266
3320
+ ########################################################
3321
+
3322
+ def vs(c1, c2):
3323
+ """
3324
+ Create a new curve that will plot as the range of the first curve against
3325
+ the range of the second curve.
3326
+
3327
+ >>> curves = pydvif.read('testData.txt')
3328
+
3329
+ >>> c1 = pydvif.vs(curves[0], curves[1])
3330
+
3331
+ >>> curves.append(c1)
3332
+
3333
+ >>> pydvif.create_plot(curves, legend=True)
3334
+
3335
+ :param c1: The first curve
3336
+ :type c1: Curve
3337
+ :param c2: The second curve
3338
+ :type c2: Curve
3339
+ :return: Curve -- the new curve
3340
+ """
3341
+ newfilename = ''
3342
+ newrecord_id = ''
3343
+ if c1.filename == c2.filename:
3344
+ newfilename = c1.filename
3345
+ if c1.record_id == c2.record_id:
3346
+ newrecord_id = c1.record_id
3347
+ nc = curve.Curve(newfilename, __toCurveString(c1) + ' vs ' + __toCurveString(c2),
3348
+ newrecord_id, c2.ylabel, c1.ylabel)
3349
+ ic1, ic2 = curve.getinterp(c1, c2)
3350
+ nc.x = np.array(ic2.y)
3351
+ nc.y = np.array(ic1.y)
3352
+ return nc
3353
+
3354
+
3355
+ def subsample(curvelist, stride=2, verbose=False):
3356
+ """
3357
+ Subsample the curve or list of curves, i.e., reduce to every nth value.
3358
+
3359
+ >>> curves = pydvif.read('testData.txt')
3360
+
3361
+ >>> pydvif.subsample(curves, 4)
3362
+
3363
+ >>> pydvif.create_plot(curves, legend=True)
3364
+
3365
+ :param curvelist: The curve or list of curves
3366
+ :type curvelist: Curve or list
3367
+ :param stride: The step size through the array
3368
+ :type stride: int
3369
+ :param verbose: If True additional information will be printed to stdout
3370
+ :type verbose: bool
3371
+ """
3372
+ curves = list()
3373
+
3374
+ if isinstance(curvelist, list):
3375
+ curves.extend(curvelist)
3376
+ else:
3377
+ curves.append(curvelist)
3378
+
3379
+ for c in curves:
3380
+ n = len(c.x)
3381
+ xss = c.x[0:n:int(stride)]
3382
+ yss = c.y[0:n:int(stride)]
3383
+ c.x = xss
3384
+ c.y = yss
3385
+
3386
+ if verbose:
3387
+ print("Reduced %s from %i -> %i values." % (c.name, n, len(c.x)))
3388
+
3389
+
3390
+ def smooth(curvelist, factor=1):
3391
+ """
3392
+ Smooth the curve to the given degree.
3393
+
3394
+ >>> curves = pydvif.read('testData.txt')
3395
+
3396
+ >>> pydvif.smooth(curves, 4)
3397
+
3398
+ >>> pydvif.create_plot(curves, legend=True)
3399
+
3400
+ :param curvelist: The curve or list of curves
3401
+ :type curvelist: Curve or list
3402
+ :param factor: The smooth factor
3403
+ :type factor: int
3404
+ """
3405
+ curves = list()
3406
+
3407
+ if isinstance(curvelist, list):
3408
+ curves.extend(curvelist)
3409
+ else:
3410
+ curves.append(curvelist)
3411
+
3412
+ for c in curves:
3413
+ if len(c.x) < 2:
3414
+ return 0
3415
+
3416
+ x = list()
3417
+ y = list()
3418
+
3419
+ for i in range(len(c.x)):
3420
+ tfactor = factor
3421
+
3422
+ if i - factor < 0 and i < (len(c.x) - 1) / 2:
3423
+ tfactor = i
3424
+ elif i + factor >= len(c.x):
3425
+ tfactor = len(c.x) - 1 - i
3426
+
3427
+ xsum = 0
3428
+ ysum = 0
3429
+
3430
+ for j in range(-tfactor, tfactor + 1):
3431
+ xsum += c.x[i + j]
3432
+ for j in range(-factor, factor + 1):
3433
+ if 0 <= i + j < len(c.x):
3434
+ ysum += c.y[i + j]
3435
+ elif i + j < 0:
3436
+ ysum += c.y[0]
3437
+ else:
3438
+ ysum += c.y[-1]
3439
+
3440
+ x.append(xsum / (2 * tfactor + 1))
3441
+ y.append(ysum / (2 * factor + 1))
3442
+
3443
+ c.x = np.array(x)
3444
+ c.y = np.array(y)
3445
+
3446
+
3447
+ def errorbar(scur, cury1, cury2, curx1=None, curx2=None, mod=1):
3448
+ """
3449
+ Plot error bars on the given curve.
3450
+
3451
+ >>> curves = list()
3452
+
3453
+ >>> curves.append(pydvif.span(1,10))
3454
+
3455
+ >>> curves.append(pydvif.span(1,10))
3456
+
3457
+ >>> curves.append(pydvif.span(1,10))
3458
+
3459
+ >>> pydvif.dy(curves[0], 0.25)
3460
+
3461
+ >>> pydvif.dy(curves[2], -0.25)
3462
+
3463
+ >>> pydvif.errorbar(curves[1], curves[0], curves[2])
3464
+
3465
+ >>> pydvif.create_plot(curves, legend=True)
3466
+
3467
+ :param scur: The given curve
3468
+ :type scur: Curve
3469
+ :param cury1: y-error-curve
3470
+ :type cury1: Curve
3471
+ :param cury2: y+error-curve
3472
+ :type cury2: Curve
3473
+ :param curx1: x-error-curve
3474
+ :type curx1: Curve
3475
+ :param curx2: x+error-curve
3476
+ :type curx2: Curve
3477
+ :param mod: point-skip
3478
+ :type mod: int
3479
+ """
3480
+ ebar = [np.zeros(len(scur.x)), np.zeros(len(scur.x)), np.zeros(len(scur.x)), np.zeros(len(scur.x))]
3481
+ lowy = list()
3482
+ for i in range(len(scur.x)):
3483
+ y = np.interp(scur.x[i], cury1.x, cury1.y)
3484
+ if scur.y[i] - y <= 0:
3485
+ lowy.append(y)
3486
+ else:
3487
+ lowy.append(scur.y[i])
3488
+
3489
+ ebar[0] = np.array(lowy)
3490
+ ebar[1] = np.interp(scur.x, cury2.x, cury2.y)
3491
+
3492
+ if curx1 is not None and curx2 is not None:
3493
+ ebar[2] = np.interp(scur.x, curx1.x, curx1.y)
3494
+ ebar[3] = np.interp(scur.x, curx2.x, curx2.y)
3495
+
3496
+ for i in range(len(ebar[0])):
3497
+ if (i % int(mod) != 0) and (i != len(ebar[0]) - 1):
3498
+ ebar[0][i] = None
3499
+ ebar[1][i] = None
3500
+ ebar[2][i] = None
3501
+ ebar[3][i] = None
3502
+
3503
+ scur.ebar = ebar
3504
+ scur.erange = None
3505
+
3506
+
3507
+ def errorrange(scur, cury1, cury2):
3508
+ """
3509
+ Plot shaded error region on given curve.
3510
+
3511
+ >>> curves = list()
3512
+
3513
+ >>> curves.append(pydvif.span(1,10))
3514
+
3515
+ >>> curves.append(pydvif.span(1,10))
3516
+
3517
+ >>> curves.append(pydvif.span(1,10))
3518
+
3519
+ >>> pydvif.dy(curves[0], 0.25)
3520
+
3521
+ >>> pydvif.dy(curves[2], -0.25)
3522
+
3523
+ >>> pydvif.errorrange(curves[1], curves[0], curves[2])
3524
+
3525
+ >>> pydvif.create_plot(curves, legend=True)
3526
+
3527
+ :param scur: The given curve
3528
+ :type scur: Curve
3529
+ :param cury1: y-error-curve
3530
+ :type cury1: Curve
3531
+ :param cury2: y+error-curve
3532
+ :type cury2: Curve
3533
+ """
3534
+
3535
+ errorbar(scur, cury1, cury2)
3536
+ scur.erange = [scur.ebar[0], scur.ebar[1]]
3537
+ scur.ebar = None
3538
+
3539
+
3540
+ def fit(c, n=1, logx=False, logy=False):
3541
+ """
3542
+ Make a new curve that is a polynomial fit to curve c.
3543
+
3544
+ >>> curves = list()
3545
+
3546
+ >>> curves.append(pydvif.span(1,10))
3547
+
3548
+ >>> pydvif.sin(curves)
3549
+
3550
+ >>> curves.append(pydvif.fit(curves[0], 2))
3551
+
3552
+ >>> pydvif.create_plot(curves, legend=True)
3553
+
3554
+ :param c: The curve to fit
3555
+ :type c: Curve
3556
+ :param n: Degree of the fitting polynomial
3557
+ :type n: int
3558
+ :param logx: Take the log(x-values) before fitting if True
3559
+ :type logx: bool
3560
+ :param logy: Take the log(y-values) before fitting if True
3561
+ :type logy: bool
3562
+ :return: Curve -- The fitting polynomial
3563
+ """
3564
+ x = c.x
3565
+ y = c.y
3566
+
3567
+ if logx:
3568
+ x = np.log10(x)
3569
+
3570
+ if logy:
3571
+ y = np.log10(y)
3572
+
3573
+ coeffs = scipy.polyfit(x, y, n)
3574
+ if len(coeffs) == 2:
3575
+ print("slope = ", coeffs[0], " intercept = ", coeffs[1])
3576
+ else:
3577
+ print("coefficients are: ", coeffs)
3578
+
3579
+ if n == 1:
3580
+ oString = "1st "
3581
+ elif n == 2:
3582
+ oString = "2nd "
3583
+ elif n == 3:
3584
+ oString = "3rd "
3585
+ else:
3586
+ oString = "%dth " % n
3587
+
3588
+ nc = curve.Curve('', oString + 'order fit to ' + __toCurveString(c))
3589
+ nc.x = np.array(x)
3590
+ nc.y = scipy.polyval(coeffs, x)
3591
+
3592
+ if logx:
3593
+ nc.x = 10.0**nc.x
3594
+
3595
+ if logy:
3596
+ nc.y = 10.0**nc.y
3597
+
3598
+ return nc
3599
+
3600
+
3601
+ def getdomain(curvelist):
3602
+ """
3603
+ Get domain of the curve or list of curves.
3604
+
3605
+ >>> curves = pydvif.read('testData.txt')
3606
+
3607
+ >>> domains = pydvif.getdomain(curves)
3608
+
3609
+ >>> plotname, minx, maxx = domains[0]
3610
+
3611
+ :param curvelist: The given curve or list of curves
3612
+ :type curvelist: Curve or list
3613
+ :return: list -- A list of tuples where each tuple contains the curve name, minimum x, and maximum x
3614
+ """
3615
+ domains = list()
3616
+ curves = list()
3617
+
3618
+ if isinstance(curvelist, list):
3619
+ curves.extend(curvelist)
3620
+ else:
3621
+ curves.append(curvelist)
3622
+
3623
+ for c in curves:
3624
+ domains.append((__toCurveString(c), min(c.x), max(c.x)))
3625
+
3626
+ return domains
3627
+
3628
+
3629
+ def sum(curvelist):
3630
+ """
3631
+ Return sum of the x and y values of each curve.
3632
+
3633
+ >>> curves = pydvif.read('testData.txt')
3634
+
3635
+ >>> sums = pydvif.sum(curves)
3636
+
3637
+ >>> plotname, sumx, sumy = sums[0]
3638
+
3639
+ :param curvelist: The given curve or list of curves
3640
+ :type curvelist: Curve or list
3641
+ :return: list -- A list of tuples where each tuple contains the curve name, sum of x-values, and sum of y-values
3642
+ """
3643
+ sums = list()
3644
+ curves = list()
3645
+
3646
+ if isinstance(curvelist, list):
3647
+ curves.extend(curvelist)
3648
+ else:
3649
+ curves.append(curvelist)
3650
+
3651
+ for c in curves:
3652
+ sums.append((__toCurveString(c), np.sum(c.x), np.sum(c.y)))
3653
+
3654
+ return sums
3655
+
3656
+
3657
+ def area(curvelist):
3658
+ """
3659
+ Return area of each curve.
3660
+
3661
+ >>> curves = pydvif.read('testData.txt')
3662
+
3663
+ >>> areas = pydvif.area(curves)
3664
+
3665
+ >>> plotname, area = areas[0]
3666
+
3667
+ :param curvelist: The given curve or list of curves
3668
+ :type curvelist: Curve or list
3669
+ :return: list -- A list of tuples where each tuple contains the curve name and area
3670
+ """
3671
+ areas = list()
3672
+ curves = list()
3673
+
3674
+ if isinstance(curvelist, list):
3675
+ curves.extend(curvelist)
3676
+ else:
3677
+ curves.append(curvelist)
3678
+
3679
+ for c in curves:
3680
+ areas.append((__toCurveString(c), scipy.integrate.simpson(c.y, c.x)))
3681
+
3682
+ return areas
3683
+
3684
+
3685
+ def disp(c, domain=True):
3686
+ """
3687
+ Create a string formatted list of the curve's x-values if domain is True, otherwise y-values.
3688
+
3689
+ >>> c = pydvif.span(1, 10)
3690
+
3691
+ >>> yvalues = pydvif.disp(c, False)
3692
+
3693
+ :param c: The given curve
3694
+ :type curvelist: Curve
3695
+ :param domain: if True, display the x-values of the curve. Otherwise, display the y-values of the curve
3696
+ :type domain: bool, optional
3697
+ :return: list -- The list of x- or y-values as strings
3698
+ """
3699
+ ss = list()
3700
+
3701
+ for i in range(len(c.x)):
3702
+ if domain:
3703
+ ss.append('x[%d]: %.4f' % (i, c.x[i]))
3704
+ else:
3705
+ ss.append('y[%d]: %.4f' % (i, c.y[i]))
3706
+
3707
+ return ss
3708
+
3709
+
3710
+ def getnumpoints(curve):
3711
+ """
3712
+ Return the given curve's number of points.
3713
+
3714
+ :param curve: The given curve
3715
+ :return: int -- the number of points in curve
3716
+ """
3717
+ return len(curve.x)
3718
+
3719
+
3720
+ def getrange(curvelist):
3721
+ """
3722
+ Get the range of the curve or list of curves.
3723
+
3724
+ >>> curves = pydvif.read('testData.txt')
3725
+
3726
+ >>> ranges = pydvif.getrange(curves)
3727
+
3728
+ >>> plotname, miny, maxy = ranges[0]
3729
+
3730
+ :param curvelist: The given curve or list of curves
3731
+ :type curvelist: Curve or list
3732
+ :return: list -- A list of tuples where each tuple contains the curve name, minimum y, and maximum y
3733
+ """
3734
+ ranges = list()
3735
+ curves = list()
3736
+
3737
+ if isinstance(curvelist, list):
3738
+ curves.extend(curvelist)
3739
+ else:
3740
+ curves.append(curvelist)
3741
+
3742
+ for c in curves:
3743
+ ranges.append((__toCurveString(c), min(c.y), max(c.y)))
3744
+
3745
+ return ranges
3746
+
3747
+
3748
+ def getx(c, value, xmin=None, xmax=None):
3749
+ """
3750
+ Get the x values of the curve for a given y.
3751
+
3752
+ >>> curves = pydvif.read('testData.txt')
3753
+
3754
+ >>> vals = pydvif.getx(curves[0], 4)
3755
+
3756
+ >>> x, y = vals[0]
3757
+
3758
+ :param c: The curve
3759
+ :type c: Curve
3760
+ :param value: y value
3761
+ :type value: float
3762
+ :return: list -- A list of tuples where each tuple contains the x value, and the given y
3763
+ """
3764
+ xypairs = list()
3765
+ r = __get_sub_range(c.x, xmin, xmax)
3766
+
3767
+ if float(value) < np.amin(c.y) or float(value) > np.amax(c.y):
3768
+ raise ValueError('y-value out of range')
3769
+
3770
+ if r[0] < r[1]:
3771
+ for i in range(r[0], r[1] + 1):
3772
+ if c.y[i] == float(value): # value exists in curve
3773
+ xypairs.append((c.x[i], float(value)))
3774
+ else: # value does not exist in curve
3775
+ ymax = c.y[i]
3776
+ if i + 1 < len(c.y):
3777
+ ymax = c.y[i + 1]
3778
+
3779
+ if c.y[i] < float(value) < ymax:
3780
+ x = np.interp(float(value), [c.y[i], ymax], [c.x[i], c.x[i + 1]])
3781
+ xypairs.append((x, float(value)))
3782
+ elif ymax < float(value) < c.y[i]:
3783
+ x = np.interp(float(value), [ymax, c.y[i]], [c.x[i + 1], c.x[i]])
3784
+ xypairs.append((x, float(value)))
3785
+ else:
3786
+
3787
+ # User range is in between actual curve points
3788
+ # c.x val1 val2 c.x
3789
+ xl = c.x[0] if xmin is None else xmin
3790
+ xr = c.x[-1] if xmax is None else xmax
3791
+ range_x = np.linspace(xl, xr, num=1000)
3792
+ y_interp = np.interp(range_x, c.x, c.y)
3793
+ for x, y in zip(range_x, y_interp):
3794
+ if y == value:
3795
+ xypairs.append((x, y))
3796
+
3797
+ # User range has only one curve point in between
3798
+ # val1 c.x val2
3799
+ if r[0] == r[1]:
3800
+ if c.y[r[0]] == float(value): # value exists in curve
3801
+ xypairs.append((c.x[r[0]], float(value)))
3802
+
3803
+ return xypairs
3804
+
3805
+
3806
+ def gety(c, value):
3807
+ """
3808
+ Get the y values of the curve for a given x.
3809
+
3810
+ >>> curves = pydvif.read('testData.txt')
3811
+
3812
+ >>> vals = pydvif.gety(curves[0], 2)
3813
+
3814
+ >>> x, y = vals[0]
3815
+
3816
+ :param c: The curve
3817
+ :type c: Curve
3818
+ :param value: x value
3819
+ :type value: float
3820
+ :return: list -- A list of tuples where each tuple contains the y value, and the given x
3821
+ """
3822
+ xypairs = list()
3823
+
3824
+ # if float(value) < np.amin(c.x) or float(value) > np.amax(c.x):
3825
+ # raise ValueError, 'x-value out of range'
3826
+
3827
+ for i in range(len(c.x)):
3828
+ if float(value) < np.amin(c.x):
3829
+ xypairs.append((float(value), 0)) # c.y[0]))
3830
+ elif float(value) > np.amax(c.x):
3831
+ xypairs.append((float(value), 0)) # c.y[-1]))
3832
+ elif c.x[i] == float(value):
3833
+ xypairs.append((float(value), c.y[i]))
3834
+ else:
3835
+ xmax = c.x[i]
3836
+ if i + 1 < len(c.x):
3837
+ xmax = c.x[i + 1]
3838
+
3839
+ if c.x[i] < float(value) < xmax:
3840
+ y = np.interp(float(value), [c.x[i], xmax], [c.y[i], c.y[i + 1]])
3841
+ xypairs.append((float(value), y))
3842
+ elif xmax < float(value) < c.x[i]:
3843
+ y = np.interp(float(value), [xmax, c.x[i]], [c.y[i + 1], c.y[i]])
3844
+ xypairs.append((float(value), y))
3845
+
3846
+ return xypairs
3847
+
3848
+
3849
+ def line(m, b, xmin, xmax, numpts=100):
3850
+ """
3851
+ Generate a line with y = mx + b and an optional number of points.
3852
+
3853
+ >>> curves = list()
3854
+
3855
+ >>> curves.append(pydvif.line(2, 5, 0, 10))
3856
+
3857
+ >>> pydvif.create_plot(curves, legend=True, stylename='ggplot')
3858
+
3859
+ :param m: The slope
3860
+ :type m: float
3861
+ :param b: The y-intercept
3862
+ :type b: float
3863
+ :param xmin: The minimum x value
3864
+ :type xmin: float
3865
+ :param xmax: The maximum x value
3866
+ :type xmax: float
3867
+ :param numpts: The number of points to use for the new line
3868
+ :type numpts: int
3869
+ :return: Curve -- The curve representing the newly created line
3870
+ """
3871
+ m = float(m)
3872
+ b = float(b)
3873
+ xmin = float(xmin)
3874
+ xmax = float(xmax)
3875
+ numpts = int(numpts)
3876
+
3877
+ spacing = (xmax - xmin) / (numpts - 1)
3878
+ x = list()
3879
+ y = list()
3880
+
3881
+ for i in range(numpts):
3882
+ x.append(xmin)
3883
+ y.append(xmin * m + b)
3884
+ xmin += spacing
3885
+
3886
+ x = np.array(x)
3887
+ y = np.array(y)
3888
+ c = curve.Curve('', f'Straight Line (m: {m} b: {b} xmin: {xmin} xmax: {xmax})')
3889
+ c.x = x
3890
+ c.y = y
3891
+
3892
+ return c
3893
+
3894
+
3895
+ def delta(xmn, x0, xmx, npts=100):
3896
+ """
3897
+ Procedure: Generate a Dirac delta distribution such that
3898
+ Int(xmin, xmax, dt*delta(t - x0)) = 1
3899
+
3900
+ :param xmn: The minimum x location
3901
+ :type xmn: float
3902
+ :param x0: The location of the unit impulse
3903
+ :type x0: float
3904
+ :param xmx: The maximum x location
3905
+ :type xmx: float
3906
+ :param npts: The number of points for the curve
3907
+ :type npts: int
3908
+ :return: The Dirac delta distribution
3909
+ :rtype: curve.Curve
3910
+ """
3911
+ # From Ultra
3912
+ dxt = xmx - xmn
3913
+ dxi = dxt / npts
3914
+ dxl = x0 - xmn
3915
+ dnl = dxl / dxi
3916
+ xv1 = (dxi * dnl) + xmn
3917
+ xv2 = xv1 + dxi
3918
+ ds = dxi**2
3919
+ yv1 = (xv2 - x0) / ds
3920
+ yv2 = (x0 - xv1) / ds
3921
+ # dxr = xmx - x0
3922
+ numl = dnl - 1
3923
+ numr = (npts - 2) - numl
3924
+
3925
+ crvl = line(0, 0, xmn, xv1 - dxi, numl)
3926
+ crvr = line(0, 0, xv2 + dxi, xmx, numr)
3927
+ crvm = makecurve([xv1, xv2], [yv1, yv2])
3928
+
3929
+ x = np.concatenate([crvl.x, crvm.x, crvr.x])
3930
+ y = np.concatenate([crvl.y, crvm.y, crvr.y])
3931
+
3932
+ c = makecurve(x, y, f'Dirac Delta {xmn} {x0} {xmx}')
3933
+
3934
+ return c
3935
+
3936
+
3937
+ def makeextensive(curvelist):
3938
+ """
3939
+ Set the y-values such that ``y[i] *= (x[i+1] - x[i])``
3940
+
3941
+ >>> curves = pydvif.read('testData.txt')
3942
+
3943
+ >>> pydvif.makeextensive(curves)
3944
+
3945
+ >>> pydvif.create_plot(curves, legend=True)
3946
+
3947
+ :param curvelist: The curve or list of curves
3948
+ :type curvelist: Curve or list
3949
+ """
3950
+ curves = list()
3951
+
3952
+ if isinstance(curvelist, list):
3953
+ curves.extend(curvelist)
3954
+ else:
3955
+ curves.append(curvelist)
3956
+
3957
+ for c in curves:
3958
+ for i in range(1, len(c.y)):
3959
+ c.y[i] *= (c.x[i] - c.x[i - 1])
3960
+
3961
+ c.y[0] = c.y[1]
3962
+ c.name = 'mkext(' + c.name + ')'
3963
+
3964
+
3965
+ def makeintensive(curvelist):
3966
+ """
3967
+ Set the y-values such that y[i] /= (x[i+1] - x[i]).
3968
+
3969
+ >>> curves = pydvif.read('testData.txt')
3970
+
3971
+ >>> pydvif.makeintensive(curves)
3972
+
3973
+ >>> pydvif.create_plot(curves, legend=True)
3974
+
3975
+ :param curvelist: The curve or list of curves
3976
+ :type curvelist: Curve or list
3977
+ """
3978
+ curves = list()
3979
+
3980
+ if isinstance(curvelist, list):
3981
+ curves.extend(curvelist)
3982
+ else:
3983
+ curves.append(curvelist)
3984
+
3985
+ for c in curves:
3986
+ for i in range(1, len(c.y)):
3987
+ d = c.x[i] - c.x[i - 1] if (c.x[i] - c.x[i - 1]) != 0 else 0.000000001
3988
+ c.y[i] /= d
3989
+
3990
+ c.y[0] = c.y[1]
3991
+ c.name = 'mkint(' + c.name + ')'
3992
+
3993
+
3994
+ def dupx(curvelist):
3995
+ """
3996
+ Duplicate the x-values such that y = x for each of the given curves.
3997
+
3998
+ >>> curves = pydvif.read('testData.txt')
3999
+
4000
+ >>> pydvif.dupx(curves)
4001
+
4002
+ >>> pydvif.create_plot(curves, legend=True)
4003
+
4004
+ :param curvelist: The curve or list of curves
4005
+ :type curvelist: Curve or list
4006
+ """
4007
+ curves = list()
4008
+
4009
+ if isinstance(curvelist, list):
4010
+ curves.extend(curvelist)
4011
+ else:
4012
+ curves.append(curvelist)
4013
+
4014
+ for c in curves:
4015
+ c.y = np.copy(c.x)
4016
+
4017
+
4018
+ def sort(curve):
4019
+ """
4020
+ Sort the specified curve so that their points are plotted in order of ascending x values.
4021
+
4022
+ >>> c = pydvif.span(1, 10)
4023
+
4024
+ >>> pydvif.sort(c)
4025
+
4026
+ :param curve: The curve to sort
4027
+ :type curve: Curve
4028
+ """
4029
+ index_array = np.argsort(curve.x)
4030
+ x = list()
4031
+ y = list()
4032
+
4033
+ for index in index_array:
4034
+ x.append(curve.x[index])
4035
+ y.append(curve.y[index])
4036
+
4037
+ curve.x = np.array(x)
4038
+ curve.y = np.array(y)
4039
+
4040
+
4041
+ def rev(curve):
4042
+ """
4043
+ Swap x and y values for the specified curves. You may want to sort after this one.
4044
+
4045
+ >>> c = pydvif.span(1, 10)
4046
+
4047
+ >>> pydvif.rev(c)
4048
+
4049
+ :param curve: The curve to sort
4050
+ :type curve: Curve
4051
+ """
4052
+ x = np.copy(curve.y)
4053
+ y = np.copy(curve.x)
4054
+
4055
+ curve.x = x
4056
+ curve.y = y
4057
+
4058
+
4059
+ def random(curve):
4060
+ """
4061
+ Generate random y values between -1 and 1 for the specified curves.
4062
+
4063
+ >>> c = pydvif.span(1, 10)
4064
+
4065
+ >>> pydvif.random(c)
4066
+
4067
+ :param curve: The curve to sort
4068
+ :type curve: Curve
4069
+ """
4070
+ for i in range(len(curve.y)):
4071
+ curve.y[i] = sysrand.uniform(-1, 1)
4072
+
4073
+
4074
+ def xindex(curvelist):
4075
+ """
4076
+ Create curves with y-values vs. integer index values.
4077
+
4078
+ >>> curves = pydvif.read('testData.txt')
4079
+
4080
+ >>> pydvif.xindex(curves)
4081
+
4082
+ >>> pydvif.create_plot(curves, legend=True)
4083
+
4084
+ :param curvelist: The curve or list of curves
4085
+ :type curvelist: Curve or list
4086
+ """
4087
+ curves = list()
4088
+
4089
+ if isinstance(curvelist, list):
4090
+ curves.extend(curvelist)
4091
+ else:
4092
+ curves.append(curvelist)
4093
+
4094
+ for c in curves:
4095
+ stop = len(c.y)
4096
+ c.x = np.linspace(1, stop, num=stop)
4097
+
4098
+
4099
+ def appendcurves(curvelist):
4100
+ """
4101
+ Merge two or more curves over the union of their domains. Where domains overlap, take the
4102
+ average of the curve's y-values.
4103
+
4104
+ >>> curves = pydvif.read('testData.txt')
4105
+
4106
+ >>> newcurve = pydvif.appendcurve(curves)
4107
+
4108
+ :param curvelist: the specified curves
4109
+ :type curvelist: list
4110
+ :return: Curve -- the merging of the two curves c1 and c2
4111
+ """
4112
+ if len(curvelist) < 2:
4113
+ if len(curvelist) == 1:
4114
+ return curvelist[0]
4115
+ else:
4116
+ return
4117
+ else:
4118
+ nc = curve.append(curvelist[0], curvelist[1])
4119
+
4120
+ for i in range(2, len(curvelist)):
4121
+ nc = curve.append(nc, curvelist[i])
4122
+
4123
+ suffix = ''
4124
+ for c in curvelist:
4125
+ suffix += "%s" % c.plotname
4126
+
4127
+ nc.name = 'Append(' + suffix + ')'
4128
+
4129
+ return nc
4130
+
4131
+
4132
+ def max_curve(curvelist):
4133
+ """
4134
+ Construct a curve from the maximum y values of the intersection of the curves domain.
4135
+
4136
+ :param curvelist: the specified curves
4137
+ :return: Curve -- a new curve with the maximum y-values over the intersection of the
4138
+ domains of the specified curves.
4139
+ """
4140
+ # Get union of domains
4141
+ if len(curvelist) <= 1:
4142
+ return None
4143
+ else:
4144
+ ux = set(curvelist[0].x).union(set(curvelist[1].x))
4145
+ for i in range(2, len(curvelist)):
4146
+ ux = set(curvelist[i].x).union(ux)
4147
+
4148
+ ux = list(ux)
4149
+ ux.sort()
4150
+
4151
+ # Create curve label suffix
4152
+ name_suffix = ''
4153
+ for i in range(len(curvelist)):
4154
+ name_suffix += "%s" % curvelist[i].plotname
4155
+
4156
+ # Calculate max
4157
+ x = np.array(ux)
4158
+ y = np.zeros(len(x))
4159
+
4160
+ for i in range(len(x)):
4161
+ y[i] = float(-sys.maxsize - 1)
4162
+ for j in range(len(curvelist)):
4163
+ try:
4164
+ vals = gety(curvelist[j], x[i])
4165
+ for val in vals:
4166
+ if y[i] < val[1]:
4167
+ y[i] = val[1]
4168
+ except:
4169
+ pass
4170
+
4171
+ nc = curve.Curve('', 'Max(' + name_suffix + ')')
4172
+ nc.x = np.array(x)
4173
+ nc.y = y
4174
+
4175
+ return nc
4176
+
4177
+
4178
+ def min_curve(curvelist):
4179
+ """
4180
+ Construct a curve from the minimum y values of the intersection of the curves domain.
4181
+
4182
+ :param curvelist: the specified curves
4183
+ :return: Curve -- a new curve with the minimum y-values over the intersection of the
4184
+ domains of the specified curves.
4185
+ """
4186
+ # Get union of domains
4187
+ if len(curvelist) <= 1:
4188
+ return None
4189
+ else:
4190
+ ux = set(curvelist[0].x).union(set(curvelist[1].x))
4191
+ for i in range(2, len(curvelist)):
4192
+ ux = set(curvelist[i].x).union(ux)
4193
+
4194
+ ux = list(ux)
4195
+ ux.sort()
4196
+
4197
+ # Create curve label suffix
4198
+ name_suffix = ''
4199
+ for i in range(len(curvelist)):
4200
+ name_suffix += "%s" % curvelist[i].plotname
4201
+
4202
+ # Calculate min
4203
+ x = np.array(ux)
4204
+ y = np.zeros(len(x))
4205
+
4206
+ for i in range(len(x)):
4207
+ y[i] = float(sys.maxsize)
4208
+ for j in range(len(curvelist)):
4209
+ try:
4210
+ vals = gety(curvelist[j], x[i])
4211
+ for val in vals:
4212
+ if y[i] > val[1]:
4213
+ y[i] = val[1]
4214
+ except:
4215
+ pass
4216
+
4217
+ nc = curve.Curve('', 'Min(' + name_suffix + ')')
4218
+ nc.x = np.array(x)
4219
+ nc.y = y
4220
+
4221
+ return nc
4222
+
4223
+
4224
+ def average_curve(curvelist):
4225
+ """
4226
+ Average the specified curves over the intersection of their domains.
4227
+
4228
+ :param curvelist: the specified curves
4229
+ :return: Curve -- a new curve with the average values over the intersection of the domains of the specified curves.
4230
+ """
4231
+ # Get union of domains
4232
+ if len(curvelist) <= 1:
4233
+ return None
4234
+ else:
4235
+ ux = set(curvelist[0].x).union(set(curvelist[1].x))
4236
+ for i in range(2, len(curvelist)):
4237
+ ux = set(curvelist[i].x).union(ux)
4238
+
4239
+ ux = list(ux)
4240
+ ux.sort()
4241
+
4242
+ # Create curve label suffix
4243
+ name_suffix = ''
4244
+ for i in range(len(curvelist)):
4245
+ name_suffix += "%s" % curvelist[i].plotname
4246
+
4247
+ # Calculate average
4248
+ x = np.array(ux)
4249
+ y = np.zeros(len(x))
4250
+
4251
+ for i in range(len(x)):
4252
+ cnt = 0
4253
+ for j in range(len(curvelist)):
4254
+ try:
4255
+ vals = gety(curvelist[j], x[i])
4256
+ for val in vals:
4257
+ y[i] += val[1]
4258
+ cnt += 1
4259
+ except:
4260
+ pass
4261
+
4262
+ y[i] /= cnt
4263
+
4264
+ nc = curve.Curve('', 'Average(' + name_suffix + ')')
4265
+ nc.x = np.array(x)
4266
+ nc.y = y
4267
+
4268
+ return nc
4269
+
4270
+
4271
+ ########################################################
4272
+ ################## Private Methods ##################### # noqa e266
4273
+ ########################################################
4274
+
4275
+ def __fft(c):
4276
+ """
4277
+ Compute the Fast Fourier Transform of a real curve.
4278
+
4279
+ :param c: The curve
4280
+ :type c: Curve
4281
+ :return: tuple - two curves, one with the real part and the other with the imaginary part for their y-values.
4282
+ """
4283
+ nc1 = curve.Curve('', 'Real part FFT ' + __toCurveString(c))
4284
+ nc2 = curve.Curve('', 'Imaginary part FFT ' + __toCurveString(c))
4285
+
4286
+ cnorm = c.normalize()
4287
+ clen = len(c.x)
4288
+
4289
+ complex_array = np.fft.fft(cnorm.y)
4290
+
4291
+ nc1.y = complex_array.real
4292
+ nc1.x = np.linspace(min(cnorm.x), max(cnorm.x), len(nc1.y))
4293
+
4294
+ nc2.y = complex_array.imag
4295
+ nc2.x = np.linspace(min(cnorm.x), max(cnorm.x), clen)
4296
+
4297
+ my(nc2, -1)
4298
+
4299
+ return nc1, nc2
4300
+
4301
+
4302
+ def __ifft(cr, ci):
4303
+ """
4304
+ Compute the 1D inverse discrete Fourier Transform.
4305
+
4306
+ :param cr: Curve containing the real part of a complex number as it's y-values.
4307
+ :type c: Curve
4308
+ :param ci: Curve containing the imaginary part of a complex number as it's y-values
4309
+ :type c: Curve
4310
+ :return: tuple - two curves, one with the real part and the other with the imaginary part for their y-values.
4311
+ """
4312
+ nc1 = curve.Curve('', 'Real part iFFT ' + __toCurveString(cr))
4313
+ nc2 = curve.Curve('', 'Imaginary part iFFT ' + __toCurveString(ci))
4314
+
4315
+ carray = np.zeros(len(cr.y), dtype=complex)
4316
+
4317
+ for i in range(len(cr.y)):
4318
+ carray[i] = complex(cr.y[i], ci.y[i])
4319
+
4320
+ numpy1_10 = LooseVersion(np.__version__) >= LooseVersion("1.10.0")
4321
+
4322
+ if numpy1_10:
4323
+ complex_array = np.fft.ifft(carray)
4324
+ else:
4325
+ complex_array = np.fft.ifft(carray)
4326
+
4327
+ # nc1.x = np.array(cr.x)
4328
+ nc1.y = complex_array.real
4329
+ nc1.x = np.linspace(min(cr.x), max(cr.x), len(nc1.y))
4330
+
4331
+ # nc2.x = np.array(ci.x)
4332
+ nc2.y = complex_array.imag
4333
+ nc2.x = np.linspace(min(ci.x), max(ci.x), len(nc2.y))
4334
+
4335
+ return nc1, nc2
4336
+
4337
+
4338
+ def __complex_times(ra, ia, rb, ib):
4339
+ """
4340
+ Perform the complex product of the given pairs of curves representing the real and imaginary components.
4341
+
4342
+ :param ra: Curve containing the real part
4343
+ :type ra: Curve
4344
+ :param ia: Curve containing the imaginary part
4345
+ :type ia: Curve
4346
+ :param rb: Curve containing the real part
4347
+ :type rb: Curve
4348
+ :param ib: Curve containing the imaginary part
4349
+ :type ib: Curve
4350
+ :return: tuple - pair of curves representing the complex conjugate
4351
+ """
4352
+ rs1 = ra * rb
4353
+ rs2 = ia * ib
4354
+ is1 = ra * ib
4355
+ is2 = ia * rb
4356
+ sa = rs1 - rs2
4357
+ sb = is1 + is2
4358
+
4359
+ return sa, sb
4360
+
4361
+
4362
+ def __get_sub_range(x, low, high):
4363
+ """
4364
+ Returns a tuple with the index of the first value in x greater than low and
4365
+ the index of the first value in x less than high.
4366
+
4367
+ :param x: The array of x-values
4368
+ :type x: array
4369
+ :param low: The lower definite integral interval value
4370
+ :type low: float
4371
+ :param high: The upper definite integral interval value
4372
+ :type high: float
4373
+ :return: tuple -- a tuple with the indices of the first value in x that is
4374
+ greater than low and the first value in x less than high.
4375
+ If low or high is not specified, the corresponding return
4376
+ will be None.
4377
+ """
4378
+ min_idx = np.where(x >= low)[0][0] if low is not None else 0
4379
+ max_idx = np.where(x <= high)[0][-1] if high is not None else len(x) - 1
4380
+ return min_idx, max_idx
4381
+
4382
+
4383
+ def __toCurveString(c):
4384
+ """
4385
+ Returns the string description of the curve.
4386
+
4387
+ :param c: The curve
4388
+ :type c: Curve
4389
+ :return: str -- The curve's name if not empty, otherwise, the curve's plotname
4390
+ """
4391
+ if c.name:
4392
+ return c.name
4393
+
4394
+ return c.plotname
4395
+
4396
+
4397
+ def __loadcolumns(fname, xcol):
4398
+ """
4399
+ Load a column oriented text data file, add parsed curves to the curvelist.
4400
+ '#' is the comment character. The last comment line must be the column
4401
+ labels. We assume the first column is the x-data, every other column is y-data.
4402
+ We also assume all columns are the same length.
4403
+
4404
+ :param fname: The column oriented (.gnu) file
4405
+ :type fname: str
4406
+ :param xcol: x-column number for column oriented (.gnu) files
4407
+ :type xcol: int
4408
+ :returns: list -- the list of curves from the file
4409
+ """
4410
+ curvelist = []
4411
+
4412
+ try:
4413
+ f = open(fname, 'r')
4414
+ lines = f.readlines()
4415
+ iLine = 0
4416
+ for line in lines:
4417
+ if line.strip()[0] != '#':
4418
+ break
4419
+ iLine += 1
4420
+ if iLine == 0:
4421
+ print('WARNING: columns have no labels, labels will be assigned...someday')
4422
+ alllabels = lines[iLine - 1][1:] # drop leading '#' character
4423
+ if '"' in alllabels:
4424
+ colLabels = [x for x in alllabels.split('"')[1:-1] if len(x.replace(" ", "")) > 0]
4425
+ else:
4426
+ colLabels = alllabels.split()
4427
+ # check that we have a label for every column
4428
+ if len(colLabels) != len(lines[iLine].split()) and iLine > 0:
4429
+ raise RuntimeError('Sorry, right now PyDV requires you to have a label for every column.')
4430
+ # We assume some column is the x-data, every other column
4431
+ # is y-data
4432
+ numcurves = len(lines[iLine].split()) - 1
4433
+
4434
+ # Make the curves, append them to self.curvelist.
4435
+ # First, get data into lists of numbers
4436
+ # numDataLines = len(lines) - iLine
4437
+ localCurves = []
4438
+ for i in range(numcurves + 1):
4439
+ localCurves.append([])
4440
+ # FIGURE OUT COOL WAY TO DO THIS LATER: localCurves = (numcurves+1)*[[]]
4441
+ for line in lines[iLine:]:
4442
+ nums = [float(n) for n in line.split()]
4443
+ assert len(nums) == numcurves + 1
4444
+ for colID in range(numcurves + 1):
4445
+ localCurves[colID].append(nums[colID])
4446
+ # convert lists to numpy arrays
4447
+ for colID in range(numcurves):
4448
+ localCurves[colID] = np.array(localCurves[colID])
4449
+ # Make Curve objects, add to curvelist
4450
+ for colID in range(numcurves + 1):
4451
+ if colID != xcol:
4452
+ c = curve.Curve(fname, colLabels[colID])
4453
+ c.x = localCurves[xcol]
4454
+ c.y = localCurves[colID]
4455
+ print("Appended curve: ", colLabels[colID], len(c.x), len(c.y))
4456
+ curvelist.append(c)
4457
+ # tidy up
4458
+ f.close()
4459
+ # anticipate failure!
4460
+ except IOError:
4461
+ traceback.print_exc(file=sys.stdout)
4462
+ print('could not load file: ' + fname)
4463
+ except ValueError:
4464
+ print('invalid pydv file: ' + fname)
4465
+
4466
+ return curvelist
4467
+
4468
+
4469
+ def __loadpdb(fname, fpdb):
4470
+ curvelist = []
4471
+
4472
+ try:
4473
+ curveList = fpdb.ls('curve*')
4474
+ if (len(curveList) == 0):
4475
+ raise ValueError
4476
+ for cname in curveList:
4477
+ curveid = fpdb.read(cname).strip('\x00').split('|')
4478
+ if (len(curveid) != 8):
4479
+ raise IOError
4480
+ current = curve.Curve(fname, fpdb.read(curveid[1]).strip('\x00'))
4481
+ current.x = np.array(fpdb.read(curveid[3]))
4482
+ current.y = np.array(fpdb.read(curveid[4]))
4483
+ curvelist.append(current)
4484
+
4485
+ fpdb.close()
4486
+ except IOError:
4487
+ print('could not load file: ' + fname)
4488
+ except ValueError:
4489
+ print('invalid pydv file: ' + fname)
4490
+
4491
+ return curvelist