graphtools.py 20.5 KB
Newer Older
Yan's avatar
Yan committed
1
2
from PyQt5 import QtWidgets
from PyQt5 import QtCore
3
4
5
from matplotlib.backends.backend_qt5agg import\
    FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
Yan's avatar
Yan committed
6
from matplotlib.widgets import SpanSelector
Yan's avatar
Yan committed
7
import numpy as np
Yan's avatar
Yan committed
8
import prasopes.datatools as dt
Yan's avatar
Yan committed
9
import prasopes.config as cf
10
import matplotlib
11
matplotlib.use("Qt5Agg")
Yan's avatar
Yan committed
12

Yan's avatar
Yan committed
13

3Yan's avatar
3Yan committed
14
15
16
17
18
colors = np.array([[0, 0, 0], [255, 0, 0], [0, 255, 0], [0, 0, 255],
                   [0, 200, 255], [255, 200, 0], [255, 100, 0],
                   [200, 50, 0], [255, 0, 200], [0, 100, 0],
                   [0, 100, 255], [100, 100, 100]])

19

20
ann_bbox = dict(boxstyle="round", fc="w", ec="0.5", alpha=0.5)
3Yan's avatar
3Yan committed
21

22

23
24
25
26
27
28
class AugFigureCanvas(FigureCanvas):
    """Figure canvas fitted with mass spectrum, chromatogram and more"""
    def __init__(self):
        self.figure = Figure(figsize=(5, 4), dpi=100, facecolor="None",
                             constrained_layout=True)
        super().__init__(self.figure)
Yan's avatar
Yan committed
29
        self.ds = None
30
        self.ms = dict(annotation=[], name="Spectrum", xlabel="m/z",
Yan's avatar
Yan committed
31
                       ylabel="ion count", xtics=20, predict=None, texts=[])
32
33
34
35
36
        self.chrom = dict(
            x=[0], y=[0], t_start=None, t_end=None, machtype=None,
            name="Chromatogram", xlabel="time(min)", ylabel="total ion count",
            timesarg=[])
        self.drlcache = [None, None]
Yan's avatar
Yan committed
37
        self.mdrlcache = [None, None]
Yan's avatar
Yan committed
38
        self.tofcache = [None, None]
Yan's avatar
Yan committed
39
        self.mobontofcache = [None, None]
40
41
42
43
44
45
46
47
48
        grid = self.figure.add_gridspec(2, 1)
        self.chromplot = self.figure.add_subplot(grid[0, 0],
                                                 facecolor=(1, 1, 1, 0.8))
        self.spectplot = self.figure.add_subplot(grid[1, 0],
                                                 facecolor=(1, 1, 1, 0.8))
        self.setStyleSheet("background-color:transparent;")
        self.setAutoFillBackground(False)
        self.paramstable = dt.table(["", "name", "value"], 100)
        pan_factory(self.chromplot)
3Yan's avatar
3Yan committed
49
        zoom_factory(self.chromplot, 0.9)
50
        pan_factory(self.spectplot, self.ms)
3Yan's avatar
3Yan committed
51
        zoom_factory(self.spectplot, 0.9, self.ms)
52
53
54
55
56
57
        textedit_factory(self.spectplot, self.ms)
        self.mass_selector = AugSpanSelector(self.spectplot, self.ms)
        self.time_selector = SpanSelector(
                self.chromplot, lambda x_min, x_max: pick_times(
                    x_min, x_max, self), 'horizontal', useblit=True,
                rectprops=dict(alpha=0.15, facecolor='purple'), button=3)
Yan's avatar
Yan committed
58
59
60
61
62
        self.figure.set_constrained_layout(False)

    def constrained_draw(self):
        self.figure.execute_constrained_layout()
        self.draw()
63
64


Yan's avatar
Yan committed
65
66
class AugSpanSelector(SpanSelector):
    def __init__(self, ax, data):
