drltools.py 17 KB
Newer Older
Yan's avatar
Yan committed
1
2
3
4
5
#!/usr/bin/env python3
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from PyQt5 import QtCore
from PyQt5 import QtWidgets
6
from PyQt5 import QtGui
Yan's avatar
Yan committed
7
from PyQt5 import QtPrintSupport
Yan's avatar
Yan committed
8
9
import matplotlib
import numpy as np
Yan's avatar
Yan committed
10
11
import prasopes.datatools as dt
import prasopes.graphtools as gt
Yan's avatar
Yan committed
12
import prasopes.filetools as ft
Yan's avatar
Yan committed
13
14
matplotlib.use("Qt5Agg")

Yan's avatar
Yan committed
15

Yan's avatar
Yan committed
16
class HBar(QtWidgets.QFrame):
17
    """horizontal bar class"""
Yan's avatar
Yan committed
18
19
20
21
22
23
    def __init__(self):
        super(HBar, self).__init__()
        self._main = QtWidgets.QWidget()
        self.setFrameShape(QtWidgets.QFrame.HLine)


Yan's avatar
Yan committed
24
def update_profile(start, end, spectrum, dataset):
25
    """spectrum updating procedure"""
Yan's avatar
Yan committed
26
27
    # Dont do anything to graph when the spectrum is not populated
    if isinstance(dataset['masses'], type(None)):
28
29
        return

Yan's avatar
Yan committed
30
31
    masses = dataset['masses']
    massargs = dt.argsubselect(masses, start, end)
32
    yshape = np.mean(dataset['matrix'], axis=0)
Yan's avatar
Yan committed
33
34
    spectrum.clear()
    dots_x = masses
35
    dots_y = yshape
Yan's avatar
Yan committed
36
37
    full_x = masses[massargs]
    full_y = yshape[massargs]
38
39
    spectrum.plot(dots_x, dots_y, ':', color='gray')
    spectrum.plot(full_x, full_y, 'r')
Yan's avatar
Yan committed
40
41
42
43
    xex = (masses[massargs[-1]]-masses[massargs[0]])*0.25
    spectrum.set_xlim(masses[massargs[0]]-xex,
                      masses[massargs[-1]]+xex)
    ymax = max(yshape[massargs])
44
45
46
    spectrum.set_ylim(ymax*-0.1, ymax*1.2)
    spectrum.figure.canvas.draw()

Yan's avatar
Yan committed
47

Yan's avatar
Yan committed
48
49
def get_daughterset(ptable, dtable, ds):
    names = []
Yan's avatar
Yan committed
50
    times = ds['chrom_dat'][0, :]
Yan's avatar
Yan committed
51
    intensities = []
Yan's avatar
Yan committed
52
    # TODO: resolve intensities trouble
Yan's avatar
Yan committed
53
    for row in range(dtable.rowCount()):
Yan's avatar
Yan committed
54
        if dtable.cellWidget(row, 0).checkState() == 2:
Yan's avatar
Yan committed
55
56
            startm = dt.floatize(ptable.cellWidget(row, 1).text())
            endm = dt.floatize(ptable.cellWidget(row, 2).text())
Yan's avatar
Yan committed
57
58
59
            massargs = dt.argsubselect(ds['masses'], startm, endm)
            intensity = (np.sum(
                ds['matrix'].T[massargs].T, axis=1)) / ds['chrom_dat'][1]
60
61
            cor = dtable.cellWidget(row, 1).currentIndex() -1
            if cor not in (-2, -1):
Yan's avatar
Yan committed
62
63
64
                factor = dt.floatize(dtable.cellWidget(row, 2).text())
                startm = dt.floatize(ptable.cellWidget(cor, 1).text())
                endm = dt.floatize(ptable.cellWidget(cor, 2).text())
Yan's avatar
Yan committed
65
                massargs = dt.argsubselect(ds['masses'], startm, endm)
Yan's avatar
Yan committed
66
                correction = ((np.sum(
Yan's avatar
Yan committed
67
                    ds['matrix'].T[massargs].T, axis=1))
Yan's avatar
Yan committed
68
69
                              / ds['chrom_dat'][1]) * factor
                intensity = intensity - correction
Yan's avatar
Yan committed
70
            intensities.append(intensity)
Yan's avatar
Yan committed
71
            names.append(dtable.item(row, 0).text())
