plotFunctions.py 41.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
"""
Created on Apr 21, 2016

@author: Chris Smith -- csmith55@utk.edu
"""
import numpy as np
from ioFuncs import readData
import pyqtgraph as pg
from pyqtgraph import QtGui


class BEPSwindow(QtGui.QMainWindow):
Unknown's avatar
Unknown committed
13
    """
14
    Window object that will handle all the plotting
Unknown's avatar
Unknown committed
15
    """
Unknown's avatar
Unknown committed
16

17
    def __init__(self, **kwargs):
Unknown's avatar
Unknown committed
18
        """
19
        Create the initial window
Unknown's avatar
Unknown committed
20
        """
Unknown's avatar
Unknown committed
21
22
        super(BEPSwindow, self).__init__()
        winTitle = kwargs.get('winTitle', 'BEPS Visualization')
23
24
25
26
        self.setWindowTitle(winTitle)
        pg.setConfigOption('background', 'w')
        pg.setConfigOption('foreground', 'k')
        pg.setConfigOption('antialias', True)
Unknown's avatar
Unknown committed
27

28
29
30
        '''
        Define some custom colormaps from VisIt
        '''
Unknown's avatar
Unknown committed
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
        self.hot_desaturated = {'ticks': [(1, (255, 76, 76, 255)),
                                          (0.857, (107, 0, 0, 255)),
                                          (0.714, (255, 96, 0, 255)),
                                          (0.571, (255, 255, 0, 255)),
                                          (0.429, (0, 127, 0, 255)),
                                          (0.285, (0, 255, 255, 255)),
                                          (0.143, (0, 0, 91, 255)),
                                          (0, (71, 71, 219, 255))],
                                'mode': 'rgb'}
        self.hot_cold = {'ticks': [(1, (255, 255, 0, 255)),
                                   (0.55, (255, 0, 0, 255)),
                                   (0.5, (0, 0, 127, 255)),
                                   (0.45, (0, 0, 255, 255)),
                                   (0, (0, 255, 255, 255))],
                         'mode': 'rgb'}
        self.difference = {'ticks': [(1, (255, 0, 0, 255)),
                                     (0.5, (255, 255, 255, 255)),
                                     (0, (0, 0, 255, 255))],
                           'mode': 'rgb'}
50
51
52
        '''
        Colormaps from Matlab
        '''
Unknown's avatar
Unknown committed
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
        self.jet = {'ticks': [(1, (128, 0, 0, 255)),
                              (0.875, (255, 0, 0, 255)),
                              (0.625, (255, 255, 0, 255)),
                              (0.375, (0, 255, 255, 255)),
                              (0.125, (0, 0, 255, 255)),
                              (0, (0, 0, 143, 255))],
                    'mode': 'rgb'}

    #     def sliceViewFunc(self,**kwargs):
    #         '''
    #         Function to slice N-d data to (N-1)-d.
    #         Makes a QWindow, fills it up with 2 ImageView objects, sets an roi to slice.
    #         Input:
    #             winTitle: string, Optional
    #                     Title of QWindow, default = 'Window'.None
    #             plotTitle: string, Optional
    #                     Title of Roi plot window, default = 'Plot'.
    #         Output:  QtGui.QMainWindow, PyQtGraph.ImageView,  PyQtGraph.ImageView, PyQtGraph.ROI
    #         '''
    #
    #         #Make QtWindow, populate it with ImageView and add roi.
    #
    #         win.setWindowTitle('pyqtgraph example: DataSlicing')
    #         cw = QtGui.QWidget()
    #         win.setCentralWidget(cw)
    #         l = QtGui.QGridLayout()
    #         cw.setLayout(l)
    #         imv1 = pg.ImageView()
    #         imv2 = pg.ImageView()
    #         l.addWidget(imv1, 0, 0)
    #         l.addWidget(imv2, 0, 1)
    #         roi = pg.LineSegmentROI([[10, 64], [120,64]], pen='y')
    #         imv1.addItem(roi)
    #
    #         # Customize plot window
    #         pltWdgt = imv1.getRoiPlot()
    #         plt = pltWdgt.getPlotItem()
    #         plt.setLabels(title = plotTitle)
    #         plt.showGrid(x = True, y = True, alpha = 1)
    #         pltdataitem = plt.listDataItems()[0]
    #         pltdataitem.setPen(color = 'r', width =1.)
    #         pltdataitem.setSymbol('o')
    #
    #         return win, imv1, imv2, roi

    # %%

    def setup(self, h5_path=None):
Unknown's avatar
Unknown committed
101
102
        """
        Call the readData functions from ioFuncs to setup the
103
        arrays for later uses and get the proper parameters
Unknown's avatar
Unknown committed
104
        """
105
106
107
108
109
        if not h5_path:
            h5_path = pg.FileDialog.getOpenFileName(caption='Select H5 file',
                                                    filter="H5 file (*.h5)")
            h5_path = str(h5_path)
        data_guess, data_results, xvec, xvec_labs, data_parts, ndims, data_main, freq_vec = readData(h5_path)
Unknown's avatar
Unknown committed
110

111
        num_cycles = data_guess.shape[1]
Unknown's avatar
Unknown committed
112
113
114

        y_labs = np.array([['Amplitude', 'V'], ['Frequency', 'Hz'], ['Q Factor', ''], ['Phase', 'rad']])

Unknown's avatar
Unknown committed
115
        # The following should ALL be derived from the file in question via PySPM!!
116
        plot_elements = [['Amplitude [V]', np.abs], ['Phase [rad]', np.angle]]
Unknown's avatar
Unknown committed
117
118
119
120

        initialPars = {'Number of Cycles': num_cycles,
                       'Type of Measurement:': 'IV',
                       'xlabel': xvec_labs,
121
                       'ylabel': y_labs,
Unknown's avatar
Unknown committed
122
123
124
                       'Plot Elements': plot_elements,
                       'Pieces': data_parts,
                       'NDims': ndims}