67
68
69
70
71
        super().__init__(
            ax, onselect=lambda x, y: None, direction='horizontal',
            minspan=0.01, useblit=True, rectprops=dict(
                alpha=0.15, facecolor='purple'),
            onmove_callback=None, span_stays=False, button=3)
Yan's avatar
Yan committed
72
        self.data = data
73

Yan's avatar
Yan committed
74
75
76
77
78
79
80
81
82
83
    def _press(self, event):
        """on button press event override"""
        if QtWidgets.QApplication.keyboardModifiers() ==\
                QtCore.Qt.ShiftModifier:
            self.direction = 'vertical'
            self.onselect = self.pick_intensities
        else:
            self.direction = 'horizontal'
            self.onselect = self.pick_masses
        self.new_axes(self.ax)
84
        super()._press(event)
Yan's avatar
Yan committed
85

86
87
88
89
90
    def _release(self, event):
        """on button release event"""
        if self.pressv is None:
            return
        elif self.direction == 'horizontal':
91
            super()._release(event)
92
93
94
95
96
97
98
99
100
101
102
103
104
105
        else:
            self.rect.set_visible(False)
            self.canvas.draw_idle()
            vmax = self._get_data(event)[1] or self.prev[1]
            span = vmax - self.ax.get_ylim()[0]
            if self.minspan is not None and span < self.minspan:
                return
            self.onselect(self.ax.get_ylim()[0], vmax)
            self.pressv = None
            return False

    def _set_span_xy(self, event):
        """Setting the span coordinates override"""
        if self.direction == 'horizontal':
106
            super()._set_span_xy(event)
107
        else:
108
            x, y = self._get_data(event)
109
110
111
112
113
            if y is None:
                return
            self.prev = x, y
            self.rect.set_y(self.ax.get_ylim()[0])
            self.rect.set_height(y)
Yan's avatar
Yan committed
114
115
116
117
118
119
120
121
122
123
124

    def pick_masses(self, vmin, vmax):
        """zoom the spectrum in x axis by mass range"""
        self.ax.set_xlim(vmin, vmax)
        autozoomy(self.ax)
        ann_spec(self.ax, self.data)

    def pick_intensities(self, vmin, vmax):
        """zoom the spectrum in y axis by top intensity from range"""
        self.ax.set_ylim(-vmax*0.01, vmax)
        ann_spec(self.ax, self.data)
Yan's avatar
Yan committed
125
126


Yan's avatar
Yan committed
127
128
129
class FixedScalarFormatter(matplotlib.ticker.ScalarFormatter):
    def __init__(self):
        super().__init__()
Yan's avatar
Yan committed
130
        self._powerlimits = (0, 0)
Yan's avatar
Yan committed
131
132
133
134
135
136

    def _set_format(self):
        """_set_format override"""
        self.format = "%.2f"


Yan's avatar
Yan committed
137
def zoom_factory(axis, base_scale, plot_data=None):
Yan's avatar
Yan committed
138
    """returns zooming functionality to axis"""
Yan's avatar
Yan committed
139
    def zoom_fun(event, pd, ax, scale):
Yan's avatar
Yan committed
140
        """zoom when scrolling"""
Yan's avatar
Yan committed
141
        if event.inaxes == axis:
3Yan's avatar
3Yan committed
142
            scale_factor = np.power(scale, event.step)
143
            if QtWidgets.QApplication.keyboardModifiers() !=\
Yan's avatar
Yan committed
144
                    QtCore.Qt.ShiftModifier:
145
                data = event.ydata
Yan's avatar
Yan committed
146
147
                new_top = data + (ax.get_ylim()[1] - data) \
                    * scale_factor
Yan's avatar
Yan committed
148
149
150
151
                ymin = -0.01
                if type(pd) is dict and "c_ymin" in pd:
                    ymin = pd['c_ymin']
                axis.set_ylim([new_top * ymin, new_top])
152
153
            else:
                data = event.xdata
Yan's avatar
Yan committed
154
155
                x_left = data - ax.get_xlim()[0]
                x_right = ax.get_xlim()[1] - data
