graphtools.py 20.1 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
37
38
39
40
41
42
43
44
45
        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]
        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
46
        zoom_factory(self.chromplot, 0.9)
47
        pan_factory(self.spectplot, self.ms)
3Yan's avatar
3Yan committed
48
        zoom_factory(self.spectplot, 0.9, self.ms)
49
50
51
52
53
54
        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
55
56
57
58
59
        self.figure.set_constrained_layout(False)

    def constrained_draw(self):
        self.figure.execute_constrained_layout()
        self.draw()
60
61


Yan's avatar
Yan committed
62
63
class AugSpanSelector(SpanSelector):
    def __init__(self, ax, data):
64
65
66
67
68
        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
69
        self.data = data
70

Yan's avatar
Yan committed
71
72
73
74
75
76
77
78
79
80
    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)
81
        super()._press(event)
Yan's avatar
Yan committed
82

83
84
85
86
87
    def _release(self, event):
        """on button release event"""
        if self.pressv is None:
            return
        elif self.direction == 'horizontal':
88
            super()._release(event)
89
90
91
92
93
94
95
96
97
98
99
100
101
102
        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':
103
            super()._set_span_xy(event)
104
        else:
105
            x, y = self._get_data(event)
106
107
108
109
110
            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
111
112
113
114
115
116
117
118
119
120
121

    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
122
123


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

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


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

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


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

193
    def drag_fun(event, ax):
Yan's avatar
Yan committed
194
195
196
        ax.drag_pan(1, 'x', event.x, event.y)
        ax.figure.canvas.draw()

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

Yan's avatar
Yan committed
205
    fig = axis.get_figure()
Yan's avatar
Yan committed
206
    fig.canvas.mpl_connect('button_press_event',
Yan's avatar
Yan committed
207
                           lambda action: pan_fun(action, axis, plot))
Yan's avatar
Yan committed
208

Yan's avatar
Yan committed
209

210
211
212
213
214
215
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(
216
                    None, "Enter new annotation", "",
217
                    text=annotation.get_text())
218
219
            if textdial[1]:
                annotation.set_text(textdial[0].replace('\\n', '\n'))
220
221
                if len(textdial[0]) == 0 and annotation in plot_data['texts']:
                    plot_data['texts'].remove(annotation)
3Yan's avatar
3Yan committed
222
                elif annotation in plot_data['annotation']:
223
224
225
                    annotation.set_bbox(ann_bbox)
                    plot_data['annotation'].remove(annotation)
                    plot_data['texts'].append(annotation)
3Yan's avatar
3Yan committed
226
                axis.figure.canvas.draw()
227
228
229
230

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


231
def plot_subtime(augCanvas):
Yan's avatar
Yan committed
232
    """plot averaged spectrum of subselected part of the chromatogram"""
233
234
235
236
237
238
    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
239
240
241
242
243
    chromargs = augCanvas.ds.get_chromargs()
    populate(augCanvas)

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

249
    augCanvas.spectplot.set_xlim(slims[0])
Yan's avatar
Yan committed
250
    if not cf.settings().value("view/autozoomy", type=bool):
251
        augCanvas.spectplot.set_ylim(slims[1])
Yan's avatar
Yan committed
252
    if augCanvas.ds.headers:
Yan's avatar
Yan committed
253
254
255
256
257
        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
258
    else:
259
260
261
262
        autozoomy(augCanvas.spectplot)
    ann_spec(augCanvas.spectplot, augCanvas.ms)
    augCanvas.chromplot.set_xlim(chlims[0])
    augCanvas.chromplot.set_ylim(chlims[1])
263
    augCanvas.draw()
Yan's avatar
Yan committed
264
    update_paramstable(augCanvas)
265
266


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


274
def shift_times(event, augCanvas):
Yan's avatar
Yan committed
275
276
277
278
279
280
281
    """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
282
283
284
285
    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
286
        times = dt.argsubselect(alltimes, x_min, x_max) + move
287
        goodtimes = np.where((times < len(alltimes)) & ~(times < 0))[0]
Yan's avatar
Yan committed
288
        if not np.array_equal(goodtimes, []):
289
            x_min, x_max = alltimes[times[goodtimes[[0, -1]]]]
290
            pick_times(x_min, x_max, augCanvas)
Yan's avatar
Yan committed
291

Yan's avatar
Yan committed
292

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

305

Yan's avatar
Yan committed
306
def ann_spec(ms_spec, msdata, ann_limit=0.01):
Yan's avatar
Yan committed
307
    """annotate spectrum