125
126
127
128
129
130
131
132
        '''
        Set up the plots using the read data
        '''
        self.__setupPlots(initialPars)
        '''
        Set the initial data
        '''
        self.__setInitialData(data_guess, data_results, xvec, data_main, freq_vec)
Unknown's avatar
Unknown committed
133
134

    def __setupPlots(self, initialPars, **kwargs):
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
        """
        This function sets up the GUI layout, adding PyQT widgets
        Fills the layout with objects, sets an roi to crosshair.
        
        Input: 
            initialParameters -- Dictionary,  
                                 Dictionary containing parameters of 
                                 data file, needed for GUI setup.
            winTitle -- string, Optional 
                        Title of QWindow, default = 'Window'.None
            
        Output:  
            None
            
        Shared Objects:
            imv1 -- QtGui.ImageView
                    Item which is used to plot the map of the SHO values at 
                    a given step
            imv2 -- QtGui.PlotWidget
                    Item which is used to plot the current loop selected by 
                    the CrossHairsRoi from imv1
            imv3 -- QtGui.PlotWidget
                    Item which is used to plot the DC offset or AC Amplitude 
                    vs. step number
            roiPt -- pg.CrossHairROI
                    ROI object within imv1 which determines the position used 
                    to generate the loop in imv2
            roi1 -- pg.ROI
                    Standard ROI object within imv1
            posLine -- pt.InfiniteLine
                    Object in imv3 which is used to denote the current UDVS 
                    step.  It's position is sinced with the frame number in 
                    imv1
            cycle_list -- QtGui.ComboBox
                    Object which allows the user to select which cycle to 
                    display
            plot_list -- QtGui.ComboBox
                    Object which allows the used to select which of the SHO 
                    parameters to plot
            roi_list -- QtGui.ComboBox
                    Object which allows the user to change the x-variable in 
                    imv2 from Voltage/Current to UDVS step
            part_list -- QtGuiComboBox
                    Object which allows the user to select between in or 
                    out-of-field for DC and forward or reverse for AC
            xlabel -- Numpy Array
                    Array holding (Name,Unit) pairs of options for the x-axis 
                    of imv2
            ylabel -- Numpy Array
                    Array holding (Name,Unit) pairs of options for the y-axis 
                    of imv2
            ndims -- Int
                    Number of spacial dimensions in data
        """
Unknown's avatar
Unknown committed
189
        #         Get the relevant parameters to enable plotting, labels etc.
190
        num_of_cycles = initialPars['Number of Cycles']
Unknown's avatar
Unknown committed
191
        ylabel = initialPars['ylabel']  # This has to change!
192
193
194
195
        xlabel = initialPars['xlabel']
        plot_elements_list = initialPars['Plot Elements']
        data_part_list = initialPars['Pieces']
        Ndims = initialPars['NDims']
Unknown's avatar
Unknown committed
196
197

        roi_elements_list = xlabel[:, 0]
198
199
        '''
        Setup the layout for the window
Unknown's avatar
Unknown committed
200
201
202
203
        '''
        cw = QtGui.QWidget()  # Add the plotting widget
        self.setCentralWidget(cw)  # What does this do?
        l = QtGui.QGridLayout()  # Use a layout
204
        cw.setLayout(l)
Unknown's avatar
Unknown committed
205

206
207
208
        '''
        Create the Image and plot widgets
        '''
Unknown's avatar
Unknown committed
209
210
        if Ndims == 1:
            imv1, imv2, imv3 = self.__setupOneD(xlabel, ylabel)
211
        else:
Unknown's avatar
Unknown committed
212
213
            imv1, imv2, imv3 = self.__setupTwoD(xlabel, ylabel)

214
215
        '''
        Create combo boxes
Unknown's avatar
Unknown committed
216
217
218
219
220
221
        '''
        cycle_list = QtGui.QComboBox()  # Make a combo box for selecting cycle number
        plot_list = QtGui.QComboBox()  # Make a combo box for selecting what variable to plot
        roi_list = QtGui.QComboBox()  # Choose between plotting versus voltage or step number
        part_list = QtGui.QComboBox()  # Choose the field or direction

222
223
224
225
226
227
        func_list = []
        '''
        Now populate them
        '''
        for i in xrange(num_of_cycles):
            cycle_list.addItem("Cycle " + str(i))
Unknown's avatar
Unknown committed
228
229

        for plot_element in plot_elements_list:
230
231
            plot_list.addItem(plot_element[0])
            func_list.append(plot_element[1])
Unknown's avatar
Unknown committed
232

233
234
        for roi_element in roi_elements_list:
            roi_list.addItem(roi_element)
Unknown's avatar
Unknown committed
235

236
237
        for part in data_part_list:
            part_list.addItem(part)
Unknown's avatar
Unknown committed
238

239
240
241
242
243
        glab = QtGui.QLabel('SHO Guess Parameters')
        g0lab = QtGui.QLabel('Amp: {}'.format('-'))
        g1lab = QtGui.QLabel('w0: {}'.format('-'))
        g2lab = QtGui.QLabel('Q: {}'.format('-'))
        g3lab = QtGui.QLabel('Phase: {}'.format('-'))
Unknown's avatar
Unknown committed
244

245
246
247
248
249
        rlab = QtGui.QLabel('SHO Result Parameters')
        r0lab = QtGui.QLabel('Amp: {}'.format('-'))
        r1lab = QtGui.QLabel('w0: {}'.format('-'))
        r2lab = QtGui.QLabel('Q: {}'.format('-'))
        r3lab = QtGui.QLabel('Phase: {}'.format('-'))
Unknown's avatar
Unknown committed
250

251
252
253
254
255
        '''
        Add the widgets to the layout
        
        addWidget(WidgetName, Row,Col, RowSpan,ColSpan) 
        '''
Unknown's avatar
Unknown committed
256
257
258
        l.addWidget(imv1, 0, 0, 13, 5)  # Add them at these positions
        l.addWidget(imv2, 0, 5, 13, 5)
        l.addWidget(imv3, 14, 0, 2, 10)