Yan's avatar
Yan committed
156
                ax.set_xlim([data - x_left * scale_factor,
Yan's avatar
Yan committed
157
                            data + x_right * scale_factor])
Yan's avatar
Yan committed
158
            if type(pd) is dict and "annotation" in pd:
Yan's avatar
Yan committed
159
                ann_spec(event.inaxes, pd)
160
            ax.figure.canvas.draw()
Yan's avatar
Yan committed
161

Yan's avatar
Yan committed
162
    fig = axis.get_figure()
163
    fig.canvas.mpl_connect('scroll_event', lambda event: zoom_fun(
3Yan's avatar
3Yan committed
164
        event, plot_data, axis, base_scale))
Yan's avatar
Yan committed
165
166


Yan's avatar
Yan committed
167
def pan_factory(axis, plot=None):
Yan's avatar
Yan committed
168
    """pan spectrum when you press a button"""
Yan's avatar
Yan committed
169
    def pan_fun(event, ax, pd):
170
        # Release focus from other objects when clicking on graph.
Yan's avatar
Yan committed
171
        focusedWidget = QtWidgets.QApplication.focusWidget()
172
        if focusedWidget and event.inaxes == ax:
Yan's avatar
Yan committed
173
            focusedWidget.clearFocus()
Yan's avatar
Yan committed
174
        # re-scale to origin if doubleclicked
Yan's avatar
Yan committed
175
176
177
        if event.dblclick and event.inaxes == ax:
            ax.get_figure()
            ax.autoscale(True)
Yan's avatar
Yan committed
178
179
180
181
            ymin = -0.01
            if type(pd) is dict and "c_ymin" in pd:
                ymin = pd['c_ymin']
            ax.set_ylim(ax.get_ylim()[1]*ymin, ax.get_ylim()[1]*1.1)
Yan's avatar
Yan committed
182
183
            if type(pd) is dict and "annotation" in pd:
                ann_spec(ax, pd)
Yan's avatar
Yan committed
184
            ax.figure.canvas.draw()
Yan's avatar
Yan committed
185
        # otherwise pan
Yan's avatar
Yan committed
186
        elif event.button == 1 and event.inaxes == ax:
Yan's avatar
Yan committed
187
            ax.start_pan(event.x, event.y, event.button)
Yan's avatar
Yan committed
188
189
190
            id_drag = fig.canvas.mpl_connect(
                'motion_notify_event',
                lambda action: drag_fun(action, ax))
Yan's avatar
Yan committed
191
            id_release = fig.canvas.mpl_connect(
Yan's avatar
Yan committed
192
193
                'button_release_event',
                lambda action: drag_end(
Yan's avatar
Yan committed
194
                    action, id_drag, id_release, pd, ax))
Yan's avatar
Yan committed
195

196
    def drag_fun(event, ax):
Yan's avatar
Yan committed
197
198
199
        ax.drag_pan(1, 'x', event.x, event.y)
        ax.figure.canvas.draw()

Yan's avatar
Yan committed
200
    def drag_end(event, id_drag, id_release, pd, ax):
Yan's avatar
Yan committed
201
202
203
        if event.button == 1:
            fig.canvas.mpl_disconnect(id_drag)
            fig.canvas.mpl_disconnect(id_release)
Yan's avatar
Yan committed
204
205
            if type(pd) is dict and "annotation" in pd:
                ann_spec(ax, pd)
206
            ax.figure.canvas.draw()
Yan's avatar
Yan committed
207

Yan's avatar
Yan committed
208
    fig = axis.get_figure()
Yan's avatar
Yan committed
209
    fig.canvas.mpl_connect('button_press_event',
Yan's avatar
Yan committed
210
                           lambda action: pan_fun(action, axis, plot))
Yan's avatar
Yan committed
211

Yan's avatar
Yan committed
212

