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

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


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

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

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

    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
124
125


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

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


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

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


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

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

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

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

Yan's avatar
Yan committed
211

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

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


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

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

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


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


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

Yan's avatar
Yan committed
294

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

307

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

    First define the array, in which the annotation should occur.
Yan's avatar
Yan committed
312
313
    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
314
    function"""
315

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

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

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

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

Yan's avatar
Yan committed
371

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

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

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


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

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

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


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