259
260
261
        l.addWidget(cycle_list, 0, 10)
        l.addWidget(plot_list, 1, 10)
        l.addWidget(roi_list, 2, 10)
Unknown's avatar
Unknown committed
262
        l.addWidget(part_list, 3, 10)
263
        l.addWidget(glab, 4, 10)
Unknown's avatar
Unknown committed
264
265
266
267
268
269
270
271
272
273
        l.addWidget(g0lab, 5, 10)
        l.addWidget(g1lab, 6, 10)
        l.addWidget(g2lab, 7, 10)
        l.addWidget(g3lab, 8, 10)
        l.addWidget(rlab, 9, 10)
        l.addWidget(r0lab, 10, 10)
        l.addWidget(r1lab, 11, 10)
        l.addWidget(r2lab, 12, 10)
        l.addWidget(r3lab, 13, 10)

274
275
276
        '''
        Customize the Voltage/Current vs time plot
        '''
Unknown's avatar
Unknown committed
277
278
279
280
        imv3.setMaximumHeight(150)  # Don't want this to be too big
        imv3.getPlotItem().setLabel('left', text=ylabel[0, 0], units=ylabel[0, 1])
        imv3.getPlotItem().setLabel('bottom', text=xlabel[1, 0], units=xlabel[1, 1])
        imv3.getViewBox().setMouseEnabled(x=False, y=False)
281
282
283
        posLine = pg.InfiniteLine(angle=90, movable=True, pen='g')
        imv3.addItem(posLine)
        posLine.setValue(0)
Unknown's avatar
Unknown committed
284
285
        posLine.setZValue(100)

286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
        '''
        Share variables we'll need for later
        '''
        self.ndims = Ndims
        self.imv1 = imv1
        self.imv2 = imv2
        self.imv3 = imv3
        self.posLine = posLine
        self.cycle_list = cycle_list
        self.plot_list = plot_list
        self.roi_list = roi_list
        self.part_list = part_list
        self.xlabel = xlabel
        self.ylabel = ylabel
        self.func_list = func_list
        self.func = func_list[0]
Unknown's avatar
Unknown committed
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
        self.glabs = [g0lab, g1lab, g2lab, g3lab]
        self.rlabs = [r0lab, r1lab, r2lab, r3lab]

        return

    #     def rawSpectViewFunc(self,initialPars, **kwargs):
    #         """
    #         This function sets up the GUI layout, adding PyQT widgets
    #         Makes a QWindow, fills it with ImageView objects, sets an roi to line.
    #         Allows viewing of raw spectrograms
    #         Input:
    #             initialParameters Dictionary,
    #                     Dictionary containing parameters of data file, needed for GUI setup.
    #             winTitle: string, Optional
    #                     Title of QWindow, default = 'Window'.None
    #
    #         Output:  QtGui.QMainWindow, PyQtGraph.ImageView,  PyQtGraph.ImageView, PyQtGraph.ROI
    #
    #         """
    #
    #         #Get the relevant parameters to enable plotting, labels etc.
    #         #Make QtWindow, populate it with ImageView and add roi.
    #         win = QtGui.QMainWindow()
    #         cw = QtGui.QWidget() #Add the plotting widget
    #         win.setCentralWidget(cw) #What does this do?
    #         l = QtGui.QGridLayout() #Use a layout
    #         cw.setLayout(l)
    #         imv1 = pg.ImageView() #Make an ImageView widget.
    #
    #         return win, imv1
332

Unknown's avatar
Unknown committed
333
334
335
    @staticmethod
    def __setupOneD(xlabel, ylabel):
        """
336
        Creates the needed widgets for plotting 1D data
Unknown's avatar
Unknown committed
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355

        Parameters
        ----------
        xlabel : list of str
            list of labels and units to use for x-axis of plots
        ylabel : list of str
            list of labels and units to use for y-axis of plots

        Returns
        -------
        imv1 : pyqtgraph.PlotWidget
            PlotWidget in which the value vs Position will be plotted
        imv2 : pyqtgraph.PlotWidget
            PlotWidget in which the loops will be plotted
        imv3 : pyqtgraph.PlotWidget
            PlotWidget in which the timeline will be plotted

        """

356
357
358
        imv1 = pg.PlotWidget()
        imv2 = pg.PlotWidget()
        imv3 = pg.PlotWidget()
Unknown's avatar
Unknown committed
359

360
361
362
        '''
        Setup all the labeling
        '''
Unknown's avatar
Unknown committed
363
364
365
        imv1.setTitle('Plot of {} vs Frequency Bin'.format(ylabel[0, 0]))
        imv1.setLabel('left', text=ylabel[0, 0], units=ylabel[0, 1])
        imv1.setLabel('bottom', text='Frequency Bin')
366
367
368
369

        '''
        Customize Spectra graph labels and plotting    
        '''
Unknown's avatar
Unknown committed
370
371
        imv2.setLabel('left', text=ylabel[0, 0], units=ylabel[0, 1])
        imv2.setLabel('bottom', text=xlabel[0, 0], units=xlabel[0, 1])
372
373
374

        return imv1, imv2, imv3

Unknown's avatar
Unknown committed
375
    def __setupTwoD(self, xlabel, ylabel):
Unknown's avatar
Unknown committed
376
        """
377
        Creates the needed widgets for plotting 1D data
Unknown's avatar
Unknown committed
378

379
380
381
        Inputs:
            xlabel -- list of labels and units to use for x-axis of plots
            ylabel -- list of labels and units to use for y-axis of plots
Unknown's avatar
Unknown committed
382

383
384
385
386
        Outputs:
            imv1 -- ImageView Widget in which the map will be plotted
            imv2 -- PlotWidget in which the loops will be plotted
            imv3 -- PlotWidget in which the timeline will be plotted
Unknown's avatar
Unknown committed
387

388
        Shared:
Unknown's avatar
Unknown committed
389
            plt1 -- PlotItem associated with the map to show position axes
390
                    and the title
Unknown's avatar
Unknown committed
391
            roi1 -- The crosshairs roi object that determines the position for
392
393
                    which the loops are plotted in imv2
            roiplt1 -- The box roi object associated with imv1
Unknown's avatar
Unknown committed
394
395
            posline -- the
        """