213
214
215
216
217
218
def textedit_factory(axis, plot_data):
    def annpicked(pickevent):
        if isinstance(pickevent.artist, matplotlib.text.Annotation) and\
                pickevent.mouseevent.button == 2:
            annotation = pickevent.artist
            textdial = QtWidgets.QInputDialog.getText(
219
                    None, "Enter new annotation", "",
220
                    text=annotation.get_text())
221
222
            if textdial[1]:
                annotation.set_text(textdial[0].replace('\\n', '\n'))
223
224
                if len(textdial[0]) == 0 and annotation in plot_data['texts']:
                    plot_data['texts'].remove(annotation)
3Yan's avatar
3Yan committed
225
                elif annotation in plot_data['annotation']:
226
227
228
                    annotation.set_bbox(ann_bbox)
                    plot_data['annotation'].remove(annotation)
                    plot_data['texts'].append(annotation)
3Yan's avatar
3Yan committed
229
                axis.figure.canvas.draw()
230
231
232
233

    axis.figure.canvas.mpl_connect('pick_event', annpicked)


234
def plot_subtime(augCanvas):
Yan's avatar
Yan committed
235
    """plot averaged spectrum of subselected part of the chromatogram"""
236
237
238
239
240
241
    slims = [augCanvas.spectplot.get_xlim(), augCanvas.spectplot.get_ylim()]
    chlims = [augCanvas.chromplot.get_xlim(), augCanvas.chromplot.get_ylim()]
    augCanvas.ms['annotation'].clear()
    augCanvas.spectplot.clear()
    augCanvas.chromplot.clear()

Yan's avatar
Yan committed
242
243
244
245
246
    chromargs = augCanvas.ds.get_chromargs()
    populate(augCanvas)

    for i, args in enumerate(chromargs):
        if len(args):
Yan's avatar
Yan committed
247
            dots_x, dots_y = [augCanvas.ds.chromatograms[i][j][args]
Yan's avatar
Yan committed
248
                              for j in (0, 1)]
Yan's avatar
Yan committed
249
            augCanvas.chromplot.plot(dots_x, dots_y, '.', color=(
Yan's avatar
Yan committed
250
                                     colors[i % len(colors)]/255))
251

252
    augCanvas.spectplot.set_xlim(slims[0])
Yan's avatar
Yan committed
253
    if not cf.settings().value("view/autozoomy", type=bool):
254
        augCanvas.spectplot.set_ylim(slims[1])
Yan's avatar
Yan committed
255
    if augCanvas.ds.headers:
Yan's avatar
Yan committed
256
257
258
259
260
        for ax in (augCanvas.spectplot, augCanvas.chromplot):
            ax.legend(loc=2)
            ax.get_legend().set_in_layout(False)
            ax.get_legend().set_visible(
                    cf.settings().value("view/legend", type=bool))
Yan's avatar
Yan committed
261
    else:
262
263
264
265
        autozoomy(augCanvas.spectplot)
    ann_spec(augCanvas.spectplot, augCanvas.ms)
    augCanvas.chromplot.set_xlim(chlims[0])
    augCanvas.chromplot.set_ylim(chlims[1])
266
    augCanvas.draw()
Yan's avatar
Yan committed
267
    update_paramstable(augCanvas)
268
269


270
def pick_times(x_min, x_max, augCanvas):
271
    """subselect part of the chromatogram and plot it"""
Yan's avatar
Yan committed
272
273
    augCanvas.ds.mintime = x_min
    augCanvas.ds.maxtime = x_max
Yan's avatar
Yan committed
274
    plot_subtime(augCanvas)
275
276


277
def shift_times(event, augCanvas):
Yan's avatar
Yan committed
278
279
280
281
282
283
284
    """shifts times when arrow is pressed"""
    if event.key() == QtCore.Qt.Key_Left:
        move = -1
    elif event.key() == QtCore.Qt.Key_Right:
        move = +1
    else:
        return