308
309

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

3Yan's avatar
3Yan committed
314
    def sub_peaks(peakz, hardpeaks, xrange, yrange, coef_x=15, coef_y=20):
Yan's avatar
Yan committed
315
        """Returns reasonable subselection of local maximas"""
Yan's avatar
Yan committed
316
317
        hardxy = np.array([i.xy for i in hardpeaks], dtype=[
            ('x', np.float32), ('y', np.float32)])
3Yan's avatar
3Yan committed
318
        sort_peaks = np.flipud(np.sort(np.array(peakz), order='y')).copy()
Yan's avatar
Yan committed
319
320
        red_x = xrange / coef_x
        red_y = yrange / coef_y
Yan's avatar
Yan committed
321
        big_peaks = np.array([], dtype=[('x', np.float32), ('y', np.float32)])
3Yan's avatar
3Yan committed
322
        for peak in np.nditer(sort_peaks, flags=["zerosize_ok"]):
323
324
325
326
327
            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)
328
329
        return big_peaks

Yan's avatar
Yan committed
330
    peaks = []
3Yan's avatar
3Yan committed
331
332
    for line in ms_spec.lines:
        xdata, ydata = line.get_data()
Yan's avatar
Yan committed
333
334
335
336
337
338
339
340
341
342
343
        # Thanks to:
        # https://gist.github.com/ben741/d8c70b608d96d9f7ed231086b237ba6b
        minlim = ms_spec.get_ylim()[1] * ann_limit
        lims = [*ms_spec.get_xlim(),*ms_spec.get_ylim()]
        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
        peakline = np.empty([len(maxargs)], dtype=[('x', np.float32), ('y', np.float32)])
        peakline['x'], peakline['y'] = xdata[maxargs], ydata[maxargs]
        peaks.append(peakline)
Yan's avatar
Yan committed
344

Yan's avatar
Yan committed
345
    # delete objects from the spectra
Yan's avatar
Yan committed
346
    for intensity in msdata['annotation']:
Yan's avatar
Yan committed
347
        intensity.remove()
Yan's avatar
Yan committed
348
    # remove them from tracking
Yan's avatar
Yan committed
349
    msdata['annotation'].clear()
Yan's avatar
Yan committed
350

351
352
353
354
355
356
357
358
    if len(peaks) == 0:
        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
359
    dispints = cf.settings().value("view/intensities", type=bool)
360
    for peak in s_peaks:
Yan's avatar
Yan committed
361
362
        annotation = '{0:.2f}\n{1: .2e}'.format(peak[0], peak[1])\
                if dispints else '{0:.2f}'.format(peak[0])
363
364
365
        peaktext = ms_spec.annotate(
            annotation, xy=(peak['x'], peak['y']), textcoords='data',
            picker=True, in_layout=False)
366
        msdata['annotation'].append(peaktext)
367

Yan's avatar
Yan committed
368

369
def pop_plot(xdata, ydata, plot, plot_data, colornum=0, legend=None, annotate=True):
Yan's avatar
Yan committed
370
    """Define and populate plot"""
3Yan's avatar
3Yan committed
371
372
373
    if len(xdata):
        plot.plot(xdata, ydata, linewidth=1, color=(
            colors[colornum % len(colors)]/255), label=legend)
Yan's avatar
Yan committed
374
    plot.set_title(plot_data['name'], loc="right")
Yan's avatar
Yan committed
375
376
    plot.set_xlabel(plot_data['xlabel'])
    plot.set_ylabel(plot_data['ylabel'])
377
    plot.set_ylim(plot.get_ylim()[1] * -0.01,
Yan's avatar
Yan committed
378
                  plot.get_ylim()[1] * 1.1)
Yan's avatar
Yan committed
379
    plot.yaxis.set_major_formatter(FixedScalarFormatter())
380
    # put hardcoded annotation if there is some
3Yan's avatar
3Yan committed
381
382
    if "texts" in plot_data and not any(
            data in plot.get_children() for data in plot_data['texts']):
383
        plot_data['texts'] = [plot.annotate(
384
            a.get_text(), a.xy, picker=True, bbox=ann_bbox, in_layout=False)
3Yan's avatar
3Yan committed
385
            for a in plot_data['texts']]
386
387
    if "annotation" in plot_data and annotate == True:
            ann_spec(plot, plot_data)