396
397
398
        plt1 = pg.PlotItem()
        imv1 = pg.ImageView(view=plt1)
        imv2 = pg.PlotWidget()
Unknown's avatar
Unknown committed
399
        imv3 = pg.PlotWidget()
400
401
402
403

        '''
        Prevent map from being to small and add the crosshair ROI
        '''
Unknown's avatar
Unknown committed
404
405
406
        imv1.setMinimumSize(500, 500)
        plt1.setTitle('Map of {} vs Position'.format(ylabel[0, 0]))
        roiPt = pg.CrosshairROI([0, 0], size=2, pen='b')  # Add a cross-hair ROI item
407
408
        imv1.addItem(roiPt)
        grad1 = imv1.ui.histogram.gradient
Unknown's avatar
Unknown committed
409
410
        #         grad1.loadPreset('thermal') #choose the default colormap from presets
        grad1.restoreState(self.jet)  # Set default colormap defined in __init__
411
412
413
414
415
416
417
        imv1.getView().setMouseEnabled(x=False, y=False)
        imv1.ui.menuBtn.hide()

        '''
        Customize Spectra graph labels and plotting    
        '''
        imv2.setTitle('Loop for Position {}'.format(roiPt.pos()))
Unknown's avatar
Unknown committed
418
419
420
        imv2.setLabel('left', text=ylabel[0, 0], units=ylabel[0, 1])
        imv2.setLabel('bottom', text=xlabel[0, 0], units=xlabel[0, 1])

421
422
423
424
        '''
        Customize ROI plot window
        '''
        roiplt1 = imv1.getRoiPlot().getPlotItem()
Unknown's avatar
Unknown committed
425
426
427
        roiplt1.setLabel('left', text=ylabel[0, 0], units=ylabel[0, 1])
        roiplt1.setLabel('bottom', text=xlabel[0, 0], units=xlabel[0, 1])

428
429
430
        '''
        Share variables unique to 2D mode
        '''
Unknown's avatar
Unknown committed
431
432
        self.plt1 = plt1
        self.roi1 = roiplt1
433
434
435
436
        self.roiPt = roiPt

        return imv1, imv2, imv3

Unknown's avatar
Unknown committed
437
    def __setInitialData(self, data_guess, data_results, xvec, data_main, freq_vec):
Unknown's avatar
Unknown committed
438
        """
439
        Tell the window what data it should be plotting from
Unknown's avatar
Unknown committed
440
        """
Unknown's avatar
Unknown committed
441
        points = np.arange(len(xvec[0, 0, 0, :]) + 1)
442
        self.num_bins = len(freq_vec)
Unknown's avatar
Unknown committed
443

444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
        if self.ndims == 1:
            self.__setDataOneD(data_guess, data_results, xvec, data_main, freq_vec, points)
        else:
            self.__setDataTwoD(data_guess, data_results, xvec, data_main, freq_vec, points)

        '''
        Initialize all shared selectors
        '''
        self.data_guess = data_guess
        self.data_results = data_results
        self.data_main = data_main
        self.freq_vec = freq_vec
        self.xvec = xvec
        self.points = points
        self.sel_frame = self.imv1.currentIndex
        self.sel_cycle = self.cycle_list.currentIndex()
        self.sel_plot = self.plot_list.currentIndex()
        self.plot_name = str(self.plot_list.currentText())
        self.sel_roi = self.roi_list.currentIndex()
        self.sel_part = self.part_list.currentIndex()
Unknown's avatar
Unknown committed
464

465
466
        return

Unknown's avatar
Unknown committed
467
    def __setDataOneD(self, data_guess, data_results, xvec, data_main, freq_vec, points):
Unknown's avatar
Unknown committed
468
        """
469
470
        Sets the initial data for the case of one spacial dimension
        Inputs:
Unknown's avatar
Unknown committed
471
            data_guess -- 6D numpy array holding BEPS data.
472
473
474
475
476
477
                        Indices are:
                        [Field, SHO, Cycle #, UDVS Step, X-Pos, Y-Pos]

                    Field:  "In-field" or "Out-of-field" for DC
                            "Forward" or "Reverse" for AC
                    SHO:    SHO parameter to be plotted
Unknown's avatar
Unknown committed
478
                            Amplitude, Resonance Frequency, Q-factor, Phase,
479
480
481
482
483
484
                            or R^2 value
                    Cycle:  Which cycle should be plotted
                    UDVS:   The UDVS step of the current plot
                    X-Pos:  X position from dataset
                    Y-Pos:  Y position from dataset

Unknown's avatar
Unknown committed
485
                        These indices should be present for all datasets
486
                        even if they only have a length of 1
Unknown's avatar
Unknown committed
487
488

             xvec -- 4D numpy array containing the values which will be plotted
489
490
491
                     against
                     Indices are
                     [Variable, Field, Cycle #, UDVS Step]
Unknown's avatar
Unknown committed
492
493

                     As with datamat, all indices must be present no matter
494
                     the shape of the actual data
Unknown's avatar
Unknown committed
495
496

                Variable:   The variable to be plotted.  DC voltage or
497
498
499
500
                            AC amplitude depending on the mode
                Field:      Same as is datamat
                Cycle #:    Same as in datamat
                UDVS Step:  Same as in datamat
Unknown's avatar
Unknown committed
501
502
503
504

            points -- numpy arrange of UDVS step numbers.  One extra step is
                      added at the end to allow for plotting in step mode
        """
Unknown's avatar
Unknown committed
505

506
507
508
509
        '''
        Plot Initial data
        '''
        positions = np.arange(data_guess.shape[3])
