graphtools.py 22.2 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
48
49
50
51
52
53
54
55
56
57
58
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)
        zoom_factory(self.chromplot, 1.15)
        pan_factory(self.spectplot, self.ms)
        zoom_factory(self.spectplot, 1.15, self.ms)
        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
59
60
class AugSpanSelector(SpanSelector):
    def __init__(self, ax, data):
61
62
63
64
65
        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
66
        self.data = data
67

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

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

    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
119
120


Yan's avatar
Yan committed
121
def zoom_factory(axis, base_scale, plot_data=None):
Yan's avatar
Yan committed
122
    """returns zooming functionality to axis"""
Yan's avatar
Yan committed
123
    def zoom_fun(event, pd, ax, scale):
Yan's avatar
Yan committed
124
        """zoom when scrolling"""
Yan's avatar
Yan committed
125
        if event.inaxes == axis:
Yan's avatar
Yan committed
126
            if event.button == 'up':
Yan's avatar
Yan committed
127
                # zoom in
Yan's avatar
Yan committed
128
                scale_factor = 1/scale
Yan's avatar
Yan committed
129
            elif event.button == 'down':
Yan's avatar
Yan committed
130
                # zoom out
Yan's avatar
Yan committed
131
                scale_factor = scale
Yan's avatar
Yan committed
132
            else:
Yan's avatar
Yan committed
133
                #  should not happen
Yan's avatar
Yan committed
134
135
                scale_factor = 1
                print(event.button)
136
            if QtWidgets.QApplication.keyboardModifiers() !=\
Yan's avatar
Yan committed
137
                    QtCore.Qt.ShiftModifier:
138
                data = event.ydata
Yan's avatar
Yan committed
139
140
                new_top = data + (ax.get_ylim()[1] - data) \
                    * scale_factor
Yan's avatar
Yan committed
141
142
143
144
                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])
145
146
            else:
                data = event.xdata
Yan's avatar
Yan committed
147
148
                x_left = data - ax.get_xlim()[0]
                x_right = ax.get_xlim()[1] - data
Yan's avatar
Yan committed
149
                ax.set_xlim([data - x_left * scale_factor,
Yan's avatar
Yan committed
150
                            data + x_right * scale_factor])
Yan's avatar
Yan committed
151
            if type(pd) is dict and "annotation" in pd:
Yan's avatar
Yan committed
152
                ann_spec(event.inaxes, pd)
153
            ax.figure.canvas.draw()
Yan's avatar
Yan committed
154

Yan's avatar
Yan committed
155
    fig = axis.get_figure()
156
157
    fig.canvas.mpl_connect('scroll_event', lambda event: zoom_fun(
        event, plot_data, axis, base_scale))
Yan's avatar
Yan committed
158
159


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

189
    def drag_fun(event, ax):
Yan's avatar
Yan committed
190
        ax.figure.set_constrained_layout(False)
Yan's avatar
Yan committed
191
192
193
        ax.drag_pan(1, 'x', event.x, event.y)
        ax.figure.canvas.draw()

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

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

Yan's avatar
Yan committed
207

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

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


229
def plot_subtime(augCanvas):
Yan's avatar
Yan committed
230
    """plot averaged spectrum of subselected part of the chromatogram"""
231
232
233
234
235
236
    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()

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

276
    augCanvas.spectplot.set_xlim(slims[0])
Yan's avatar
Yan committed
277
    if not cf.settings().value("view/autozoomy", type=bool):
278
279
280
281
282
283
        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
284
    else:
285
286
287
288
        autozoomy(augCanvas.spectplot)
    ann_spec(augCanvas.spectplot, augCanvas.ms)
    augCanvas.chromplot.set_xlim(chlims[0])
    augCanvas.chromplot.set_ylim(chlims[1])
289
    augCanvas.draw()
290
291


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


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

Yan's avatar
Yan committed
326

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