285
286
287
288
    if not np.array_equal(augCanvas.chrom['timesarg'], []):
        x_min, x_max = augCanvas.chrom['t_start'], augCanvas.chrom['t_end']
        alltimes = np.concatenate([subset['chrom_dat'][0] for subset
                                   in augCanvas.ds])
Yan's avatar
Yan committed
289
        times = dt.argsubselect(alltimes, x_min, x_max) + move
290
        goodtimes = np.where((times < len(alltimes)) & ~(times < 0))[0]
Yan's avatar
Yan committed
291
        if not np.array_equal(goodtimes, []):
292
            x_min, x_max = alltimes[times[goodtimes[[0, -1]]]]
293
            pick_times(x_min, x_max, augCanvas)
Yan's avatar
Yan committed
294

Yan's avatar
Yan committed
295

296
def autozoomy(ms_spec):
3Yan's avatar
3Yan committed
297
    if cf.settings().value("view/autozoomy", type=bool) and not (
298
299
            np.array_equal(ms_spec.lines[0].get_xdata(), [0]) and
            len(ms_spec.lines) == 1):
Yan's avatar
Yan committed
300
        ms_spec.autoscale(True, 'y')
3Yan's avatar
3Yan committed
301
302
        gap = 0.01
        ymax = np.max([np.max(line.get_data()[1][dt.argsubselect(
Yan's avatar
Yan committed
303
            line.get_data()[0], *ms_spec.get_xlim())])*1.1
3Yan's avatar
3Yan committed
304
            for line in ms_spec.lines])
Yan's avatar
Yan committed
305
        ms_spec.set_ylim(-ymax*gap, ymax)
3Yan's avatar
3Yan committed
306
        ms_spec.figure.canvas.draw()
Yan's avatar
Yan committed
307

308

Yan's avatar
Yan committed
309
def ann_spec(ms_spec, msdata, ann_limit=0.01, coef_x=15, coef_y=20):
Yan's avatar
Yan committed
310
    """annotate spectrum
311
312

    First define the array, in which the annotation should occur.
Yan's avatar
Yan committed
313
314
    Then remove values which are invalid as local maximas. Local maximas are
    then reduced to a representation of the important ones by the sub_peaks
315
    function"""
316

Yan's avatar
Yan committed
317
318
319
320
    cx = msdata['ancx'] if 'ancx' in msdata.keys() else 15
    cy = msdata['ancy'] if 'ancy' in msdata.keys() else 20

    def sub_peaks(peakz, hardpeaks, xrange, yrange, coef_x=cx, coef_y=cy):
Yan's avatar
Yan committed
321
        """Returns reasonable subselection of local maximas"""
Yan's avatar
Yan committed
322
323
        hardxy = np.array([i.xy for i in hardpeaks], dtype=[
            ('x', np.float32), ('y', np.float32)])
3Yan's avatar
3Yan committed
324
        sort_peaks = np.flipud(np.sort(np.array(peakz), order='y')).copy()
Yan's avatar
Yan committed
325
326
        red_x = xrange / coef_x
        red_y = yrange / coef_y
Yan's avatar
Yan committed
327
        big_peaks = np.array([], dtype=[('x', np.float32), ('y', np.float32)])
3Yan's avatar
3Yan committed
328
        for peak in np.nditer(sort_peaks, flags=["zerosize_ok"]):
329
330
331
332
333
            if not (np.any((abs(peak['y'] - big_peaks['y']) < red_y)
                           & (abs(peak['x'] - big_peaks['x']) < red_x)) or
                    np.any((abs(peak['y'] - hardxy['y']) < red_y)
                           & (abs(peak['x'] - hardxy['x']) < red_x))):
                big_peaks = np.append(big_peaks, peak)
334
335
        return big_peaks

Yan's avatar
Yan committed
336
    peaks = []
3Yan's avatar
3Yan committed
337
338
    for line in ms_spec.lines:
        xdata, ydata = line.get_data()
Yan's avatar
Yan committed
339
340
341
        # Thanks to:
        # https://gist.github.com/ben741/d8c70b608d96d9f7ed231086b237ba6b
        minlim = ms_spec.get_ylim()[1] * ann_limit