Unknown's avatar
Unknown committed
510
511
512
        self.plot1 = self.imv1.plot(x=positions,
                                    y=data_guess[0, 0, 0, :, 0],
                                    pen='k')
513
514
515
516
517
518
        self.imv1.currentIndex = 0
        roiPt = pg.InfiniteLine(angle=90, movable=True, pen='r')
        self.imv1.addItem(roiPt)
        self.roiPt = roiPt
        self.roiPt.setPos(0)
        self.point_roi = self.__getROIpos()
Unknown's avatar
Unknown committed
519
520
        self.roiPt.setBounds((positions[0], positions[-1]))

521
522
        self.row = int(self.point_roi[0])
        self.col = int(self.point_roi[1])
Unknown's avatar
Unknown committed
523

524
        self.main_plot = pg.PlotDataItem(x=np.arange(self.num_bins),
Unknown's avatar
Unknown committed
525
526
527
528
                                         y=self.func(data_main[0, 0, :, 0, 0]),
                                         pen='g')
        self.guess = self.__calc_sho(data_guess[0, 0, 0, 0, 0], freq_vec)
        self.guess_plot = pg.PlotDataItem(x=np.arange(self.num_bins),
529
                                          y=self.func(self.guess),
Unknown's avatar
Unknown committed
530
531
                                          pen='k')

532
533
        self.imv2.addItem(self.main_plot)
        self.imv2.addItem(self.guess_plot)
Unknown's avatar
Unknown committed
534

535
        if data_results is not None:
Unknown's avatar
Unknown committed
536
            self.results = self.__calc_sho(data_results[0, 0, 0, 0, 0], freq_vec)
537
538
            self.results_plot = pg.PlotDataItem(x=np.arange(self.num_bins),
                                                y=self.func(self.results),
Unknown's avatar
Unknown committed
539
                                                pen='r')
540
541
542
543
544
            self.imv2.addItem(self.results_plot)
        else:
            self.results = None
            self.results_plot = None

Unknown's avatar
Unknown committed
545
546
547
        self.imv2.setTitle('Loop for Position {}'.format(self.point_roi))

        self.imv3.plot(points, xvec[0, 0, 0, :],
548
                       stepMode=True,
Unknown's avatar
Unknown committed
549
550
551
552
                       pen='k')
        self.posLine.setBounds([points[0], points[-2]])

    def __setDataTwoD(self, data_mat, data_results, xvec, data_main, freq_vec, points):
Unknown's avatar
Unknown committed
553
        """
554
        Sets the initial data for the case of two spacial dimensions
Unknown's avatar
Unknown committed
555

556
        Inputs:
Unknown's avatar
Unknown committed
557
            data_guess -- 6D numpy array holding BEPS data.
558
559
560
561
562
563
                        Indices are:
                        [Field, SHO, Cycle #, UDVS Step, X-Pos, Y-Pos]

                    Field:  "In-field" or "Out-of-field" for DC
                            "Forward" or "Reverse" for AC
                    SHO:    SHO parameter to be plotted
Unknown's avatar
Unknown committed
564
                            Amplitude, Resonance Frequency, Q-factor, Phase,
565
566
567
568
569
570
                            or R^2 value
                    Cycle:  Which cycle should be plotted
                    UDVS:   The UDVS step of the current plot
                    X-Pos:  X position from dataset
                    Y-Pos:  Y position from dataset

Unknown's avatar
Unknown committed
571
                        These indices should be present for all datasets
572
                        even if they only have a length of 1
Unknown's avatar
Unknown committed
573
574

             xvec -- 4D numpy array containing the values which will be plotted
575
576
577
                     against
                     Indices are
                     [Variable, Field, Cycle #, UDVS Step]
Unknown's avatar
Unknown committed
578
579

                     As with datamat, all indices must be present no matter
580
                     the shape of the actual data
Unknown's avatar
Unknown committed
581
582

                Variable:   The variable to be plotted.  DC voltage or
583
584
585
586
                            AC amplitude depending on the mode
                Field:      Same as is datamat
                Cycle #:    Same as in datamat
                UDVS Step:  Same as in datamat
Unknown's avatar
Unknown committed
587
588

            points -- numpy arrange of UDVS step numbers.  One extra step is
589
                      added at the end to allow for plotting in step mode
Unknown's avatar
Unknown committed
590
        """
Unknown's avatar
Unknown committed
591

592
593
594
        '''
        Plot Initial data
        '''
Unknown's avatar
Unknown committed
595
596
        self.imv1.setImage(data_mat['Amplitude [V]'][0, 0, :, :, :],
                           xvals=xvec[0, 0, 0, :])
597
598
599
600
        self.plt1.getViewBox().autoRange(padding=0.1)
        '''
        Prevent the selection of a point from outside the domain
        '''
Unknown's avatar
Unknown committed
601
        self.roiPt.maxBounds = self.imv1.getImageItem().boundingRect()
602
        roisize = self.roiPt.size()
Unknown's avatar
Unknown committed
603
604
605
606
        self.roiPt.maxBounds.adjust(0, 0, roisize[0] / 2, roisize[1] / 2)

        self.point_roi = self.__getROIpos()  # Get position

607
608
        self.row = int(self.point_roi[0])
        self.col = int(self.point_roi[1])
Unknown's avatar
Unknown committed
609

610
        self.main_plot = pg.PlotDataItem(x=np.arange(self.num_bins),
Unknown's avatar
Unknown committed
611
612
613
614
                                         y=self.func(data_main[0, 0, 0, :, 0, 0]),
                                         pen='g')
        self.guess = self.__calc_sho(data_mat[0, 0, 0, 0, 0], freq_vec)
        self.guess_plot = pg.PlotDataItem(x=np.arange(self.num_bins),
615
                                          y=self.func(self.guess),
Unknown's avatar
Unknown committed
616
617
                                          pen='k')

618
619
620
621
        self.imv2.addItem(self.main_plot)
        self.imv2.addItem(self.guess_plot)

        if data_results is not None:
