drltools.py 16.9 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]
Yan's avatar
Yan committed
60
            cor = dtable.cellWidget(row, 1).currentIndex()-1
Yan's avatar
Yan committed
61
            if cor != -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
Yan's avatar
Yan committed
79
80
    colors = np.array([[255, 0, 0], [0, 255, 0], [0, 0, 255],
                       [0, 200, 255], [255, 0, 255], [255, 200, 0]])
Yan's avatar
Yan committed
81
82
83
84

    names, times, intensities = get_daughterset(ptable, dtable, ds)
    for i in range(len(drlspectrum.lines)):
        drlspectrum.lines[0].remove()
Yan's avatar
Yan committed
85
    for i, j in enumerate(intensities):
86
        drlspectrum.plot(times, j, label=names[i],
Yan's avatar
Yan committed
87
                         color=(colors[i % len(colors)] / 255))
Yan's avatar
Yan committed
88
89
    if len(names) != 0:
        drlspectrum.set_ylim(top=np.amax(intensities)*1.1,
Yan's avatar
Yan committed
90
                             bottom=np.amax(intensities)*-0.01)
91
    drlspectrum.legend()
Yan's avatar
Yan committed
92
    drlspectrum.figure.canvas.draw()
93

94
95
    count = 0
    for row in range(dtable.rowCount()):
Yan's avatar
Yan committed
96
97
98
        if dtable.cellWidget(row, 0).checkState() == 2:
            dtable.item(row, 0).setBackground(QtGui.QBrush(
                QtGui.QColor(*colors[count % len(colors)], alpha=50)))
99
100
            count += 1
        else:
Yan's avatar
Yan committed
101
            dtable.item(row, 0).setBackground(QtGui.QBrush())
102

Yan's avatar
Yan committed
103

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


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

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

    if start > end:
        start, end = end, start
132
133
134

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

Yan's avatar
Yan committed
136
    ptnames = gettableitemlist(ptable)
Yan's avatar
Yan committed
137
    for row in range(dtable.rowCount()):
Yan's avatar
Yan committed
138
139
140
141
142
143
        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
144

Yan's avatar
Yan committed
145
146
    update_profile(start, end, spectrum, dataset)
    update_drlspectrum(ptable, dtable, dataset, drlspectrum)
147
148
149


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


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


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

    newrow = parenttable.rowCount()
190

191
192
193
194
    parenttable.setRowCount(newrow + 1)
    pname = QtWidgets.QLineEdit()
    pname.setFrame(False)
    parenttable.setCellWidget(newrow, 0, pname)
Yan's avatar
Yan committed
195
196
    start_mz = setdoublecell(parenttable, newrow, 1)
    end_mz = setdoublecell(parenttable, newrow, 2)
197
    parenttable.setCellWidget(newrow, 3, graph_canvas)
198
199
200
201
202
    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))
203

204
    daughtertable.setRowCount(newrow + 1)
Yan's avatar
Yan committed
205

Yan's avatar
Yan committed
206
    # TODO: decide which box will be used in the final version
Yan's avatar
Yan committed
207
    checkbox = QtWidgets.QCheckBox()
208
209
    dname = QtWidgets.QTableWidgetItem()
    dname.setFlags(dname.flags() & ~QtCore.Qt.ItemIsEditable)
Yan's avatar
Yan committed
210
    dname.setTextAlignment(QtCore.Qt.AlignRight)
Yan's avatar
Yan committed
211
212
    daughtertable.setItem(newrow, 0, dname)
    daughtertable.setCellWidget(newrow, 0, checkbox)
213

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

Yan's avatar
Yan committed
220
    factor = setdoublecell(daughtertable, newrow, 2)
221

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

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


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

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

255
    return table
256
257


Yan's avatar
Yan committed
258
259
260
261
262
263
264
265
266
267
268
269
270
271
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
272
273
        for i in range(1, len(rawdata)):
            rawline = rawdata[i].split(",")
Yan's avatar
Yan committed
274
275
276
277
278
279
280
281
            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
282
                                   states, corrected_to, corr_factors)):
Yan's avatar
Yan committed
283
                k.append(rawline[j])
Yan's avatar
Yan committed
284
285
286
        for row in reversed(range(ptable.rowCount())):
            dtable.removeRow(row)
            ptable.removeRow(row)
Yan's avatar
Yan committed
287
        # first populate only parent table
Yan's avatar
Yan committed
288
        for i in range(len(names)):
Yan's avatar
Yan committed
289
            add_line(dataset, ptable, dtable, drlspectrum)
Yan's avatar
Yan committed
290
291
292
            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
293
        # and after that daughter table
Yan's avatar
Yan committed
294
        for i in range(len(names)):
Yan's avatar
Yan committed
295
            dtable.cellWidget(i, 1).setCurrentIndex(
Yan's avatar
Yan committed
296
                int(corrected_to[i]))
Yan's avatar
Yan committed
297
298
            dtable.cellWidget(i, 2).setText(corr_factors[i])
            dtable.cellWidget(i, 0).setCheckState(int(states[i]))
Yan's avatar
Yan committed
299
300


Yan's avatar
Yan committed
301
302
303
304
305
306
307
308
309
310
311
312
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
313
314
315
316
                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
317
318
319
            expf.write("{}\n".format((",".join(map(str, vals)))))
        expf.close()

Yan's avatar
Yan committed
320

Yan's avatar
Yan committed
321
322
323
324
325
326
327
328
329
330
331
332
333
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
334
            dataset = list()
Yan's avatar
Yan committed
335
336
337
338
339
340
            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
341

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


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

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

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

Yan's avatar
Yan committed
373
374
    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
375
376
377
    graph_canvas = FigureCanvas(dial_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
Yan's avatar
Yan committed
378
    graphlabels = dict(x=[0], y=[0], line=None, name="",
Yan's avatar
Yan committed
379
380
                       xlabel="time(min)",
                       ylabel="relative intensity")
Yan's avatar
Yan committed
381
382
383
384
    gt.pan_factory(chromplot)
    gt.zoom_factory(chromplot, 1.15)
    gt.pop_plot(chromplot, graphlabels)

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

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

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

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

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

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

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

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

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

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

Yan's avatar
Yan committed
443
444
445
446
    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
447
    tablelayout.addWidget(dtable)
448

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