drltools.py 18 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)


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def floatize(table, row, column):
    """grabs the tableWidgetItem and transforms its text safely to
    float, if the text is not acceptable as float, returns zero"""
    imptext = table.item(row, column).text()
    validator = QtGui.QDoubleValidator()
    validator.setBottom(0)
    status = validator.validate(imptext, 0)[0]
    if status == QtGui.QValidator.Acceptable:
        outfloat = float(imptext)
    else:
        outfloat = 0
    return outfloat


def update_profile(pt, row, dataset):
39
    """spectrum updating procedure"""
Yan's avatar
Yan committed
40
41
    # Dont do anything to graph when the spectrum is not populated
    if isinstance(dataset['masses'], type(None)):
42
43
        return

44
45
46
    start = floatize(pt, row, 1)
    end = floatize(pt, row, 2)
    spectrum = pt.cellWidget(row, 3).figure.get_axes()[0]
Yan's avatar
Yan committed
47
48
    masses = dataset['masses']
    massargs = dt.argsubselect(masses, start, end)
49
    yshape = np.mean(dataset['matrix'], axis=0)
Yan's avatar
Yan committed
50
51
    spectrum.clear()
    dots_x = masses
52
    dots_y = yshape
Yan's avatar
Yan committed
53
54
    full_x = masses[massargs]
    full_y = yshape[massargs]
55
56
    spectrum.plot(dots_x, dots_y, ':', color='gray')
    spectrum.plot(full_x, full_y, 'r')
Yan's avatar
Yan committed
57
58
59
60
    xex = (masses[massargs[-1]]-masses[massargs[0]])*0.25
    spectrum.set_xlim(masses[massargs[0]]-xex,
                      masses[massargs[-1]]+xex)
    ymax = max(yshape[massargs])
61
62
63
    spectrum.set_ylim(ymax*-0.1, ymax*1.2)
    spectrum.figure.canvas.draw()

Yan's avatar
Yan committed
64

Yan's avatar
Yan committed
65
66
67
68
69
70
71
72
73
def get_intensity(row, ptable, dtable, ds):
    startm = floatize(ptable, row, 1)
    endm = floatize(ptable, row, 2)
    massargs = dt.argsubselect(ds['masses'], startm, endm)
    intensity = (np.sum(
        ds['matrix'].T[massargs].T, axis=1)) / ds['chrom_dat'][1]
    return intensity


Yan's avatar
Yan committed
74
def get_daughterset(ptable, dtable, ds):
Yan's avatar
Yan committed
75
    # TODO: write a less resources demanding function - probably "per-line"
Yan's avatar
Yan committed
76
    names = []
Yan's avatar
Yan committed
77
    times = ds['chrom_dat'][0, :]
Yan's avatar
Yan committed
78
    intensities = []
Yan's avatar
Yan committed
79
    # TODO: resolve intensities trouble
Yan's avatar
Yan committed
80
    for row in range(dtable.rowCount()):
Yan's avatar
Yan committed
81
        if dtable.cellWidget(row, 0).checkState() == 2:
Yan's avatar
Yan committed
82
            intensity = get_intensity(row, ptable, dtable, ds)
83
84
            cor = dtable.cellWidget(row, 1).currentIndex() - 1
            # TODO: check if cor still produce the mess or it started to behave
85
            if cor not in (-2, -1):
86
                factor = floatize(dtable, row, 2)
Yan's avatar
Yan committed
87
88
                correction = get_intensity(cor, ptable, dtable, ds)\
                    * factor
Yan's avatar
Yan committed
89
                intensity = intensity - correction
Yan's avatar
Yan committed
90
            intensities.append(intensity)
Yan's avatar
Yan committed
91
92
93
94
            names.append("{} - {} * {}".format(
                dtable.item(row, 0).text(),
                dtable.item(row,2).text(),
                dtable.cellWidget(row,1).currentText()))
Yan's avatar
Yan committed
95
96
97
98
    return names, times, intensities


def update_drlspectrum(ptable, dtable, ds, drlspectrum):
99
    # Dont do anything when the dataset is not populated
Yan's avatar
Yan committed
100
    if isinstance(ds['masses'], type(None)):
Yan's avatar
Yan committed
101
        return