Unknown's avatar
Unknown committed
622
            self.results = self.__calc_sho(data_results[0, 0, 0, 0, 0], freq_vec)
623
624
            self.results_plot = pg.PlotDataItem(x=np.arange(self.num_bins),
                                                y=self.func(self.results),
Unknown's avatar
Unknown committed
625
                                                pen='r')
626
627
628
            self.imv2.addItem(self.results_plot)
        else:
            self.results = None
Unknown's avatar
Unknown committed
629
630
631
            self.results_plot = None

        self.imv3.plot(points, xvec[0, 0, 0, :],
632
633
634
635
                       stepMode=True,
                       pen='k')
        self.posLine.setBounds([points[0],
                                points[-2]])
Unknown's avatar
Unknown committed
636

637
        self.point_roi = self.__getROIpos()
Unknown's avatar
Unknown committed
638

639
    def __getROIpos(self):
Unknown's avatar
Unknown committed
640
        """
641
        Returns the current position of the ROI selector
Unknown's avatar
Unknown committed
642
        """
643
644
        roipos = self.roiPt.pos()
        if self.ndims == 1:
Unknown's avatar
Unknown committed
645
            for i in xrange(1, len(roipos)):
646
647
                roipos[i] = 0
        return roipos
Unknown's avatar
Unknown committed
648

649
    def setSignals(self):
Unknown's avatar
Unknown committed
650
651
        """
        Define the signals to be watched and how they connect to
652
        update functions
Unknown's avatar
Unknown committed
653
        """
654
        if self.ndims > 1:
Unknown's avatar
Unknown committed
655
            self.roiPt.sigRegionChanged.connect(self.updateROICross)  # Link roi changes to update function
656
657
            self.imv1.timeLine.sigPositionChanged.connect(self.updateTimeMap)
        else:
Unknown's avatar
Unknown committed
658
            self.roiPt.sigPositionChanged.connect(self.updateROICross)  # Link roi changes to update function
659
        self.posLine.sigPositionChanged.connect(self.updateTimeLine)
Unknown's avatar
Unknown committed
660
661
662
        self.cycle_list.activated[str].connect(self.updateCycleList)  # Link cycle changes to update function
        self.plot_list.activated[str].connect(self.updatePlotList)  # Link plot variable changes to update function
        self.roi_list.activated[str].connect(self.updateROIList)  # Link ROI variable changes to update function
663
664
        self.part_list.activated[str].connect(self.updatePartList)
        self.guess_plot.sigPlotChanged.connect(self.updateParms)
Unknown's avatar
Unknown committed
665
666

    #     Update functions for interactivity
667
    def updateCycleList(self):
Unknown's avatar
Unknown committed
668
        """
669
        Save the current frame
Unknown's avatar
Unknown committed
670
        """
671
        current_frame = self.sel_frame
Unknown's avatar
Unknown committed
672

673
674
675
676
677
678
679
680
681
        '''
        Get the new cycle
        '''
        self.sel_cycle = self.cycle_list.currentIndex()

        '''
        Replot everything
        '''
        if self.ndims > 1:
Unknown's avatar
Unknown committed
682
683
684
685
            self.imv1.setImage(self.data_guess[self.plot_name][self.sel_part, self.sel_cycle, :, :, :],
                               xvals=self.xvec[self.sel_roi,
                                     self.sel_part,
                                     self.sel_cycle, :],
686
                               autoHistogramRange=True)
Unknown's avatar
Unknown committed
687

688
689
        else:
            self.plot1.setData(y=self.data_guess[self.plot_name][self.sel_part,
Unknown's avatar
Unknown committed
690
691
692
                                 self.sel_cycle,
                                 self.sel_frame, :, 0])

693
        self.main_plot.setData(y=self.func(self.data_main[self.sel_part,
Unknown's avatar
Unknown committed
694
695
696
697
                                           self.sel_cycle,
                                           self.sel_frame, :,
                                           self.row,
                                           self.col]))
698
        self.guess = self.__calc_sho(self.data_guess[self.sel_part,
Unknown's avatar
Unknown committed
699
700
701
702
703
704
705
                                                     self.sel_cycle,
                                                     self.sel_frame,
                                                     self.row,
                                                     self.col],
                                     self.freq_vec)
        self.guess_plot.setData(y=self.func(self.guess))

706
707
        if self.results is not None:
            self.results = self.__calc_sho(self.data_results[self.sel_part,
Unknown's avatar
Unknown committed
708
709
710
711
712
                                                             self.sel_cycle,
                                                             self.sel_frame,
                                                             self.row,
                                                             self.col],
                                           self.freq_vec)
713
            self.results_plot.setData(y=self.func(self.results))
Unknown's avatar
Unknown committed
714

715
716
717
718
719
720
721
        '''
        Set the selected frame to the current frame
        '''
        self.sel_frame = current_frame
        if self.ndims > 1:
            self.imv1.setCurrentIndex(self.sel_frame)
        self.posLine.setPos(self.sel_frame)
Unknown's avatar
Unknown committed
722

723
    def updatePlotList(self):
Unknown's avatar
Unknown committed
724
        """
725
        Save the current frame
Unknown's avatar
Unknown committed
726
        """
727
        current_frame = self.sel_frame
Unknown's avatar
Unknown committed
728

729
730
731
732
733
734
        '''
        Get the new plot selection and update Map
        '''
        self.sel_plot = self.plot_list.currentIndex()
        self.plot_name = str(self.plot_list.currentText())
        self.func = self.func_list[self.sel_plot]
Unknown's avatar
Unknown committed
735

736
737
        if self.ndims > 1:
            self.imv1.setImage(self.data_guess[self.plot_name][self.sel_part,
Unknown's avatar
Unknown committed
738
739
740
741
                               self.sel_cycle, :, :, :],
                               xvals=self.xvec[self.sel_roi,
                                     self.sel_part,
                                     self.sel_cycle, :],
742
                               autoHistogramRange=True)