Yan's avatar
Yan committed
388
389
390
391
392
    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
393

Yan's avatar
Yan committed
394
def legendize(rawlegend, augCanvas):
395
    # sanity check
Yan's avatar
Yan committed
396
397
    if len(rawlegend) == 0:
        return None
398
399
400
    marks = ["-", "+"]
    quads = ["q3", "q1"]

Yan's avatar
Yan committed
401
    def translate(wut):
Yan's avatar
Yan committed
402
        if augCanvas.ds.machtype == 47:
403
            if wut[1] in (0, 1):
404
405
406
407
408
                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
409
        elif augCanvas.ds.machtype in (57, 63):
Yan's avatar
Yan committed
410
411
412
            if int(wut[1]) == 1:
                text = "{}ms; m/z = {:.1f}-{:.1f}".format(
                        marks[int(wut[0])], *wut[2:])
Yan's avatar
Yan committed
413
            else:
Yan's avatar
Yan committed
414
415
416
417
                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
418
        else:
419
            text = "unknown header type"
Yan's avatar
Yan committed
420
        return text
Yan's avatar
Yan committed
421
422
423
424
    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
425
    strtext = " and\n".join(strdata) + "; t = {:.2f}-{:.2f} min".format(
Yan's avatar
Yan committed
426
                    augCanvas.ds.mintime, augCanvas.ds.maxtime)
Yan's avatar
Yan committed
427
428
429
    return strtext


430
def populate(augCanvas):
Yan's avatar
Yan committed
431
    """populate the GUI plots with desired dataset"""
432
    if np.array_equal(augCanvas.ds, []):
Yan's avatar
Yan committed
433
        return
434
    [i.clear() for i in (augCanvas.ms['annotation'],
435
     augCanvas.chromplot, augCanvas.spectplot)]
Yan's avatar
Yan committed
436

437
438
    if augCanvas.ms['predict']:
        # TODO: Fix the broken code
439
440
        predict = augCanvas.ms['predict']
        maxm = np.argmax(predict[1]) + predict[0]
3Yan's avatar
3Yan committed
441
442
        maxseek = dt.argsubselect(linex, maxm-.5, maxm+.5)
        maxpos = maxseek[np.argmax(liney[maxseek])]
443
        crudeints = predict[1] * augCanvas.ms['y'][maxpos]
444
        crudemasses = (np.arange(len(predict[1])) + linex[maxpos])
Yan's avatar
Yan committed
445
        pmasses, pints = [], []
446
447
        [pmasses.extend([np.nan, i, i]) for i in crudemasses]
        [pints.extend([np.nan, 0, i]) for i in crudeints]
448
        augCanvas.spectplot.plot(pmasses, pints, linewidth=1)
Yan's avatar
Yan committed
449

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


473
def update_paramstable(augCanvas):
Yan's avatar
Yan committed
474
    if not augCanvas.ds.params:
475
        augCanvas.paramstable.setRowCount(0)
Yan's avatar
Yan committed
476
        return
Yan's avatar
Yan committed
477
    elif len(augCanvas.ds.params[0]) == augCanvas.paramstable.rowCount():
478
479
480
481
        states = [augCanvas.paramstable.cellWidget(row, 0).checkState()
                  for row in range(augCanvas.paramstable.rowCount())]
    else:
        states = False
Yan's avatar
Yan committed
482
483
        augCanvas.paramstable.setRowCount(len(augCanvas.ds.params[0]))
    for row, paramname in enumerate(augCanvas.ds.params[0]):
484
485
486
        [augCanvas.paramstable.setItem(row, col, QtWidgets.QTableWidgetItem())
         for col in range(1, 3)]
        augCanvas.paramstable.setCellWidget(row, 0, QtWidgets.QCheckBox())
487
        if states:
488
489
            augCanvas.paramstable.cellWidget(row, 0).setCheckState(states[row])
        augCanvas.paramstable.item(row, 1).setText(paramname)
Yan's avatar
Yan committed
490
        vals = [param[row] for param in augCanvas.ds.params[1]
Yan's avatar
Yan committed
491
492
                if (param[0] >= augCanvas.ds.mintime and
                param[0] <= augCanvas.ds.maxtime)]
Yan's avatar
Yan committed
493
        if len(vals) == 0:
Yan's avatar
Yan committed
494
            text = ""
Yan's avatar
Yan committed
495
496
497
498
499
500
501
502
        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)
503
        augCanvas.paramstable.item(row, 2).setText(text)