102
    colors = np.array([[0, 0, 0], [255, 0, 0], [0, 255, 0], [0, 0, 255],
103
104
105
                       [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
106

107
    # TODO: write a less resources demanding function
Yan's avatar
Yan committed
108
109
110
    names, times, intensities = get_daughterset(ptable, dtable, ds)
    for i in range(len(drlspectrum.lines)):
        drlspectrum.lines[0].remove()
111

112
    i = 0
113
    for row in range(dtable.rowCount()):
Yan's avatar
Yan committed
114
        if dtable.cellWidget(row, 0).checkState() == 2:
115
            dtable.blockSignals(True)
Yan's avatar
Yan committed
116
            dtable.item(row, 0).setBackground(QtGui.QBrush(
117
                QtGui.QColor(*colors[row % len(colors)], alpha=50)))
118
119
            dtable.blockSignals(False)
            label = " {}".format(ptable.item(row, 0).text())
120
121
122
            drlspectrum.plot(times, intensities[i], label=label,
                             color=(colors[row % len(colors)] / 255))
            i += 1
123
        else:
Yan's avatar
Yan committed
124
            dtable.item(row, 0).setBackground(QtGui.QBrush())
125

126
127
128
129
    if len(names) != 0:
        drlspectrum.set_ylim(top=np.amax(intensities)*1.1,
                             bottom=np.amax(intensities)*-0.01)
        drlspectrum.legend(loc=2)
130
131
    drlspectrum.figure.canvas.draw()

Yan's avatar
Yan committed
132

Yan's avatar
Yan committed
133
def gettableitemlist(ptable):
134
    ion_list = []
Yan's avatar
Yan committed
135
136
137
    for row in range(ptable.rowCount()):
        text = []
        for i in range(3):
138
139
            if not isinstance(ptable.item(row, i), type(None)):
                frg = ptable.item(row, i).text()
Yan's avatar
Yan committed
140
141
142
143
144
            else:
                frg = ""
            text.append(frg)
        line = "{} ({}-{})".format(*text)
        ion_list.append(line)
145
146
147
    return ion_list


148
149
150
151
152
153
154
155
156
157
158
159
def update_corrfors(ptable, dtable):
    """update corrections selection layout of the daughter table"""
    ionlist = gettableitemlist(ptable)
    for row in range(dtable.rowCount()):
        corfor = dtable.cellWidget(row, 1)
        index = corfor.currentIndex()
        corfor.blockSignals(True)
        corfor.clear()
        corfor.addItem("")
        corfor.addItems(ionlist)
        corfor.setCurrentIndex(index)
        corfor.blockSignals(False)
Yan's avatar
Yan committed
160

161

Yan's avatar
Yan committed
162
163
def ptable_changed(row, column, ptable, dtable, ds, drlspectrum,
                   addline=True):
164
165
166
167
168
    """routine called by change of the ptable spectra"""
    update_corrfors(ptable, dtable)
    dtable.item(row, 0).setText(gettableitemlist(ptable)[row])
    if column in (1, 2):
        update_profile(ptable, row, ds)
Yan's avatar
Yan committed
169
170
    if row == ptable.rowCount() - 1 and addline == True:
        add_line(ds, ptable, dtable, drlspectrum)
171

172

173
174
175
176
177
178
179
def dtable_changed(row, column, ptable, dtable, ds, drlspectrum):
    """routine called by change of the dtable spectra"""
    if dtable.cellWidget(row, 0).checkState() == 2:
        if (column == 0)\
           or (column == 2
               and dtable.cellWidget(row, 1).currentIndex() != 0):
                update_drlspectrum(ptable, dtable, ds, drlspectrum)
180

Yan's avatar
Yan committed
181

182
183
184
185
186
def corr_changed(row, ptable, dtable, ds, drlspectrum):
    """routine called by change of correction for ion"""
    if (dtable.cellWidget(row, 0).checkState() == 2
       and floatize(dtable, row, 2) != 0):
        update_drlspectrum(ptable, dtable, ds, drlspectrum)
187
188


189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
def delete_row(row, ptable, dtable, ds, drlspectrum):
    dtable.cellWidget(row,0).setCheckState(0)
    dtable.removeRow(row)
    ptable.removeRow(row)
    for i in range(dtable.rowCount()):
        corfor = dtable.cellWidget(i, 1)
        corfor.disconnect()
        index = corfor.currentIndex()
        corfor.clear()
        corfor.addItem("")
        corfor.addItems(gettableitemlist(ptable))
        if index == row+1:
            corfor.setCurrentIndex(0)
            corr_changed(i, ptable, dtable, ds, drlspectrum)
        elif index > row+1:
            corfor.setCurrentIndex(index-1)
        else:
            corfor.setCurrentIndex(index)
        corfor.currentIndexChanged.connect(lambda: corr_changed(
            i, ptable, dtable, ds, drlspectrum))


211
def remove_rows(ptable, dtable, ds, drlspectrum):
Yan's avatar
Yan committed
212
    # TODO: maybe nicer selection in future, but this works for now
213
    rows = reversed(list(set(
Yan's avatar
Yan committed
214
        map(lambda x: x.row(), ptable.selectedIndexes()))))
215
    for row in rows:
216
        delete_row(row, ptable, dtable, ds, drlspectrum)
217
218


Yan's avatar
Yan committed
219
def add_line(ds, parenttable, daughtertable, drlspectrum):
220
    """add parent ion to the table"""
221
222
223
224
225
226
227
228
229
230
231
232
    newrow = parenttable.rowCount()

    parenttable.blockSignals(True)
    daughtertable.blockSignals(True)

    parenttable.setRowCount(newrow + 1)
    for i in range(3):
        parenttable.setItem(newrow, i, QtWidgets.QTableWidgetItem())
        if newrow is not 0:
            parenttable.item(newrow, i).setText(str(floatize(
                    parenttable, newrow-1, i)+1))

233
    ion_graph = Figure(figsize=(3, 1.5), dpi=100, facecolor="None")
234
235
    ion_graph.add_subplot(111, facecolor=(1, 1, 1, 0.8),
                          position=(-0.01, -0.01, 1.02, 1.02))
236
237
238
239
    graph_canvas = FigureCanvas(ion_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
    parenttable.setCellWidget(newrow, 3, graph_canvas)
240

241
    daughtertable.setRowCount(newrow + 1)
Yan's avatar
Yan committed
242
    checkbox = QtWidgets.QCheckBox()
243
244
    dname = QtWidgets.QTableWidgetItem()
    dname.setFlags(dname.flags() & ~QtCore.Qt.ItemIsEditable)
Yan's avatar
Yan committed
245
    dname.setTextAlignment(QtCore.Qt.AlignRight)
Yan's avatar
Yan committed
246
247
    daughtertable.setItem(newrow, 0, dname)
    daughtertable.setCellWidget(newrow, 0, checkbox)
248
249
250
251
252
253
254
255
    corfor = QtWidgets.QComboBox()
    corfor.setFrame(False)
    daughtertable.setCellWidget(newrow, 1, corfor)
    daughtertable.setItem(newrow, 2, QtWidgets.QTableWidgetItem())

    parenttable.blockSignals(False)
    daughtertable.blockSignals(False)

Yan's avatar
Yan committed
256
257
    ptable_changed(newrow, 1, parenttable, daughtertable, ds,
                   drlspectrum, False)
258

Yan's avatar
Yan committed
259
260
    checkbox.stateChanged.connect(lambda: update_drlspectrum(
        parenttable, daughtertable, ds, drlspectrum))
261
262
    corfor.currentIndexChanged.connect(lambda: corr_changed(
        newrow, parenttable, daughtertable, ds, drlspectrum))
263
264


Yan's avatar
Yan committed
265
def iontable(labels):
266
267
    """creates a table for ions"""
    table = QtWidgets.QTableWidget(columnCount=len(labels))
268
    table.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
269
270
                        QtWidgets.QSizePolicy.Expanding)
    table.setHorizontalHeaderLabels(labels)
271
272
273
274
275
    table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)

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

278
    return table
279
280


Yan's avatar
Yan committed
281
282
283
284
285
286
287
288
289
290
291
292
293
294
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
295
296
        for i in range(1, len(rawdata)):
            rawline = rawdata[i].split(",")
Yan's avatar
Yan committed
297
298
299
300
301
302
303
304
            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
305
                                   states, corrected_to, corr_factors)):