Yan's avatar
Yan committed
72
73
74
75
    return names, times, intensities


def update_drlspectrum(ptable, dtable, ds, drlspectrum):
Yan's avatar
Yan committed
76
77
    # Dont do when the dataset is not populated
    if isinstance(ds['masses'], type(None)):
Yan's avatar
Yan committed
78
        return
79
80
81
82
    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]])
Yan's avatar
Yan committed
83
84
85
86

    names, times, intensities = get_daughterset(ptable, dtable, ds)
    for i in range(len(drlspectrum.lines)):
        drlspectrum.lines[0].remove()
87

88
    i = 0
89
    for row in range(dtable.rowCount()):
Yan's avatar
Yan committed
90
91
        if dtable.cellWidget(row, 0).checkState() == 2:
            dtable.item(row, 0).setBackground(QtGui.QBrush(
92
93
94
95
96
                QtGui.QColor(*colors[row % len(colors)], alpha=50)))
            label = " {}".format(ptable.cellWidget(row, 0).text())
            drlspectrum.plot(times, intensities[i], label=label,
                             color=(colors[row % len(colors)] / 255))
            i += 1
97
        else:
Yan's avatar
Yan committed
98
            dtable.item(row, 0).setBackground(QtGui.QBrush())
99

100
101
102
103
104
    if len(names) != 0:
        drlspectrum.set_ylim(top=np.amax(intensities)*1.1,
                             bottom=np.amax(intensities)*-0.01)
        drlspectrum.legend(loc=2)
        drlspectrum.figure.canvas.draw()
Yan's avatar
Yan committed
105

Yan's avatar
Yan committed
106
def gettableitemlist(ptable):
107
    ion_list = []
Yan's avatar
Yan committed
108
109
110
    for row in range(ptable.rowCount()):
        text = []
        for i in range(3):
Yan's avatar
Yan committed
111
            if not isinstance(ptable.cellWidget(row, i), type(None)):
Yan's avatar
Yan committed
112
113
114
115
116
117
                frg = ptable.cellWidget(row, i).text()
            else:
                frg = ""
            text.append(frg)
        line = "{} ({}-{})".format(*text)
        ion_list.append(line)
118
119
120
    return ion_list


Yan's avatar
Yan committed
121
122
def update_drl(start_mz, end_mz, spectrum, dataset, pname,
               ptable, dtable, drlspectrum):
Yan's avatar
Yan committed
123
124
    """cares that masses are in order and valid, then refresh tables"""
    for line in start_mz, end_mz:
Yan's avatar
Yan committed
125
126
127
        status = QtGui.QDoubleValidator().validate(line.text(), 0)[0]
        if status != QtGui.QValidator.Acceptable:
            line.setText("0")
Yan's avatar
Yan committed
128

Yan's avatar
Yan committed
129
130
    start = dt.floatize(start_mz.text())
    end = dt.floatize(end_mz.text())
131
132
133

    if start > end:
        start, end = end, start
134
135
136

    if float(0) not in (start, end) and pname.text() is "":
        pname.setText(str(int((start+end)/2)))
137

138

Yan's avatar
Yan committed
139
    ptnames = gettableitemlist(ptable)
Yan's avatar
Yan committed
140
    for row in range(dtable.rowCount()):
Yan's avatar
Yan committed
141
142
143
144
145
146
        dtable.item(row, 0).setText(ptnames[row])
        index = dtable.cellWidget(row, 1).currentIndex()
        dtable.cellWidget(row, 1).clear()
        dtable.cellWidget(row, 1).addItem("")
        dtable.cellWidget(row, 1).addItems(gettableitemlist(ptable))
        dtable.cellWidget(row, 1).setCurrentIndex(index)
Yan's avatar
Yan committed
147

Yan's avatar
Yan committed
148
149
    update_profile(start, end, spectrum, dataset)
    update_drlspectrum(ptable, dtable, dataset, drlspectrum)
150
151
152


def remove_rows(ptable, dtable):
Yan's avatar
Yan committed
153
    # TODO: maybe nicer selection in future, but this works for now
154
    rows = reversed(list(set(
Yan's avatar
Yan committed
155
        map(lambda x: x.row(), ptable.selectedIndexes()))))
156
157
158
159
    for row in rows:
        dtable.removeRow(row)
        ptable.removeRow(row)
        for i in range(dtable.rowCount()):