339

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

    First define the array, in which the annotation should occur.
    Then remove values which are invalid as local maximas. Then select
    local maximas from the array by forcycling. Local maximas are then
    reduced to a representation of the important ones by the sub_peaks
    function"""
348

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

Yan's avatar
Yan committed
366
    peaks = []
3Yan's avatar
3Yan committed
367
368
369
    for line in ms_spec.lines:
        xdata, ydata = line.get_data()
        argvis = dt.argsubselect(xdata, *ms_spec.get_xlim())
370
        # remove tails which cannot be evaluated as maximas
3Yan's avatar
3Yan committed
371
        argvis = argvis[np.where((argvis != 0)
372
                                 & (argvis != (len(xdata)-1)))]
3Yan's avatar
3Yan committed
373
374
375
        lim = ms_spec.get_ylim()[1] * ann_limit
        for i in argvis:
            if ydata[i] > lim and ydata[i] > max(ydata[i-1], ydata[i+1]):
376
                peaks.append((xdata[i], ydata[i]))
377
    s_peaks = sub_peaks(peaks, msdata['texts'],
378
379
                        np.diff(ms_spec.get_xlim()),
                        np.diff(ms_spec.get_ylim()))
Yan's avatar
Yan committed
380

Yan's avatar
Yan committed
381
    # delete objects from the spectra
Yan's avatar
Yan committed
382
    for intensity in msdata['annotation']:
Yan's avatar
Yan committed
383
        intensity.remove()
Yan's avatar
Yan committed
384
    # remove them from tracking
Yan's avatar
Yan committed
385
    msdata['annotation'].clear()
Yan's avatar
Yan committed
386

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

Yan's avatar
Yan committed
397

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

Yan's avatar
Yan committed
422
def legendize(rawlegend, chrom_data):
423
    # sanity check
Yan's avatar
Yan committed
424
425
    if len(rawlegend) == 0:
        return None
426
427
428
    marks = ["-", "+"]
    quads = ["q3", "q1"]

Yan's avatar
Yan committed
429
    def translate(wut):
430
        if chrom_data['machtype'] == 47:
431
            if wut[1] in (0, 1):
432
433
434
435
436
437
                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:])
        elif chrom_data['machtype'] == 57:
Yan's avatar
Yan committed
438
439
440
441
            if int(wut[0]) == 1:
                text = "ms; m/z = {:.1f}-{:.1f}".format(*wut[1:])
            else:
                text = ("ms^{:.0f};"+"".join([" {:.2f}/{:.1f}@{:.1f}V" for _ in
442
443
                        range(int(wut[0])-1)])+"; m/z = {:.1f}-{:.1f}").format(
                    *wut)
Yan's avatar
Yan committed
444
        else:
445
            text = "unknown header type"
Yan's avatar
Yan committed
446
447
        return text
    strdata = [translate(i) for i in np.unique(np.array(rawlegend), axis=0)]
Yan's avatar
Yan committed
448
    strtext = " and\n".join(strdata) + "; t = {:.2f}-{:.2f} min".format(
Yan's avatar
Yan committed
449
                    chrom_data['t_start'], chrom_data['t_end'])
Yan's avatar
Yan committed
450
451
452
    return strtext


453
def populate(augCanvas):
Yan's avatar
Yan committed
454
    """populate the GUI plots with desired dataset"""
455
    if np.array_equal(augCanvas.ds, []):
Yan's avatar
Yan committed
456
        return
457
    [i.clear() for i in (augCanvas.ms['annotation'],
458
     augCanvas.chromplot, augCanvas.spectplot)]
Yan's avatar
Yan committed
459

460
461
    if augCanvas.ms['predict']:
        # TODO: Fix the broken code
462
463
        predict = augCanvas.ms['predict']
        maxm = np.argmax(predict[1]) + predict[0]
3Yan's avatar
3Yan committed
464
465
        maxseek = dt.argsubselect(linex, maxm-.5, maxm+.5)
        maxpos = maxseek[np.argmax(liney[maxseek])]
466
        crudeints = predict[1] * augCanvas.ms['y'][maxpos]
467
        crudemasses = (np.arange(len(predict[1])) + linex[maxpos])
Yan's avatar
Yan committed
468
        pmasses, pints = [], []
469
470
        [pmasses.extend([np.nan, i, i]) for i in crudemasses]
        [pints.extend([np.nan, 0, i]) for i in crudeints]
471
        augCanvas.spectplot.plot(pmasses, pints, linewidth=1)
Yan's avatar
Yan committed
472

473
474
    augCanvas.chrom['t_start'] = augCanvas.ds[0]['chrom_dat'][0, 0]
    augCanvas.chrom['t_end'] = augCanvas.ds[-1]['chrom_dat'][0, -1]
475
    for i, subset in enumerate(augCanvas.ds):
476
477
        if len(augCanvas.ms['headers']) == len(augCanvas.ds):
            legend = legendize(augCanvas.ms['headers'][i], augCanvas.chrom)
Yan's avatar
Yan committed
478
479
        else:
            legend = None
480
        if cf.settings().value("view/oddeven", type=bool):
3Yan's avatar
3Yan committed
481
            msx = subset['masses']
482
            for j in range(2):
3Yan's avatar
3Yan committed
483
484
485
                msy = np.mean(subset['matrix'][j::2], axis=0)
                chromx = subset['chrom_dat'][0, :][j::2]
                chromy = subset['chrom_dat'][1, :][j::2]
486
487
488
489
                pop_plot(msx, msy, augCanvas.spectplot, augCanvas.ms,
                         i*2+j, legend)
                pop_plot(chromx, chromy, augCanvas.chromplot,
                         augCanvas.chrom, i*2+j, legend)
490
        else:
3Yan's avatar
3Yan committed
491
492
493
494
            msx = subset['masses']
            msy = np.mean(subset['matrix'], axis=0)
            chromx = subset['chrom_dat'][0, :]
            chromy = subset['chrom_dat'][1, :]
495
496
497
498
499
            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
500
            ax.legend(loc=2)
Yan's avatar
Yan committed
501
            ax.get_legend().set_in_layout(False)
3Yan's avatar
3Yan committed
502
503
        ax.autoscale(True)
        ax.set_ylim(ax.get_ylim()[1]*-0.01, ax.get_ylim()[1]*1.1)
504
        augCanvas.draw()
3Yan's avatar
3Yan committed
505
    return
Yan's avatar
Yan committed
506
507


508
509
510
def update_paramstable(augCanvas):
    if len(augCanvas.ms['params']) == 0:
        augCanvas.paramstable.setRowCount(0)
Yan's avatar
Yan committed
511
        return
512
513
514
515
516
517
    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]))
518
    for row, paramname in enumerate(augCanvas.ms['params'][0]):
519
520
521
        [augCanvas.paramstable.setItem(row, col, QtWidgets.QTableWidgetItem())
         for col in range(1, 3)]
        augCanvas.paramstable.setCellWidget(row, 0, QtWidgets.QCheckBox())
522
        if states:
523
524
            augCanvas.paramstable.cellWidget(row, 0).setCheckState(states[row])
        augCanvas.paramstable.item(row, 1).setText(paramname)
525
        vals = [param[row] for param in augCanvas.ms['params'][1]
526
                if (param[0] >= augCanvas.chrom['t_start'] and
527
                param[0] <= augCanvas.chrom['t_end'])]
Yan's avatar
Yan committed
528
        if len(vals) == 0:
Yan's avatar
Yan committed
529
            text = ""
Yan's avatar
Yan committed
530
531
532
533
534
535
536
537
        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)
538
        augCanvas.paramstable.item(row, 2).setText(text)