Unknown's avatar
Unknown committed
743
744
745
746
747
            self.plt1.setTitle('Map of {} vs Position'.format(self.ylabel[self.sel_plot, 0]))

            self.roi1.setLabel('left',
                               text=self.ylabel[self.sel_plot, 0],
                               units=self.ylabel[self.sel_plot, 1])
748
749
        else:
            self.plot1.setData(y=self.data_guess[self.plot_name][self.sel_part,
Unknown's avatar
Unknown committed
750
751
752
753
754
                                 self.sel_cycle,
                                 self.sel_frame, :, 0])
            self.imv1.setTitle('Plot of {} vs {}'.format(self.ylabel[self.sel_plot, 0],
                                                         self.xlabel[self.sel_roi, 0]))

755
        self.main_plot.setData(y=self.func(self.data_main[self.sel_part,
Unknown's avatar
Unknown committed
756
757
758
759
                                           self.sel_cycle,
                                           self.sel_frame, :,
                                           self.row,
                                           self.col]))
760
        self.guess = self.__calc_sho(self.data_guess[self.sel_part,
Unknown's avatar
Unknown committed
761
762
763
764
765
766
767
768
769
                                                     self.sel_cycle,
                                                     self.sel_frame,
                                                     self.row,
                                                     self.col],
                                     self.freq_vec)
        self.guess_plot.setData(y=self.func(self.guess))
        self.imv2.setLabel('left',
                           text=self.ylabel[self.sel_plot, 0],
                           units=self.ylabel[self.sel_plot, 1])
770
771
772

        if self.results is not None:
            self.results = self.__calc_sho(self.data_results[self.sel_part,
Unknown's avatar
Unknown committed
773
774
775
776
777
                                                             self.sel_cycle,
                                                             self.sel_frame,
                                                             self.row,
                                                             self.col],
                                           self.freq_vec)
778
            self.results_plot.setData(y=self.func(self.results))
Unknown's avatar
Unknown committed
779

780
781
782
783
784
785
786
        '''
        Set the selected frame to the current frame
        '''
        self.sel_frame = current_frame
        if self.ndims > 1:
            self.imv1.setCurrentIndex(self.sel_frame)
        self.posLine.setPos(self.sel_frame)
Unknown's avatar
Unknown committed
787

788
    def updateROIList(self):
Unknown's avatar
Unknown committed
789
        """
790
        Save the current frame
Unknown's avatar
Unknown committed
791
        """
792
        current_frame = self.sel_frame
Unknown's avatar
Unknown committed
793

794
795
796
797
        '''
        Get the new choice of ROI variable from the list and update plots
        '''
        self.sel_roi = self.roi_list.currentIndex()
Unknown's avatar
Unknown committed
798

799
800
        if self.ndims > 1:
            self.imv1.setImage(self.data_guess[self.plot_name][self.sel_part,
Unknown's avatar
Unknown committed
801
802
803
804
                               self.sel_cycle, :, :, :],
                               xvals=self.xvec[self.sel_roi,
                                     self.sel_part,
                                     self.sel_cycle, :],
805
806
                               autoHistogramRange=True)

Unknown's avatar
Unknown committed
807
808
809
810
            self.roi1.setLabel('bottom',
                               text=self.xlabel[self.sel_roi, 0],
                               units=self.xlabel[self.sel_roi, 1])

811
        self.main_plot.setData(y=self.func(self.data_main[self.sel_part,
Unknown's avatar
Unknown committed
812
813
814
815
                                           self.sel_cycle,
                                           self.sel_frame, :,
                                           self.row,
                                           self.col]))
816
        self.guess = self.__calc_sho(self.data_guess[self.sel_part,
Unknown's avatar
Unknown committed
817
818
819
820
821
                                                     self.sel_cycle,
                                                     self.sel_frame,
                                                     self.row,
                                                     self.col],
                                     self.freq_vec)
822
        self.guess_plot.setData(y=self.func(self.guess))
Unknown's avatar
Unknown committed
823

824
825
        if self.results is not None:
            self.results = self.__calc_sho(self.data_results[self.sel_part,
Unknown's avatar
Unknown committed
826
827
828
829
830
831
832
833
834
835
836
                                                             self.sel_cycle,
                                                             self.sel_frame,
                                                             self.row,
                                                             self.col],
                                           self.freq_vec)
            self.results_plot.setData(y=self.func(self.results))

        self.imv2.setLabel('bottom',
                           text=self.xlabel[self.sel_roi, 0],
                           units=self.xlabel[self.sel_roi, 1])

837
838
839
840
        '''
        Set the selected frame to the current frame
        '''
        self.sel_frame = current_frame
Unknown's avatar
Unknown committed
841
        if self.ndims > 1:
842
843
            self.imv1.setCurrentIndex(self.sel_frame)
        self.posLine.setPos(self.sel_frame)
Unknown's avatar
Unknown committed
844

845
    def updatePartList(self):
Unknown's avatar
Unknown committed
846
        """
847
        Save the current frame
Unknown's avatar
Unknown committed
848
        """
849
        current_frame = self.sel_frame
Unknown's avatar
Unknown committed
850

851
852
853
854
855
856
        '''
        Get the new part variable and update plots
        
        The part variable is the Field for DC and the direction for AC
        '''
        self.sel_part = self.part_list.currentIndex()
Unknown's avatar
Unknown committed
857

858
859
        if self.ndims > 1:
            self.imv1.setImage(self.data_guess[self.plot_name][self.sel_part,
Unknown's avatar
Unknown committed
860
861
862
863
                               self.sel_cycle, :, :, :],
                               xvals=self.xvec[self.sel_roi,
                                     self.sel_part,
                                     self.sel_cycle, :],
864
865
866
                               autoHistogramRange=True)
        else:
            self.plot1.setData(y=self.data_guess[self.plot_name][self.sel_part,
Unknown's avatar
Unknown committed
867
868
869
                                 self.sel_cycle,
                                 self.sel_frame, :, 0])