Yan's avatar
Yan committed
160
161
162
163
            index = dtable.cellWidget(i, 1).currentIndex()
            dtable.cellWidget(i, 1).clear()
            dtable.cellWidget(i, 1).addItem("")
            dtable.cellWidget(i, 1).addItems(gettableitemlist(ptable))
164
            if index == row+1:
Yan's avatar
Yan committed
165
                dtable.cellWidget(i, 1).setCurrentIndex(0)
166
            elif index > row+1:
Yan's avatar
Yan committed
167
                dtable.cellWidget(i, 1).setCurrentIndex(index-1)
168
169


Yan's avatar
Yan committed
170
def setdoublecell(table, row, column):
171
    """populate table cell with float-validated posititve text"""
Yan's avatar
Yan committed
172
    table.setCellWidget(row, column, QtWidgets.QLineEdit())
173
174
    validator = QtGui.QDoubleValidator()
    validator.setBottom(0)
Yan's avatar
Yan committed
175
176
177
    table.cellWidget(row, column).setValidator(validator)
    table.cellWidget(row, column).setFrame(False)
    table.cellWidget(row, column).setText("0")
178
179
    table.horizontalHeader().setSectionResizeMode(
            column, QtWidgets.QHeaderView.ResizeToContents)
Yan's avatar
Yan committed
180
    return table.cellWidget(row, column)
181
182


Yan's avatar
Yan committed
183
def add_line(ds, parenttable, daughtertable, drlspectrum):
184
185
    """add parent ion to the table"""
    ion_graph = Figure(figsize=(3, 1.5), dpi=100, facecolor="None")
Yan's avatar
Yan committed
186
187
    ionspect = ion_graph.add_subplot(
        111, facecolor=(1, 1, 1, 0.8), position=(-0.01, -0.01, 1.02, 1.02))
188
189
190
191
192
    graph_canvas = FigureCanvas(ion_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)

    newrow = parenttable.rowCount()
193

194
195
196
197
    parenttable.setRowCount(newrow + 1)
    pname = QtWidgets.QLineEdit()
    pname.setFrame(False)
    parenttable.setCellWidget(newrow, 0, pname)
Yan's avatar
Yan committed
198
199
    start_mz = setdoublecell(parenttable, newrow, 1)
    end_mz = setdoublecell(parenttable, newrow, 2)
200
    parenttable.setCellWidget(newrow, 3, graph_canvas)
201
202
203
204
205
    if newrow is not 0:
        for i in range(3):
            parenttable.cellWidget(newrow, i).setText(
                str(dt.floatize(
                    parenttable.cellWidget(newrow-1, i).text())+1))
206

207
    daughtertable.setRowCount(newrow + 1)
Yan's avatar
Yan committed
208

Yan's avatar
Yan committed
209
    checkbox = QtWidgets.QCheckBox()
210
211
    dname = QtWidgets.QTableWidgetItem()
    dname.setFlags(dname.flags() & ~QtCore.Qt.ItemIsEditable)
Yan's avatar
Yan committed
212
    dname.setTextAlignment(QtCore.Qt.AlignRight)
Yan's avatar
Yan committed
213
214
    daughtertable.setItem(newrow, 0, dname)
    daughtertable.setCellWidget(newrow, 0, checkbox)
215

216
217
218
    corto = QtWidgets.QComboBox()
    corto.setFrame(False)
    corto.addItem("")
Yan's avatar
Yan committed
219
    corto.addItems(gettableitemlist(parenttable))
Yan's avatar
Yan committed
220
    daughtertable.setCellWidget(newrow, 1, corto)
221

Yan's avatar
Yan committed
222
    factor = setdoublecell(daughtertable, newrow, 2)
223

Yan's avatar
Yan committed
224
225
    update_drl(start_mz, end_mz, ionspect, ds, pname,
               parenttable, daughtertable, drlspectrum)
226

Yan's avatar
Yan committed
227
    pname.editingFinished.connect(lambda: update_drl(
Yan's avatar
Yan committed
228
        start_mz, end_mz, ionspect, ds, pname, parenttable,
Yan's avatar
Yan committed
229
        daughtertable, drlspectrum))
230
    start_mz.editingFinished.connect(lambda: update_drl(
Yan's avatar
Yan committed
231
        start_mz, end_mz, ionspect, ds, pname, parenttable,
Yan's avatar
Yan committed
232
        daughtertable, drlspectrum))