Yan's avatar
Yan committed
306
                k.append(rawline[j])
Yan's avatar
Yan committed
307
308
309
        for row in reversed(range(ptable.rowCount())):
            dtable.removeRow(row)
            ptable.removeRow(row)
Yan's avatar
Yan committed
310
        # first populate only parent table
Yan's avatar
Yan committed
311
        for i in range(len(names)):
Yan's avatar
Yan committed
312
            add_line(dataset, ptable, dtable, drlspectrum)
313
314
315
            ptable.item(i, 0).setText(names[i])
            ptable.item(i, 1).setText(start_masses[i])
            ptable.item(i, 2).setText(end_masses[i])
Yan's avatar
Yan committed
316
        # and after that daughter table
Yan's avatar
Yan committed
317
        for i in range(len(names)):
Yan's avatar
Yan committed
318
            dtable.cellWidget(i, 1).setCurrentIndex(
Yan's avatar
Yan committed
319
                int(corrected_to[i]))
320
            dtable.item(i, 2).setText(corr_factors[i])
Yan's avatar
Yan committed
321
            dtable.cellWidget(i, 0).setCheckState(int(states[i]))
Yan's avatar
Yan committed
322
323


Yan's avatar
Yan committed
324
325
326
327
328
329
330
331
332
333
334
335
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):
336
                vals.append(ptable.item(row, i).text())