Yan's avatar
Yan committed
342
        lims = [*ms_spec.get_xlim(), *ms_spec.get_ylim()]
Yan's avatar
Yan committed
343
344
345
346
        maxargs = np.where((xdata[1:-1] > lims[0]) & (xdata[1:-1] < lims[1]) &
                           (ydata[1:-1] > minlim) & (ydata[1:-1] < lims[3]) &
                           (ydata[1:-1] > ydata[0:-2]) &
                           (ydata[1:-1] > ydata[2:]))[0] + 1
Yan's avatar
Yan committed
347
348
        peakline = np.empty([len(maxargs)], dtype=[('x', np.float32),
                                                   ('y', np.float32)])
Yan's avatar
Yan committed
349
350
        peakline['x'], peakline['y'] = xdata[maxargs], ydata[maxargs]
        peaks.append(peakline)
Yan's avatar
Yan committed
351

Yan's avatar
Yan committed
352
    # delete objects from the spectra
Yan's avatar
Yan committed
353
    for intensity in msdata['annotation']:
Yan's avatar
Yan committed
354
        intensity.remove()
Yan's avatar
Yan committed
355
    # remove them from tracking
Yan's avatar
Yan committed
356
    msdata['annotation'].clear()
Yan's avatar
Yan committed
357

Yan's avatar
Yan committed
358
    if not len(peaks):
359
360
361
362
363
364
365
        return
    peaks = np.concatenate(peaks)

    s_peaks = sub_peaks(peaks, msdata['texts'],
                        np.diff(ms_spec.get_xlim()),
                        np.diff(ms_spec.get_ylim()))

Yan's avatar
Yan committed
366
    dispints = cf.settings().value("view/intensities", type=bool)
367
    for peak in s_peaks:
Yan's avatar
Yan committed
368
369
370
        digits = cf.settings().value("view/digits", type=int)
        annotation = '{0:.{2}f}\n{1: .{2}e}'.format(peak[0], peak[1], digits)\
                if dispints else '{0:.{1}f}'.format(peak[0], digits)
371
372
373
        peaktext = ms_spec.annotate(
            annotation, xy=(peak['x'], peak['y']), textcoords='data',
            picker=True, in_layout=False)
374
        msdata['annotation'].append(peaktext)
375

Yan's avatar
Yan committed
376

Yan's avatar
Yan committed
377
378
def pop_plot(xdata, ydata, plot, plot_data, colornum=0,
             legend=None, annotate=True):
Yan's avatar
Yan committed
379
    """Define and populate plot"""
3Yan's avatar
3Yan committed
380
381
382
    if len(xdata):
        plot.plot(xdata, ydata, linewidth=1, color=(
            colors[colornum % len(colors)]/255), label=legend)
Yan's avatar
Yan committed
383
    plot.set_title(plot_data['name'], loc="right")
Yan's avatar
Yan committed
384
385
    plot.set_xlabel(plot_data['xlabel'])
    plot.set_ylabel(plot_data['ylabel'])
386
    plot.set_ylim(plot.get_ylim()[1] * -0.01,
Yan's avatar
Yan committed
387
                  plot.get_ylim()[1] * 1.1)
Yan's avatar
Yan committed
388
    plot.yaxis.set_major_formatter(FixedScalarFormatter())
389
    # put hardcoded annotation if there is some
3Yan's avatar
3Yan committed
390
391
    if "texts" in plot_data and not any(
            data in plot.get_children() for data in plot_data['texts']):
392
        plot_data['texts'] = [plot.annotate(
393
            a.get_text(), a.xy, picker=True, bbox=ann_bbox, in_layout=False)
3Yan's avatar
3Yan committed
394
            for a in plot_data['texts']]
Yan's avatar
Yan committed
395
396
    if "annotation" in plot_data and annotate:
        ann_spec(plot, plot_data)