870
        self.main_plot.setData(y=self.func(self.data_main[self.sel_part,
Unknown's avatar
Unknown committed
871
872
873
874
                                           self.sel_cycle,
                                           self.sel_frame, :,
                                           self.row,
                                           self.col]))
875
        self.guess = self.__calc_sho(self.data_guess[self.sel_part,
Unknown's avatar
Unknown committed
876
877
878
879
880
881
882
                                                     self.sel_cycle,
                                                     self.sel_frame,
                                                     self.row,
                                                     self.col],
                                     self.freq_vec)
        self.guess_plot.setData(y=self.func(self.guess))

883
884
        if self.results is not None:
            self.results = self.__calc_sho(self.data_results[self.sel_part,
Unknown's avatar
Unknown committed
885
886
887
888
889
890
891
                                                             self.sel_cycle,
                                                             self.sel_frame,
                                                             self.row,
                                                             self.col],
                                           self.freq_vec)
            self.results_plot.setData(y=self.func(self.results))

892
893
894
895
896
897
898
        '''
        Set the selected frame to the current frame
        '''
        if self.ndims > 1:
            self.sel_frame = current_frame
            self.imv1.setCurrentIndex(self.sel_frame)
        self.posLine.setPos(self.sel_frame)
Unknown's avatar
Unknown committed
899

900
    def updateROICross(self):
Unknown's avatar
Unknown committed
901
        """
902
        Get the new roi position and update the loop plot accordingly
Unknown's avatar
Unknown committed
903
        """
904
905
906
907
908
909
910
        self.point_roi = self.__getROIpos()

        self.row = int(self.point_roi[0])
        self.col = int(self.point_roi[1])

        self.main_plot.setData(x=np.arange(self.num_bins),
                               y=self.func(self.data_main[self.sel_part,
Unknown's avatar
Unknown committed
911
912
913
914
                                           self.sel_cycle,
                                           self.sel_frame, :,
                                           self.row,
                                           self.col]))
915
916
917
918
919
        self.guess = self.__calc_sho(self.data_guess[self.sel_part,
                                                     self.sel_cycle,
                                                     self.sel_frame,
                                                     self.row,
                                                     self.col],
Unknown's avatar
Unknown committed
920
921
922
                                     self.freq_vec)
        self.guess_plot.setData(y=self.func(self.guess))

923
924
925
926
927
928
        if self.results is not None:
            self.results = self.__calc_sho(self.data_results[self.sel_part,
                                                             self.sel_cycle,
                                                             self.sel_frame,
                                                             self.row,
                                                             self.col],
Unknown's avatar
Unknown committed
929
930
931
                                           self.freq_vec)
            self.results_plot.setData(y=self.func(self.results))

932
933
934
        self.imv2.setTitle('SHO for Position {}'.format(self.point_roi))

    def updateTimeMap(self):
Unknown's avatar
Unknown committed
935
        """
936
        Get the new frame index from the map and update timeline
Unknown's avatar
Unknown committed
937
        """
938
939
940
        self.sel_frame = self.imv1.currentIndex

        self.posLine.setPos(self.sel_frame)
Unknown's avatar
Unknown committed
941

942
    def updateTimeLine(self):
Unknown's avatar
Unknown committed
943
944
945
        """
        Get the new frame index from the timeline and update map
        """
946
947
948
        self.sel_frame = int(np.floor(self.posLine.value()))

        if self.ndims == 1:
Unknown's avatar
Unknown committed
949
            self.plot1.setData(y=self.data_guess[self.plot_name][0, 0, self.sel_frame, :, 0])
950
951
        else:
            self.imv1.setCurrentIndex(self.sel_frame)
Unknown's avatar
Unknown committed
952
953
954
955
956
957
958

        self.main_plot.setData(x=np.arange(self.num_bins),
                               y=self.func(self.data_main[self.sel_part,
                                           self.sel_cycle,
                                           self.sel_frame, :,
                                           self.row,
                                           self.col]))
959
        self.guess = self.__calc_sho(self.data_guess[self.sel_part,
Unknown's avatar
Unknown committed
960
961
962
963
964
965
                                                     self.sel_cycle,
                                                     self.sel_frame,
                                                     self.row,
                                                     self.col],
                                     self.freq_vec)
        self.guess_plot.setData(y=self.func(self.guess))
966
967
968

        if self.results is not None:
            self.results = self.__calc_sho(self.data_results[self.sel_part,
Unknown's avatar
Unknown committed
969
970
971
972
973
                                                             self.sel_cycle,
                                                             self.sel_frame,
                                                             self.row,
                                                             self.col],
                                           self.freq_vec)
974
975
976
            self.results_plot.setData(y=self.func(self.results))

    def updateParms(self):
Unknown's avatar
Unknown committed
977
        """
978
        update the values of the parameters printed to the sidebar
Unknown's avatar
Unknown committed
979
        """
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
        gparms = self.data_guess[self.sel_part,
                                 self.sel_cycle,
                                 self.sel_frame,
                                 self.row,
                                 self.col]
        self.glabs[0].setText('Amp: {}'.format(gparms['Amplitude [V]']))
        self.glabs[1].setText('w0: {}'.format(gparms['Frequency [Hz]']))
        self.glabs[2].setText('Q: {}'.format(gparms['Quality Factor']))
        self.glabs[3].setText('Phase: {}'.format(gparms['Phase [rad]']))

        if self.data_results is not None:
            rparms = self.data_results[self.sel_part,
                                       self.sel_cycle,
                                       self.sel_frame,
                                       self.row,
                                       self.col]
            self.rlabs[0].setText('Amp: {}'.format(rparms['Amplitude [V]']))
            self.rlabs[1].setText('w0: {}'.format(rparms['Frequency [Hz]']))
            self.rlabs[2].setText('Q: {}'.format(rparms['Quality Factor']))
            self.rlabs[3].setText('Phase: {}'.format(rparms['Phase [rad]']))