Yan's avatar
Yan committed
337
338
            vals.append(dtable.cellWidget(row, 0).checkState())
            vals.append(dtable.cellWidget(row, 1).currentIndex())
339
            vals.append(dtable.item(row, 2).text())
Yan's avatar
Yan committed
340
341
342
            expf.write("{}\n".format((",".join(map(str, vals)))))
        expf.close()

Yan's avatar
Yan committed
343

Yan's avatar
Yan committed
344
345
346
347
348
349
350
351
352
353
354
355
356
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
357
            dataset = list()
Yan's avatar
Yan committed
358
359
360
361
362
363
            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
364

Yan's avatar
Yan committed
365
def print_graph(labels, ptable, dtable, ds):
Yan's avatar
Yan committed
366
    printfig = Figure(figsize=(5, 2), dpi=100)
Yan's avatar
Yan committed
367
368
369
370
    printplot = printfig.add_subplot(111)
    printcanvas = FigureCanvas(printfig)
    gt.pop_plot(printplot, labels)
    update_drlspectrum(ptable, dtable, ds, printplot)
Yan's avatar
Yan committed
371
    widget = QtWidgets.QDialog(None, windowTitle='Print preview')
Yan's avatar
Yan committed
372
373
    layout = QtWidgets.QVBoxLayout(widget)
    layout.addWidget(printcanvas)
Yan's avatar
Yan committed
374
    widget.resize(600, 400)
Yan's avatar
Yan committed
375
376
377
378
379
380
381
    widget.show()
    dialog = QtPrintSupport.QPrintDialog()
    if dialog.exec_() == QtWidgets.QDialog.Accepted:
        printcanvas.render(dialog.printer())
    widget.close()


382
383
384
385
386
def key_pressed(event, ptable, dtable, ds, drlspectrum):
    if event.key() == QtCore.Qt.Key_Delete:
        for row in map(lambda x: x.row(),
                       ptable.selectionModel().selectedRows()):
            delete_row(row, ptable, dtable, ds, drlspectrum)
Yan's avatar
Yan committed
387
388
389
390
    if event.key() == QtCore.Qt.Key_F5:
        update_drlspectrum(ptable, dtable, ds, drlspectrum)
        for row in range(ptable.rowCount()):
            update_profile(ptable, row, ds)
391
392


Yan's avatar
Yan committed
393
def main_window(parent, ds, filename, cache):
394
    """constructs a dialog window"""
Yan's avatar
Yan committed
395
396
    def saveonclose(widget, event, buffer, ptable, dautable, canvas):
        buffer[0], buffer[1], buffer[2] = ptable, dautable, canvas
Yan's avatar
Yan committed
397
        QtWidgets.QMainWindow.closeEvent(widget, event)
Yan's avatar
Yan committed
398

Yan's avatar
Yan committed
399
    window = QtWidgets.QMainWindow(
Yan's avatar
Yan committed
400
        parent, windowTitle='Delayed reactant labelling')
Yan's avatar
Yan committed
401
402
    main_widget = QtWidgets.QWidget(window)
    window.setCentralWidget(main_widget)
Yan's avatar
Yan committed
403

Yan's avatar
Yan committed
404
    window.closeEvent = lambda event: saveonclose(
Yan's avatar
Yan committed
405
        window, event, cache, pt, dtable, graph_canvas)
Yan's avatar
Yan committed
406

Yan's avatar
Yan committed
407
408
    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