Yan's avatar
Yan committed
397
398
399
400
401
    if "xtics" in plot_data:
        plot.locator_params(nbins=plot_data["xtics"], axis='x')
        plot.minorticks_on()
        plot.tick_params(axis='y', which='minor', left=False)

Yan's avatar
Yan committed
402

Yan's avatar
Yan committed
403
def legendize(rawlegend, augCanvas):
404
    # sanity check
Yan's avatar
Yan committed
405
406
    if len(rawlegend) == 0:
        return None
407
408
409
    marks = ["-", "+"]
    quads = ["q3", "q1"]

Yan's avatar
Yan committed
410
    def translate(wut):
Yan's avatar
Yan committed
411
        if augCanvas.ds.machtype == 47:
412
            if wut[1] in (0, 1):
413
414
415
416
417
                text = "{}{}ms; m/z = {:.1f}-{:.1f}".format(
                        marks[int(wut[0])], quads[int(wut[1])], *wut[4:])
            else:
                text = "{}ms^{} {:.2f}@{:.1f}V; m/z = {:.1f}-{:.1f}".format(
                        marks[int(wut[0])], *wut[1:])
Yan's avatar
Yan committed
418
        elif augCanvas.ds.machtype in (57, 63):
Yan's avatar
Yan committed
419
420
421
            if int(wut[1]) == 1:
                text = "{}ms; m/z = {:.1f}-{:.1f}".format(
                        marks[int(wut[0])], *wut[2:])
Yan's avatar
Yan committed
422
            else:
Yan's avatar
Yan committed
423
424
425
426
                text = ("{}ms^{:.0f};" + "".join([" {:.2f}/{:.1f}@{:.1f}V" for
                                                  _ in range(int(wut[1])-1)]) +
                        "; m/z = {:.1f}-{:.1f}").format(
                                marks[int(wut[0])], *wut[1:])
Yan's avatar
Yan committed
427
        else:
428
            text = "unknown header type"
Yan's avatar
Yan committed
429
        return text
Yan's avatar
Yan committed
430
431
432
433
    uniqindexs = np.unique(np.array(rawlegend), return_index=True)\
        if np.array(rawlegend).dtype == np.dtype('O') else\
        np.unique(np.array(rawlegend), axis=0, return_index=True)
    strdata = [translate(i) for i in rawlegend[np.sort(uniqindexs[1])]]
Yan's avatar
Yan committed
434
    strtext = " and\n".join(strdata) + "; t = {:.2f}-{:.2f} min".format(
Yan's avatar
Yan committed
435
                    augCanvas.ds.mintime, augCanvas.ds.maxtime)
Yan's avatar
Yan committed
436
437
438
    return strtext


439
def populate(augCanvas):
Yan's avatar
Yan committed
440
    """populate the GUI plots with desired dataset"""
441
    if np.array_equal(augCanvas.ds, []):
Yan's avatar
Yan committed
442
        return
443
    [i.clear() for i in (augCanvas.ms['annotation'],
444
     augCanvas.chromplot, augCanvas.spectplot)]
Yan's avatar
Yan committed
445

446
447
    if augCanvas.ms['predict']:
        # TODO: Fix the broken code
448
449
        predict = augCanvas.ms['predict']
        maxm = np.argmax(predict[1]) + predict[0]
3Yan's avatar
3Yan committed
450
451
        maxseek = dt.argsubselect(linex, maxm-.5, maxm+.5)
        maxpos = maxseek[np.argmax(liney[maxseek])]
452
        crudeints = predict[1] * augCanvas.ms['y'][maxpos]
453
        crudemasses = (np.arange(len(predict[1])) + linex[maxpos])
Yan's avatar
Yan committed
454
        pmasses, pints = [], []
455
456
        [pmasses.extend([np.nan, i, i]) for i in crudemasses]
        [pints.extend([np.nan, 0, i]) for i in crudeints]
457
        augCanvas.spectplot.plot(pmasses, pints, linewidth=1)