233
    end_mz.editingFinished.connect(lambda: update_drl(
Yan's avatar
Yan committed
234
        start_mz, end_mz, ionspect, ds, pname, parenttable,
Yan's avatar
Yan committed
235
236
237
        daughtertable, drlspectrum))
    checkbox.stateChanged.connect(lambda: update_drlspectrum(
        parenttable, daughtertable, ds, drlspectrum))
Yan's avatar
Yan committed
238
239
240
241
    corto.currentIndexChanged.connect(lambda: update_drlspectrum(
        parenttable, daughtertable, ds, drlspectrum))
    factor.editingFinished.connect(lambda: update_drlspectrum(
        parenttable, daughtertable, ds, drlspectrum))
242
243


Yan's avatar
Yan committed
244
def iontable(labels):
245
246
    """creates a table for ions"""
    table = QtWidgets.QTableWidget(columnCount=len(labels))
247
    table.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
248
249
                        QtWidgets.QSizePolicy.Expanding)
    table.setHorizontalHeaderLabels(labels)
250
251
252
253
254
    table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)

    for n in range(table.columnCount()):
        table.horizontalHeader().setSectionResizeMode(
            n, QtWidgets.QHeaderView.Stretch)
Yan's avatar
Yan committed
255
    table.setMinimumSize(600, 0)
256

257
    return table
258
259


Yan's avatar
Yan committed
260
261
262
263
264
265
266
267
268
269
270
271
272
273
def load_drltables(parent, ptable, dtable, dataset, drlspectrum):
    filename = QtWidgets.QFileDialog.getOpenFileName(
            caption="Load DRL config tables",
            filter="comma-separated values (*.csv)")[0]
    if filename is not '':
        names = []
        start_masses = []
        end_masses = []
        states = []
        corrected_to = []
        corr_factors = []

        with open(filename, 'r') as cfile:
            rawdata = cfile.read().splitlines()
Yan's avatar
Yan committed
274
275
        for i in range(1, len(rawdata)):
            rawline = rawdata[i].split(",")
Yan's avatar
Yan committed
276
277
278
279
280
281
282
283
            if len(rawline) != 6 or int(rawline[3]) not in range(3) \
                    or int(rawline[4]) not in range(len(rawdata)):
                QtWidgets.QMessageBox.warning(
                    parent, "Load DRL config tables",
                    "Config file corrupted on line {},"
                    " cancelling request".format(i+1))
                return
            for j, k in enumerate((names, start_masses, end_masses,
Yan's avatar
Yan committed
284
                                   states, corrected_to, corr_factors)):
Yan's avatar
Yan committed
285
                k.append(rawline[j])
Yan's avatar
Yan committed
286
287
288
        for row in reversed(range(ptable.rowCount())):
            dtable.removeRow(row)
            ptable.removeRow(row)
Yan's avatar
Yan committed
289
        # first populate only parent table
Yan's avatar
Yan committed
290
        for i in range(len(names)):
Yan's avatar
Yan committed
291
            add_line(dataset, ptable, dtable, drlspectrum)
Yan's avatar
Yan committed
292
293
294
            ptable.cellWidget(i, 0).setText(names[i])
            ptable.cellWidget(i, 1).setText(start_masses[i])
            ptable.cellWidget(i, 2).setText(end_masses[i])
Yan's avatar
Yan committed
295
        # and after that daughter table
Yan's avatar
Yan committed
296
        for i in range(len(names)):
Yan's avatar
Yan committed
297
            dtable.cellWidget(i, 1).setCurrentIndex(
Yan's avatar
Yan committed
298
                int(corrected_to[i]))
Yan's avatar
Yan committed
299
300
            dtable.cellWidget(i, 2).setText(corr_factors[i])
            dtable.cellWidget(i, 0).setCheckState(int(states[i]))
Yan's avatar
Yan committed
301
302


Yan's avatar
Yan committed
303
304
305
306
307
308
309
310
311
312
313
314
def save_drlconfig(ptable, dtable, parent):
    """safe DRL table layout so it can be summoned when needed"""
    exp_f_name = ft.get_save_filename(
        "Save DRL table layout", "comma-separated values (*.csv)",
        "csv", parent)
    if exp_f_name is not '':
        expf = open(exp_f_name, 'w')
        expf.write("#ion_name, start m/z, end m/z, visible,"
                   "corrected_to, factor\n")
        for row in range(ptable.rowCount()):
            vals = []
            for i in range(3):
