graphtools.py 22.7 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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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)
        self.ds = []
        self.ms = dict(annotation=[], name="Spectrum", xlabel="m/z",
                       ylabel="ion count", xtics=20, predict=None,
                       params=[], headers=[], texts=[])
        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.filename = None
        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)
Yan's avatar
Yan committed
48
        zoom_factory(self.chromplot, 1e-3)
49
        pan_factory(self.spectplot, self.ms)
Yan's avatar
Yan committed
50
        zoom_factory(self.spectplot, 1e-3, 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
129
130
131
132
133
134
135
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
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:
Yan's avatar
Yan 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(
Yan's avatar
Yan committed
163
        event, plot_data, axis, 1+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()

241
    for i, subset in enumerate(augCanvas.ds):
242
243
244
245
        selection = augCanvas.chrom['timesarg'][i]
        if len(augCanvas.ms['headers']) == len(augCanvas.ds):
            legend = legendize(augCanvas.ms['headers'][i][selection],
                               augCanvas.chrom)
Yan's avatar
Yan committed
246
247
        else:
            legend = None
3Yan's avatar
3Yan committed
248
        if cf.settings().value("view/oddeven", type=bool):
249
            for j in range(2):
Yan's avatar
Yan committed
250
251
                chromx = subset['chrom_dat'][0, :][j::2]
                chromy = subset['chrom_dat'][1, :][j::2]
252
253
                pop_plot(chromx, chromy, augCanvas.chromplot,
                         augCanvas.chrom, i*2+j, legend)
3Yan's avatar
3Yan committed
254
255
256
                if not np.array_equal(selection[j::2], []):
                    clr = i*2+j if selection[0] % 2 == 0\
                            else i*2+(1-j)
Yan's avatar
Yan committed
257
                    ms_x = subset['masses']
3Yan's avatar
3Yan committed
258
                    ms_y = np.mean(subset['matrix'][selection[j::2]], axis=0)
259
260
                    pop_plot(ms_x, ms_y, augCanvas.spectplot,
                             augCanvas.ms, clr, legend)
3Yan's avatar
3Yan committed
261
262
                    dots_x = subset['chrom_dat'][0, selection[j::2]]
                    dots_y = subset['chrom_dat'][1, selection[j::2]]
263
                    augCanvas.chromplot.plot(dots_x, dots_y, '.', color=(
3Yan's avatar
3Yan committed
264
                        colors[(clr) % len(colors)]/255))
3Yan's avatar
3Yan committed
265
266
267
        else:
            chromx = subset['chrom_dat'][0, :]
            chromy = subset['chrom_dat'][1, :]
268
269
            pop_plot(chromx, chromy, augCanvas.chromplot,
                     augCanvas.chrom, i, legend)
3Yan's avatar
3Yan committed
270
            if not np.array_equal(selection, []):
3Yan's avatar
3Yan committed
271
                ms_x = subset['masses']
3Yan's avatar
3Yan committed
272
                ms_y = np.mean(subset['matrix'][selection], axis=0)
273
274
                pop_plot(ms_x, ms_y, augCanvas.spectplot,
                         augCanvas.ms, i, legend)
3Yan's avatar
3Yan committed
275
276
                dots_x = subset['chrom_dat'][0, selection]
                dots_y = subset['chrom_dat'][1, selection]
277
                augCanvas.chromplot.plot(dots_x, dots_y, '.', color=(
3Yan's avatar
3Yan committed
278
                    colors[i % len(colors)]/255))
279

280
    augCanvas.spectplot.set_xlim(slims[0])
Yan's avatar
Yan committed
281
    if not cf.settings().value("view/autozoomy", type=bool):
282
283
284
285
286
287
        augCanvas.spectplot.set_ylim(slims[1])
    if not augCanvas.ms['headers'] == []:
        augCanvas.spectplot.legend(loc=2)
        augCanvas.spectplot.get_legend().set_in_layout(False)
        augCanvas.chromplot.legend(loc=2)
        augCanvas.chromplot.get_legend().set_in_layout(False)
Yan's avatar
Yan committed
288
    else:
289
290
291
292
        autozoomy(augCanvas.spectplot)
    ann_spec(augCanvas.spectplot, augCanvas.ms)
    augCanvas.chromplot.set_xlim(chlims[0])
    augCanvas.chromplot.set_ylim(chlims[1])
293
    augCanvas.draw()
294
295


296
def pick_times(x_min, x_max, augCanvas):
297
    """subselect part of the chromatogram and plot it"""
298
299
    augCanvas.chrom['t_start'] = x_min
    augCanvas.chrom['t_end'] = x_max
3Yan's avatar
3Yan committed
300
    times = dt.argsubselect(np.concatenate(
301
302
303
        [subset['chrom_dat'][0] for subset in augCanvas.ds]), x_min, x_max)
    augCanvas.chrom['timesarg'].clear()
    for subset in augCanvas.ds:
304
305
        goodtimes = np.where((times < len(subset['chrom_dat'][0]))
                             & ~(times < 0))[0]
306
        augCanvas.chrom['timesarg'].append(times[goodtimes])
3Yan's avatar
3Yan committed
307
        times = times - len(subset['chrom_dat'][0])
308
309
    update_paramstable(augCanvas)
    plot_subtime(augCanvas)
310
311


312
def shift_times(event, augCanvas):
Yan's avatar
Yan committed
313
314
315
316
317
318
319
    """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
320
321
322
323
    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
324
        times = dt.argsubselect(alltimes, x_min, x_max) + move
325
        goodtimes = np.where((times < len(alltimes)) & ~(times < 0))[0]
Yan's avatar
Yan committed
326
        if not np.array_equal(goodtimes, []):
327
            x_min, x_max = alltimes[times[goodtimes[[0, -1]]]]
328
            pick_times(x_min, x_max, augCanvas)
Yan's avatar
Yan committed
329

Yan's avatar
Yan committed
330

331
def autozoomy(ms_spec):
3Yan's avatar
3Yan committed
332
    if cf.settings().value("view/autozoomy", type=bool) and not (
333
334
            np.array_equal(ms_spec.lines[0].get_xdata(), [0]) and
            len(ms_spec.lines) == 1):
Yan's avatar
Yan committed
335
        ms_spec.autoscale(True, 'y')
3Yan's avatar
3Yan committed
336
337
        gap = 0.01
        ymax = np.max([np.max(line.get_data()[1][dt.argsubselect(
Yan's avatar
Yan committed
338
            line.get_data()[0], *ms_spec.get_xlim())])*1.1
3Yan's avatar
3Yan committed
339
            for line in ms_spec.lines])
Yan's avatar
Yan committed
340
        ms_spec.set_ylim(-ymax*gap, ymax)
3Yan's avatar
3Yan committed
341
        ms_spec.figure.canvas.draw()
Yan's avatar
Yan committed
342

343

Yan's avatar
Yan committed
344
def ann_spec(ms_spec, msdata, ann_limit=0.01):
Yan's avatar
Yan committed
345
    """annotate spectrum
346
347

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

352
    def sub_peaks(peakz, hardpeaks, xrange, yrange, coef_x=10, coef_y=10):
Yan's avatar
Yan committed
353
        """Returns reasonable subselection of local maximas"""
Yan's avatar
Yan committed
354
355
356
        hardxy = np.array([i.xy for i in hardpeaks], dtype=[
            ('x', np.float32), ('y', np.float32)])
        sort_peaks = np.flipud(np.sort(np.array(peakz))).copy()
Yan's avatar
Yan committed
357
358
        red_x = xrange / coef_x
        red_y = yrange / coef_y
Yan's avatar
Yan committed
359
        big_peaks = np.array([], dtype=[('x', np.float32), ('y', np.float32)])
3Yan's avatar
3Yan committed
360
        for peak in np.nditer(sort_peaks, flags=["zerosize_ok"]):
361
362
363
364
365
            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)
366
367
        return big_peaks

Yan's avatar
Yan committed
368
    peaks = []
3Yan's avatar
3Yan committed
369
370
    for line in ms_spec.lines:
        xdata, ydata = line.get_data()
Yan's avatar
Yan committed
371
372
373
374
375
376
377
378
379
380
381
382
383
        # 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)
    peaks = np.concatenate(peaks)

384
    s_peaks = sub_peaks(peaks, msdata['texts'],
385
386
                        np.diff(ms_spec.get_xlim()),
                        np.diff(ms_spec.get_ylim()))
Yan's avatar
Yan committed
387

Yan's avatar
Yan committed
388
    # delete objects from the spectra
Yan's avatar
Yan committed
389
    for intensity in msdata['annotation']:
Yan's avatar
Yan committed
390
        intensity.remove()
Yan's avatar
Yan committed
391
    # remove them from tracking
Yan's avatar
Yan committed
392
    msdata['annotation'].clear()
Yan's avatar
Yan committed
393

Yan's avatar
Yan committed
394
    dispints = cf.settings().value("view/intensities", type=bool)
395
    for peak in s_peaks:
Yan's avatar
Yan committed
396
397
        annotation = '{0:.2f}\n{1: .2e}'.format(peak[0], peak[1])\
                if dispints else '{0:.2f}'.format(peak[0])
398
399
400
        peaktext = ms_spec.annotate(
            annotation, xy=(peak['x'], peak['y']), textcoords='data',
            picker=True, in_layout=False)
401
        msdata['annotation'].append(peaktext)
402

Yan's avatar
Yan committed
403

Yan's avatar
Yan committed
404
def pop_plot(xdata, ydata, plot, plot_data, colornum=0, legend=None):
Yan's avatar
Yan committed
405
    """Define and populate plot"""
406
407
    plot.plot(xdata, ydata, linewidth=1, color=(
        colors[colornum % len(colors)]/255), label=legend)
Yan's avatar
Yan committed
408
    plot.set_title(plot_data['name'], loc="right")
Yan's avatar
Yan committed
409
410
    plot.set_xlabel(plot_data['xlabel'])
    plot.set_ylabel(plot_data['ylabel'])
411
    plot.set_ylim(plot.get_ylim()[1] * -0.01,
Yan's avatar
Yan committed
412
                  plot.get_ylim()[1] * 1.1)
Yan's avatar
Yan committed
413
    plot.yaxis.set_major_formatter(FixedScalarFormatter())
414
    # put hardcoded annotation if there is some
3Yan's avatar
3Yan committed
415
416
    if "texts" in plot_data and not any(
            data in plot.get_children() for data in plot_data['texts']):
417
        plot_data['texts'] = [plot.annotate(
418
            a.get_text(), a.xy, picker=True, bbox=ann_bbox, in_layout=False)
3Yan's avatar
3Yan committed
419
            for a in plot_data['texts']]
Yan's avatar
Yan committed
420
421
    if "annotation" in plot_data:
        ann_spec(plot, plot_data)
Yan's avatar
Yan committed
422
423
424
425
426
    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
427

Yan's avatar
Yan committed
428
def legendize(rawlegend, chrom_data):
429
    # sanity check
Yan's avatar
Yan committed
430
431
    if len(rawlegend) == 0:
        return None
432
433
434
    marks = ["-", "+"]
    quads = ["q3", "q1"]

Yan's avatar
Yan committed
435
    def translate(wut):
436
        if chrom_data['machtype'] == 47:
437
            if wut[1] in (0, 1):
438
439
440
441
442
                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
443
444
445
446
        elif chrom_data['machtype'] in (57, 63):
            if int(wut[1]) == 1:
                text = "{}ms; m/z = {:.1f}-{:.1f}".format(
                        marks[int(wut[0])], *wut[2:])
Yan's avatar
Yan committed
447
            else:
Yan's avatar
Yan committed
448
449
450
451
                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
452
        else:
453
            text = "unknown header type"
Yan's avatar
Yan committed
454
        return text
Yan's avatar
Yan committed
455
456
457
458
    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
459
    strtext = " and\n".join(strdata) + "; t = {:.2f}-{:.2f} min".format(
Yan's avatar
Yan committed
460
                    chrom_data['t_start'], chrom_data['t_end'])
Yan's avatar
Yan committed
461
462
463
    return strtext


464
def populate(augCanvas):
Yan's avatar
Yan committed
465
    """populate the GUI plots with desired dataset"""
466
    if np.array_equal(augCanvas.ds, []):
Yan's avatar
Yan committed
467
        return
468
    [i.clear() for i in (augCanvas.ms['annotation'],
469
     augCanvas.chromplot, augCanvas.spectplot)]
Yan's avatar
Yan committed
470

471
472
    if augCanvas.ms['predict']:
        # TODO: Fix the broken code
473
474
        predict = augCanvas.ms['predict']
        maxm = np.argmax(predict[1]) + predict[0]
3Yan's avatar
3Yan committed
475
476
        maxseek = dt.argsubselect(linex, maxm-.5, maxm+.5)
        maxpos = maxseek[np.argmax(liney[maxseek])]
477
        crudeints = predict[1] * augCanvas.ms['y'][maxpos]
478
        crudemasses = (np.arange(len(predict[1])) + linex[maxpos])
Yan's avatar
Yan committed
479
        pmasses, pints = [], []
480
481
        [pmasses.extend([np.nan, i, i]) for i in crudemasses]
        [pints.extend([np.nan, 0, i]) for i in crudeints]
482
        augCanvas.spectplot.plot(pmasses, pints, linewidth=1)
Yan's avatar
Yan committed
483

484
485
    augCanvas.chrom['t_start'] = augCanvas.ds[0]['chrom_dat'][0, 0]
    augCanvas.chrom['t_end'] = augCanvas.ds[-1]['chrom_dat'][0, -1]
486
    for i, subset in enumerate(augCanvas.ds):
487
488
        if len(augCanvas.ms['headers']) == len(augCanvas.ds):
            legend = legendize(augCanvas.ms['headers'][i], augCanvas.chrom)
Yan's avatar
Yan committed
489
490
        else:
            legend = None
491
        if cf.settings().value("view/oddeven", type=bool):
3Yan's avatar
3Yan committed
492
            msx = subset['masses']
493
            for j in range(2):
3Yan's avatar
3Yan committed
494
495
496
                msy = np.mean(subset['matrix'][j::2], axis=0)
                chromx = subset['chrom_dat'][0, :][j::2]
                chromy = subset['chrom_dat'][1, :][j::2]
497
498
499
500
                pop_plot(msx, msy, augCanvas.spectplot, augCanvas.ms,
                         i*2+j, legend)
                pop_plot(chromx, chromy, augCanvas.chromplot,
                         augCanvas.chrom, i*2+j, legend)
501
        else:
3Yan's avatar
3Yan committed
502
503
504
505
            msx = subset['masses']
            msy = np.mean(subset['matrix'], axis=0)
            chromx = subset['chrom_dat'][0, :]
            chromy = subset['chrom_dat'][1, :]
506
507
508
509
510
            pop_plot(msx, msy, augCanvas.spectplot, augCanvas.ms, i, legend)
            pop_plot(chromx, chromy, augCanvas.chromplot, augCanvas.chrom,
                     i, legend)
    for ax in (augCanvas.spectplot, augCanvas.chromplot):
        if not augCanvas.ms['headers'] == []:
Yan's avatar
Yan committed
511
            ax.legend(loc=2)
Yan's avatar
Yan committed
512
            ax.get_legend().set_in_layout(False)
3Yan's avatar
3Yan committed
513
514
        ax.autoscale(True)
        ax.set_ylim(ax.get_ylim()[1]*-0.01, ax.get_ylim()[1]*1.1)
Yan's avatar
Yan committed
515
    augCanvas.constrained_draw()
3Yan's avatar
3Yan committed
516
    return
Yan's avatar
Yan committed
517
518


519
520
521
def update_paramstable(augCanvas):
    if len(augCanvas.ms['params']) == 0:
        augCanvas.paramstable.setRowCount(0)
Yan's avatar
Yan committed
522
        return
523
524
525
526
527
528
    elif len(augCanvas.ms['params'][0]) == augCanvas.paramstable.rowCount():
        states = [augCanvas.paramstable.cellWidget(row, 0).checkState()
                  for row in range(augCanvas.paramstable.rowCount())]
    else:
        states = False
        augCanvas.paramstable.setRowCount(len(augCanvas.ms['params'][0]))
529
    for row, paramname in enumerate(augCanvas.ms['params'][0]):
530
531
532
        [augCanvas.paramstable.setItem(row, col, QtWidgets.QTableWidgetItem())
         for col in range(1, 3)]
        augCanvas.paramstable.setCellWidget(row, 0, QtWidgets.QCheckBox())
533
        if states:
534
535
            augCanvas.paramstable.cellWidget(row, 0).setCheckState(states[row])
        augCanvas.paramstable.item(row, 1).setText(paramname)
536
        vals = [param[row] for param in augCanvas.ms['params'][1]
537
                if (param[0] >= augCanvas.chrom['t_start'] and
538
                param[0] <= augCanvas.chrom['t_end'])]
Yan's avatar
Yan committed
539
        if len(vals) == 0:
Yan's avatar
Yan committed
540
            text = ""
Yan's avatar
Yan committed
541
542
543
544
545
546
547
548
        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)
549
        augCanvas.paramstable.item(row, 2).setText(text)