Yan's avatar
Yan committed
458

Yan's avatar
Yan committed
459
    chromxy = augCanvas.ds.chromatograms
Yan's avatar
Yan committed
460
    msxy = augCanvas.get_spectra()
Yan's avatar
Yan committed
461
    for i in range(len(msxy)):
Yan's avatar
Yan committed
462
463
        if augCanvas.ds.headers and\
                len(augCanvas.ds.headers) == len(augCanvas.ds.chromatograms):
Yan's avatar
Yan committed
464
            legend = legendize(augCanvas.ds.headers[i], augCanvas)
Yan's avatar
Yan committed
465
466
        else:
            legend = None
Yan's avatar
Yan committed
467
468
        pop_plot(msxy[i][0], msxy[i][1], augCanvas.spectplot,
                 augCanvas.ms, i, legend)
Yan's avatar
Yan committed
469
        pop_plot(chromxy[i][0], chromxy[i][1], augCanvas.chromplot,
Yan's avatar
Yan committed
470
                 augCanvas.chrom, i, legend)
471
    for ax in (augCanvas.spectplot, augCanvas.chromplot):
Yan's avatar
Yan committed
472
        if augCanvas.ds.headers:
Yan's avatar
Yan committed
473
            ax.legend(loc=2)
Yan's avatar
Yan committed
474
            ax.get_legend().set_in_layout(False)
Yan's avatar
Yan committed
475
476
            ax.get_legend().set_visible(
                    cf.settings().value("view/legend", type=bool))
3Yan's avatar
3Yan committed
477
478
        ax.autoscale(True)
        ax.set_ylim(ax.get_ylim()[1]*-0.01, ax.get_ylim()[1]*1.1)
Yan's avatar
Yan committed
479
    augCanvas.constrained_draw()
3Yan's avatar
3Yan committed
480
    return
Yan's avatar
Yan committed
481
482


483
def update_paramstable(augCanvas):
Yan's avatar
Yan committed
484
    if not augCanvas.ds.params:
485
        augCanvas.paramstable.setRowCount(0)
Yan's avatar
Yan committed
486
        return
Yan's avatar
Yan committed
487
    elif len(augCanvas.ds.params[0]) == augCanvas.paramstable.rowCount():
488
489
490
491
        states = [augCanvas.paramstable.cellWidget(row, 0).checkState()
                  for row in range(augCanvas.paramstable.rowCount())]
    else:
        states = False
Yan's avatar
Yan committed
492
493
        augCanvas.paramstable.setRowCount(len(augCanvas.ds.params[0]))
    for row, paramname in enumerate(augCanvas.ds.params[0]):
494
495
496
        [augCanvas.paramstable.setItem(row, col, QtWidgets.QTableWidgetItem())
         for col in range(1, 3)]
        augCanvas.paramstable.setCellWidget(row, 0, QtWidgets.QCheckBox())
497
        if states:
498
499
            augCanvas.paramstable.cellWidget(row, 0).setCheckState(states[row])
        augCanvas.paramstable.item(row, 1).setText(paramname)
Yan's avatar
Yan committed
500
        vals = [param[row] for param in augCanvas.ds.params[1]
Yan's avatar
Yan committed
501
502
                if (param[0] >= augCanvas.ds.mintime and
                param[0] <= augCanvas.ds.maxtime)]
Yan's avatar
Yan committed
503
        if len(vals) == 0:
Yan's avatar
Yan committed
504
            text = ""
Yan's avatar
Yan committed
505
506
507
508
509
510
511
512
        elif all([type(val) in [np.float32, np.float64] for val in vals]):
            aver = np.average(vals)
            minim = min(vals)
            maxim = max(vals)
            text = "{:.2f} (from {:.2f} to {:.2f})".format(aver, minim, maxim)
        else:
            values = [str(i) for i in np.unique(np.array(vals), axis=0)]
            text = " or ".join(values)
513
        augCanvas.paramstable.item(row, 2).setText(text)