Yan's avatar
Yan committed
315
316
317
318
                vals.append(ptable.cellWidget(row, i).text())
            vals.append(dtable.cellWidget(row, 0).checkState())
            vals.append(dtable.cellWidget(row, 1).currentIndex())
            vals.append(dtable.cellWidget(row, 2).text())
Yan's avatar
Yan committed
319
320
321
            expf.write("{}\n".format((",".join(map(str, vals)))))
        expf.close()

Yan's avatar
Yan committed
322

Yan's avatar
Yan committed
323
324
325
326
327
328
329
330
331
332
333
334
335
def export_drlspectrum(parent, fn, ptable, dtable, ds):
    if fn[0] is None:
        QtWidgets.QMessageBox.warning(
            main_window, "Export DRL dataset",
            "Nothing to export, cancelling request")
        return
    names, times, intensities = get_daughterset(ptable, dtable, ds)
    exp_f_name = ft.get_save_filename(
        "Export DRL data", "comma-separated values (*.csv)", "csv", parent)
    if exp_f_name is not '':
        expf = open(exp_f_name, 'w')
        expf.write("times, {}\n".format((",".join(names))))
        for i in range(len(times)):
Yan's avatar
Yan committed
336
            dataset = list()
Yan's avatar
Yan committed
337
338
339
340
341
342
            dataset.append(times[i])
            for intensity in intensities:
                dataset.append(intensity[i])
            expf.write("{}\n".format((",".join(map(str, dataset)))))
        expf.close()

Yan's avatar
Yan committed
343

Yan's avatar
Yan committed
344
def print_graph(labels, ptable, dtable, ds):
Yan's avatar
Yan committed
345
    printfig = Figure(figsize=(5, 2), dpi=100)
Yan's avatar
Yan committed
346
347
348
349
    printplot = printfig.add_subplot(111)
    printcanvas = FigureCanvas(printfig)
    gt.pop_plot(printplot, labels)
    update_drlspectrum(ptable, dtable, ds, printplot)
Yan's avatar
Yan committed
350
    widget = QtWidgets.QDialog(None, windowTitle='Print preview')
Yan's avatar
Yan committed
351
352
    layout = QtWidgets.QVBoxLayout(widget)
    layout.addWidget(printcanvas)
Yan's avatar
Yan committed
353
    widget.resize(600, 400)
Yan's avatar
Yan committed
354
355
356
357
358
359
360
    widget.show()
    dialog = QtPrintSupport.QPrintDialog()
    if dialog.exec_() == QtWidgets.QDialog.Accepted:
        printcanvas.render(dialog.printer())
    widget.close()


Yan's avatar
Yan committed
361
def main_window(parent, ds, filename, cache):
362
    """constructs a dialog window"""
Yan's avatar
Yan committed
363
364
    def saveonclose(widget, event, buffer, ptable, dautable, canvas):
        buffer[0], buffer[1], buffer[2] = ptable, dautable, canvas
Yan's avatar
Yan committed
365
        QtWidgets.QMainWindow.closeEvent(widget, event)
Yan's avatar
Yan committed
366

Yan's avatar
Yan committed
367
    window = QtWidgets.QMainWindow(
Yan's avatar
Yan committed
368
        parent, windowTitle='Delayed reactant labelling')
Yan's avatar
Yan committed
369
370
    main_widget = QtWidgets.QWidget(window)
    window.setCentralWidget(main_widget)
Yan's avatar
Yan committed
371

Yan's avatar
Yan committed
372
    window.closeEvent = lambda event: saveonclose(
Yan's avatar
Yan committed
373
        window, event, cache, pt, dtable, graph_canvas)
Yan's avatar
Yan committed
374

Yan's avatar
Yan committed
375
376
    dial_graph = Figure(figsize=(5, 2), dpi=100, facecolor="None")
    chromplot = dial_graph.add_subplot(111, facecolor=(1, 1, 1, 0.8))