409
410
411
    graph_canvas = FigureCanvas(dial_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
Yan's avatar
Yan committed
412
    graphlabels = dict(x=[0], y=[0], line=None, name="",
Yan's avatar
Yan committed
413
414
                       xlabel="time(min)",
                       ylabel="relative intensity")
Yan's avatar
Yan committed
415
416
417
418
    gt.pan_factory(chromplot)
    gt.zoom_factory(chromplot, 1.15)
    gt.pop_plot(chromplot, graphlabels)

419
420
421
    drl_load = QtWidgets.QPushButton("&Load")
    drl_save = QtWidgets.QPushButton("&Save")
    drl_export = QtWidgets.QPushButton("&Export")
Yan's avatar
Yan committed
422
    drl_print = QtWidgets.QPushButton("&Print")
423
    close = QtWidgets.QPushButton("&Close")
Yan's avatar
Yan committed
424
    close.clicked.connect(window.close)
425

Yan's avatar
Yan committed
426
427
428
    btn_add = QtWidgets.QPushButton("&Add")
    btn_rem = QtWidgets.QPushButton("Remove")

429
430
    # pt = parenttable
    # dt = daughtertable
Yan's avatar
Yan committed
431
    if cache == [None, None, None]:
Yan's avatar
Yan committed
432
        dtable = iontable(["Name", "corrected for", "factor"])
433

Yan's avatar
Yan committed
434
        pt = iontable(["Name", "start (m/z)", "end (m/z)", "profile"])
Yan's avatar
Yan committed
435
        add_line(ds, pt, dtable, chromplot)
Yan's avatar
Yan committed
436
437
    else:
        pt = cache[0]
Yan's avatar
Yan committed
438
        dtable = cache[1]
Yan's avatar
Yan committed
439
        graph_canvas = cache[2]
440

441
442
443
    window.keyPressEvent = lambda event: key_pressed(
        event, pt, dtable, ds, chromplot)

444
    btn_add.clicked.connect(lambda: add_line(
Yan's avatar
Yan committed
445
        ds, pt, dtable, chromplot))
446
447
    btn_rem.clicked.connect(lambda: remove_rows(
        pt, dtable, ds, chromplot))
Yan's avatar
Yan committed
448
    drl_load.clicked.connect(lambda: load_drltables(
Yan's avatar
Yan committed
449
        main_widget, pt, dtable, ds, chromplot))
Yan's avatar
Yan committed
450
    drl_save.clicked.connect(lambda: save_drlconfig(
Yan's avatar
Yan committed
451
        pt, dtable, main_widget))
Yan's avatar
Yan committed
452
    drl_print.clicked.connect(lambda: print_graph(
Yan's avatar
Yan committed
453
        graphlabels, pt, dtable, ds))
Yan's avatar
Yan committed
454
    drl_export.clicked.connect(lambda: export_drlspectrum(
Yan's avatar
Yan committed
455
        main_widget, filename, pt, dtable, ds))
456

457
    pt.itemChanged.connect(lambda item: ptable_changed(
Yan's avatar
Yan committed
458
        item.row(), item.column(), pt, dtable, ds, chromplot))
459
460
461
462

    dtable.itemChanged.connect(lambda item: dtable_changed(
        item.row(), item.column(), pt, dtable, ds, chromplot))

Yan's avatar
Yan committed
463
    main_layout = QtWidgets.QVBoxLayout(main_widget)
Yan's avatar
Yan committed
464
465
    sub_layout = QtWidgets.QHBoxLayout()
    tablelayout = QtWidgets.QVBoxLayout()
Yan's avatar
Yan committed
466
    pt_butlayout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
467
    main_butlayout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
468

Yan's avatar
Yan committed
469
470
471
472
    pt_butlayout.addWidget(btn_add)
    pt_butlayout.addWidget(btn_rem)
    pt_butlayout.addStretch(0)

473
474
    main_layout.addLayout(sub_layout)
    main_layout.addWidget(HBar())
Yan's avatar
Yan committed
475
    main_layout.addLayout(main_butlayout)
476

Yan's avatar
Yan committed
477
478
    main_butlayout.addWidget(drl_load)
    main_butlayout.addWidget(drl_save)
Yan's avatar
Yan committed
479
    main_butlayout.addWidget(drl_print)
Yan's avatar
Yan committed
480
481
    main_butlayout.addStretch(1)
    main_butlayout.addWidget(drl_export)
482
    main_butlayout.addWidget(close)
Yan's avatar
Yan committed
483

484
    sub_layout.addWidget(graph_canvas, stretch=1)
Yan's avatar
Yan committed
485
    sub_layout.addLayout(tablelayout)
486

Yan's avatar
Yan committed
487
488
489
490
    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
491
    tablelayout.addWidget(dtable)
492

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