Yan's avatar
Yan committed
377
378
379
    graph_canvas = FigureCanvas(dial_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
Yan's avatar
Yan committed
380
    graphlabels = dict(x=[0], y=[0], line=None, name="",
Yan's avatar
Yan committed
381
382
                       xlabel="time(min)",
                       ylabel="relative intensity")
Yan's avatar
Yan committed
383
384
385
386
    gt.pan_factory(chromplot)
    gt.zoom_factory(chromplot, 1.15)
    gt.pop_plot(chromplot, graphlabels)

387
388
389
    drl_load = QtWidgets.QPushButton("&Load")
    drl_save = QtWidgets.QPushButton("&Save")
    drl_export = QtWidgets.QPushButton("&Export")
Yan's avatar
Yan committed
390
    drl_print = QtWidgets.QPushButton("&Print")
391
    close = QtWidgets.QPushButton("&Close")
Yan's avatar
Yan committed
392
    close.clicked.connect(window.close)
393

Yan's avatar
Yan committed
394
395
396
    btn_add = QtWidgets.QPushButton("&Add")
    btn_rem = QtWidgets.QPushButton("Remove")

397
398
    # pt = parenttable
    # dt = daughtertable
Yan's avatar
Yan committed
399
    if cache == [None, None, None]:
Yan's avatar
Yan committed
400
        dtable = iontable(["Name", "corrected for", "factor"])
401

Yan's avatar
Yan committed
402
        pt = iontable(["Name", "start (m/z)", "end (m/z)", "profile"])
Yan's avatar
Yan committed
403
        add_line(ds, pt, dtable, chromplot)
Yan's avatar
Yan committed
404
405
    else:
        pt = cache[0]
Yan's avatar
Yan committed
406
        dtable = cache[1]
Yan's avatar
Yan committed
407
        graph_canvas = cache[2]
408
409

    btn_add.clicked.connect(lambda: add_line(
Yan's avatar
Yan committed
410
411
        ds, pt, dtable, chromplot))
    btn_rem.clicked.connect(lambda: remove_rows(pt,dtable))
Yan's avatar
Yan committed
412
    drl_load.clicked.connect(lambda: load_drltables(
Yan's avatar
Yan committed
413
        main_widget, pt, dtable, ds, chromplot))
Yan's avatar
Yan committed
414
    drl_save.clicked.connect(lambda: save_drlconfig(
Yan's avatar
Yan committed
415
        pt, dtable, main_widget))
Yan's avatar
Yan committed
416
    drl_print.clicked.connect(lambda: print_graph(
Yan's avatar
Yan committed
417
        graphlabels, pt, dtable, ds))
Yan's avatar
Yan committed
418
    drl_export.clicked.connect(lambda: export_drlspectrum(
Yan's avatar
Yan committed
419
        main_widget, filename, pt, dtable, ds))
420

Yan's avatar
Yan committed
421
    main_layout = QtWidgets.QVBoxLayout(main_widget)
Yan's avatar
Yan committed
422
423
    sub_layout = QtWidgets.QHBoxLayout()
    tablelayout = QtWidgets.QVBoxLayout()
Yan's avatar
Yan committed
424
    pt_butlayout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
425
    main_butlayout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
426

Yan's avatar
Yan committed
427
428
429
430
    pt_butlayout.addWidget(btn_add)
    pt_butlayout.addWidget(btn_rem)
    pt_butlayout.addStretch(0)

431
432
    main_layout.addLayout(sub_layout)
    main_layout.addWidget(HBar())
Yan's avatar
Yan committed
433
    main_layout.addLayout(main_butlayout)
434

Yan's avatar
Yan committed
435
436
    main_butlayout.addWidget(drl_load)
    main_butlayout.addWidget(drl_save)
Yan's avatar
Yan committed
437
    main_butlayout.addWidget(drl_print)
Yan's avatar
Yan committed
438
439
    main_butlayout.addStretch(1)
    main_butlayout.addWidget(drl_export)
440
    main_butlayout.addWidget(close)
Yan's avatar
Yan committed
441

442
    sub_layout.addWidget(graph_canvas, stretch=1)
Yan's avatar
Yan committed
443
    sub_layout.addLayout(tablelayout)
444

Yan's avatar
Yan committed
445
446
447
448
    tablelayout.addWidget(QtWidgets.QLabel("Raw ions table:"))
    tablelayout.addWidget(pt)
    tablelayout.addLayout(pt_butlayout)
    tablelayout.addWidget(QtWidgets.QLabel("Corrected ions table:"))
Yan's avatar
Yan committed
449
    tablelayout.addWidget(dtable)
450

Yan's avatar
Yan committed
451
    window.show()