drltools.py 23 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
import os.path
Yan's avatar
Yan committed
14
15
matplotlib.use("Qt5Agg")

Yan's avatar
Yan committed
16

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


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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):
40
    """spectrum updating procedure"""
Yan's avatar
Yan committed
41
42
    # Dont do anything to graph when the spectrum is not populated
    if isinstance(dataset['masses'], type(None)):
43
44
        return

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

Yan's avatar
Yan committed
60

3Yan's avatar
3Yan committed
61
62
63
def get_intensity(row, ds, drls):
    startm = floatize(drls['pt'], row, 1)
    endm = floatize(drls['pt'], row, 2)
Yan's avatar
Yan committed
64
    massargs = dt.argsubselect(ds['masses'], startm, endm)
65
    nonzero_tic = list(map(lambda x: max(x, 1), ds['chrom_dat'][1]))
Yan's avatar
Yan committed
66
    intensity = (np.sum(
67
        ds['matrix'].T[massargs].T, axis=1)) / nonzero_tic
Yan's avatar
Yan committed
68
69
70
    return intensity


3Yan's avatar
3Yan committed
71
def get_daughterset(ds, drls):
Yan's avatar
Yan committed
72
    # TODO: write a less resources demanding function - probably "per-line"
Yan's avatar
Yan committed
73
    names = []
3Yan's avatar
3Yan committed
74
    times = ds['chrom_dat'][0, :] - drls['tshift'].value()
Yan's avatar
Yan committed
75
    intensities = []
Yan's avatar
Yan committed
76
    # TODO: resolve intensities trouble
3Yan's avatar
3Yan committed
77
78
79
80
    for row in range(drls['dt'].rowCount()):
        if drls['dt'].cellWidget(row, 0).checkState() == 2:
            intensity = get_intensity(row, ds, drls)
            cor = drls['dt'].cellWidget(row, 1).currentIndex() - 1
81
            if cor not in (-2, -1):
3Yan's avatar
3Yan committed
82
83
                factor = floatize(drls['dt'], row, 2)
                correction = get_intensity(cor, ds, drls) * factor
Yan's avatar
Yan committed
84
                intensity = intensity - correction
Yan's avatar
Yan committed
85
            intensities.append(intensity)
Yan's avatar
Yan committed
86
            names.append("{} - {} * {}".format(
3Yan's avatar
3Yan committed
87
88
89
                drls['dt'].item(row, 0).text(),
                drls['dt'].item(row,2).text(),
                drls['dt'].cellWidget(row,1).currentText()))
Yan's avatar
Yan committed
90
91
92
    return names, times, intensities


3Yan's avatar
3Yan committed
93
def get_parentset(ds, drls):
94
95
96
97
98
    names = []
    times = ds['chrom_dat'][0, :]
    intensities = []
    # TODO: resolve intensities trouble
    rowlist = []
3Yan's avatar
3Yan committed
99
100
    for row in range(drls['dt'].rowCount()):
        if drls['dt'].cellWidget(row, 0).checkState() == 2:
101
            rowlist.append(row)
3Yan's avatar
3Yan committed
102
103
            if drls['dt'].cellWidget(row, 1).currentIndex() > 0\
                    and floatize(drls['dt'], row, 2) != 0:
104
                rowlist.append(
3Yan's avatar
3Yan committed
105
                    drls['dt'].cellWidget(row, 1).currentIndex()-1)
106
    for row in set(rowlist):
3Yan's avatar
3Yan committed
107
            intensity = get_intensity(row, ds, drls)
108
            intensities.append(intensity)
3Yan's avatar
3Yan committed
109
            names.append(drls['dt'].item(row, 0).text())
110
111
112
    return names, times, intensities


3Yan's avatar
3Yan committed
113
def update_drlspectrum(ds, drls, drlspectrum):
114
    # Dont do anything when the dataset is not populated
Yan's avatar
Yan committed
115
    if isinstance(ds['masses'], type(None)):
Yan's avatar
Yan committed
116
        return
117
    colors = np.array([[0, 0, 0], [255, 0, 0], [0, 255, 0], [0, 0, 255],
118
119
120
                       [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
121

122
    # TODO: write a less resources demanding function
3Yan's avatar
3Yan committed
123
    names, times, intensities = get_daughterset(ds, drls)
Yan's avatar
Yan committed
124
125
    for i in range(len(drlspectrum.lines)):
        drlspectrum.lines[0].remove()
126

3Yan's avatar
3Yan committed
127
128
129
    drlspectrum.axvline(
        drls['tshift'].value(), color="#FF000088", linestyle=":")

130
    i = 0
3Yan's avatar
3Yan committed
131
132
133
134
    for row in range(drls['dt'].rowCount()):
        if drls['dt'].cellWidget(row, 0).checkState() == 2:
            drls['dt'].blockSignals(True)
            drls['dt'].item(row, 0).setBackground(QtGui.QBrush(
135
                QtGui.QColor(*colors[row % len(colors)], alpha=50)))
3Yan's avatar
3Yan committed
136
137
            drls['dt'].blockSignals(False)
            label = " {}".format(drls['pt'].item(row, 0).text())
138
139
140
            drlspectrum.plot(times, intensities[i], label=label,
                             color=(colors[row % len(colors)] / 255))
            i += 1
141
        else:
3Yan's avatar
3Yan committed
142
            drls['dt'].item(row, 0).setBackground(QtGui.QBrush())
143

144
145
146
147
    if len(names) != 0:
        drlspectrum.set_ylim(top=np.amax(intensities)*1.1,
                             bottom=np.amax(intensities)*-0.01)
        drlspectrum.legend(loc=2)
148
149
    drlspectrum.figure.canvas.draw()

Yan's avatar
Yan committed
150

Yan's avatar
Yan committed
151
def gettableitemlist(ptable):
152
    ion_list = []
Yan's avatar
Yan committed
153
154
155
    for row in range(ptable.rowCount()):
        text = []
        for i in range(3):
156
157
            if not isinstance(ptable.item(row, i), type(None)):
                frg = ptable.item(row, i).text()
Yan's avatar
Yan committed
158
159
160
161
162
            else:
                frg = ""
            text.append(frg)
        line = "{} ({}-{})".format(*text)
        ion_list.append(line)
163
164
165
    return ion_list


3Yan's avatar
3Yan committed
166
def update_corrfors(drls):
167
    """update corrections selection layout of the daughter table"""
3Yan's avatar
3Yan committed
168
169
170
    ionlist = gettableitemlist(drls['pt'])
    for row in range(drls['dt'].rowCount()):
        corfor = drls['dt'].cellWidget(row, 1)
171
172
173
174
175
176
177
        index = corfor.currentIndex()
        corfor.blockSignals(True)
        corfor.clear()
        corfor.addItem("")
        corfor.addItems(ionlist)
        corfor.setCurrentIndex(index)
        corfor.blockSignals(False)
Yan's avatar
Yan committed
178

179

3Yan's avatar
3Yan committed
180
def ptable_changed(row, column, ds, drls, drlspectrum):
181
    """routine called by change of the ptable spectra"""
3Yan's avatar
3Yan committed
182
183
    update_corrfors(drls)
    drls['dt'].item(row, 0).setText(gettableitemlist(drls['pt'])[row])
184
    if column in (1, 2):
3Yan's avatar
3Yan committed
185
        update_profile(drls['pt'], row, ds)
186

187

3Yan's avatar
3Yan committed
188
def dtable_changed(row, column, ds, drls, drlspectrum):
189
    """routine called by change of the dtable spectra"""
3Yan's avatar
3Yan committed
190
    if drls['dt'].cellWidget(row, 0).checkState() == 2:
191
192
        if (column == 0)\
           or (column == 2
3Yan's avatar
3Yan committed
193
194
               and drls['dt'].cellWidget(row, 1).currentIndex() != 0):
                update_drlspectrum(ds, drls, drlspectrum)
195

Yan's avatar
Yan committed
196

3Yan's avatar
3Yan committed
197
def corr_changed(row, ds, drls, drlspectrum):
198
    """routine called by change of correction for ion"""
3Yan's avatar
3Yan committed
199
200
201
    if (drls['dt'].cellWidget(row, 0).checkState() == 2
       and floatize(drls['dt'], row, 2) != 0):
        update_drlspectrum(ds, drls, drlspectrum)
202
203


3Yan's avatar
3Yan committed
204
def remove_rows(ds, drls, drlspectrum, rows=None):
Yan's avatar
Yan committed
205
    # TODO: maybe nicer selection in future, but this works for now
206
207
    if rows == None:
        rows = reversed(list(set(
3Yan's avatar
3Yan committed
208
            map(lambda x: x.row(), drls['pt'].selectedIndexes()))))
209
    for row in rows:
3Yan's avatar
3Yan committed
210
211
212
213
214
        drls['dt'].cellWidget(row,0).setCheckState(0)
        drls['dt'].removeRow(row)
        drls['pt'].removeRow(row)
        for i in range(drls['dt'].rowCount()):
            corfor = drls['dt'].cellWidget(i, 1)
215
216
217
218
            corfor.disconnect()
            index = corfor.currentIndex()
            corfor.clear()
            corfor.addItem("")
3Yan's avatar
3Yan committed
219
            corfor.addItems(gettableitemlist(drls['pt']))
220
221
            if index == row+1:
                corfor.setCurrentIndex(0)
3Yan's avatar
3Yan committed
222
                corr_changed(i, ds, drls, drlspectrum)
223
224
225
226
227
            elif index > row+1:
                corfor.setCurrentIndex(index-1)
            else:
                corfor.setCurrentIndex(index)
                corfor.currentIndexChanged.connect(lambda:
3Yan's avatar
3Yan committed
228
                    corr_changed(i, ds, drls, drlspectrum))
229
230


3Yan's avatar
3Yan committed
231
def add_line(ds, drls, drlspectrum):
232
    """add parent ion to the table"""
3Yan's avatar
3Yan committed
233
    newrow = drls['pt'].rowCount()
234

3Yan's avatar
3Yan committed
235
236
    drls['pt'].blockSignals(True)
    drls['dt'].blockSignals(True)
237

3Yan's avatar
3Yan committed
238
    drls['pt'].setRowCount(newrow + 1)
239
    for i in range(3):
3Yan's avatar
3Yan committed
240
        drls['pt'].setItem(newrow, i, QtWidgets.QTableWidgetItem())
241
        if newrow is not 0:
3Yan's avatar
3Yan committed
242
243
            drls['pt'].item(newrow, i).setText(str(floatize(
                    drls['pt'], newrow-1, i)+1))
244

245
    ion_graph = Figure(figsize=(3, 1.5), dpi=100, facecolor="None")
246
247
    ion_graph.add_subplot(111, facecolor=(1, 1, 1, 0.8),
                          position=(-0.01, -0.01, 1.02, 1.02))
248
249
250
    graph_canvas = FigureCanvas(ion_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
3Yan's avatar
3Yan committed
251
    drls['pt'].setCellWidget(newrow, 3, graph_canvas)
252

3Yan's avatar
3Yan committed
253
    drls['dt'].setRowCount(newrow + 1)
Yan's avatar
Yan committed
254
    checkbox = QtWidgets.QCheckBox()
3Yan's avatar
3Yan committed
255
    checkbox.setFocusProxy(drls['dt'])
256
257
    dname = QtWidgets.QTableWidgetItem()
    dname.setFlags(dname.flags() & ~QtCore.Qt.ItemIsEditable)
Yan's avatar
Yan committed
258
    dname.setTextAlignment(QtCore.Qt.AlignRight)
3Yan's avatar
3Yan committed
259
260
    drls['dt'].setItem(newrow, 0, dname)
    drls['dt'].setCellWidget(newrow, 0, checkbox)
261
    corfor = QtWidgets.QComboBox()
3Yan's avatar
3Yan committed
262
    corfor.setFocusProxy(drls['dt'])
263
    corfor.setFrame(False)
3Yan's avatar
3Yan committed
264
265
    drls['dt'].setCellWidget(newrow, 1, corfor)
    drls['dt'].setItem(newrow, 2, QtWidgets.QTableWidgetItem())
266

3Yan's avatar
3Yan committed
267
268
    drls['pt'].blockSignals(False)
    drls['dt'].blockSignals(False)
269

3Yan's avatar
3Yan committed
270
    ptable_changed(newrow, 1, ds, drls, drlspectrum)
271

Yan's avatar
Yan committed
272
    checkbox.stateChanged.connect(lambda: update_drlspectrum(
3Yan's avatar
3Yan committed
273
        ds, drls, drlspectrum))
274
    corfor.currentIndexChanged.connect(lambda: corr_changed(
3Yan's avatar
3Yan committed
275
        newrow, ds, drls, drlspectrum))
276
277


Yan's avatar
Yan committed
278
def iontable(labels):
279
280
    """creates a table for ions"""
    table = QtWidgets.QTableWidget(columnCount=len(labels))
281
    table.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
282
283
                        QtWidgets.QSizePolicy.Expanding)
    table.setHorizontalHeaderLabels(labels)
284
285
286
287
288
    table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)

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

291
    return table
292
293


3Yan's avatar
3Yan committed
294
def load_drltables(parent, dataset, drls, drlspectrum):
Yan's avatar
Yan committed
295
296
297
298
299
300
301
302
303
304
305
306
307
    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
308
309
        for i in range(1, len(rawdata)):
            rawline = rawdata[i].split(",")
310
            # TODO: rawline[4] can be -1 - decide if accept this behaviour
Yan's avatar
Yan committed
311
            if len(rawline) != 6 or int(rawline[3]) not in range(3) \
312
                    or int(rawline[4]) not in range(-1,len(rawdata)):
Yan's avatar
Yan committed
313
314
315
316
317
318
                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
319
                                   states, corrected_to, corr_factors)):
Yan's avatar
Yan committed
320
                k.append(rawline[j])
3Yan's avatar
3Yan committed
321
322
323
        for row in reversed(range(drls['pt'].rowCount())):
            drls['dt'].removeRow(row)
            drls['pt'].removeRow(row)
324
        # first populate only the parent table
Yan's avatar
Yan committed
325
        for i in range(len(names)):
3Yan's avatar
3Yan committed
326
327
328
329
            add_line(dataset, drls, drlspectrum)
            drls['pt'].item(i, 0).setText(names[i])
            drls['pt'].item(i, 1).setText(start_masses[i])
            drls['pt'].item(i, 2).setText(end_masses[i])
330
        # and after that the daughter table
Yan's avatar
Yan committed
331
        for i in range(len(names)):
3Yan's avatar
3Yan committed
332
            drls['dt'].cellWidget(i, 1).setCurrentIndex(
Yan's avatar
Yan committed
333
                int(corrected_to[i]))
3Yan's avatar
3Yan committed
334
335
            drls['dt'].item(i, 2).setText(corr_factors[i])
            drls['dt'].cellWidget(i, 0).setCheckState(int(states[i]))
Yan's avatar
Yan committed
336
337


3Yan's avatar
3Yan committed
338
def save_drlconfig(drls, parent, exp_f_name=None):
Yan's avatar
Yan committed
339
    """safe DRL table layout so it can be summoned when needed"""
340
341
342
343
    if exp_f_name == None:
        exp_f_name = ft.get_save_filename(
            "Save DRL table layout", "comma-separated values (*.csv)",
            "csv", parent)
Yan's avatar
Yan committed
344
345
346
347
    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")
3Yan's avatar
3Yan committed
348
        for row in range(drls['pt'].rowCount()):
Yan's avatar
Yan committed
349
350
            vals = []
            for i in range(3):
3Yan's avatar
3Yan committed
351
352
353
354
                vals.append(drls['pt'].item(row, i).text())
            vals.append(drls['dt'].cellWidget(row, 0).checkState())
            vals.append(drls['dt'].cellWidget(row, 1).currentIndex())
            vals.append(drls['dt'].item(row, 2).text())
Yan's avatar
Yan committed
355
356
357
            expf.write("{}\n".format((",".join(map(str, vals)))))
        expf.close()

Yan's avatar
Yan committed
358

3Yan's avatar
3Yan committed
359
def export_drlspectrum(parent, fn, ds, drls):
Yan's avatar
Yan committed
360
361
    if fn[0] is None:
        QtWidgets.QMessageBox.warning(
362
            None, "Export DRL dataset",
Yan's avatar
Yan committed
363
364
            "Nothing to export, cancelling request")
        return
3Yan's avatar
3Yan committed
365
366
367
368
369
370
    names, times, intensities = get_daughterset(ds, drls)
    subset = np.where(times > 0)[0]
    times = times[subset]
    intensities = intensities[subset]

    pnames, ptimes, pintensities = get_parentset(ds, drls)
371
372
373
374
375
376
377
378
379
380
381
382
383
384
    if names == []:
        QtWidgets.QMessageBox.warning(
            None, "Export DRL dataset",
            "Nothing to export, cancelling request")
        return
    fname = QtWidgets.QFileDialog.getSaveFileName(
            None,"Export DRL data",
        options=(QtWidgets.QFileDialog.DontConfirmOverwrite |
        QtWidgets.QFileDialog.HideNameFilterDetails))[0]
    if fname is '':
        return
    exp_f_name = list(map(lambda x: "{}/{}-{}.csv".format(
        fname, os.path.basename(fname), x),
        ["raw", "corrected", "input"]))
Yan's avatar
Yan committed
385
386
387
388
389
390
391
392
393
394
    for name in exp_f_name:
        if os.path.isfile(name):
            quest = QtWidgets.QMessageBox.warning(
                parent, "Export DRL data",
                "File {} already exists in the filesystem.\n"
                "Do you want to overwrite it?"
                .format(os.path.basename(name)),
                QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
            if quest == QtWidgets.QMessageBox.No:
                return
395
396
397
398
399
400
401
    if not os.path.exists(fname):
        os.makedirs(fname)
    for i, table in enumerate([[pnames, pintensities],
                               [names, intensities]]):
        expf = open(exp_f_name[i], 'w')
        expf.write("times, {}\n".format((",".join(table[0]))))
        for j in range(len(times)):
Yan's avatar
Yan committed
402
            dataset = list()
403
404
405
            dataset.append(times[j])
            for intensity in table[1]:
                dataset.append(intensity[j])
Yan's avatar
Yan committed
406
407
            expf.write("{}\n".format((",".join(map(str, dataset)))))
        expf.close()
3Yan's avatar
3Yan committed
408
    save_drlconfig(drls, parent, exp_f_name[2])
Yan's avatar
Yan committed
409

Yan's avatar
Yan committed
410

3Yan's avatar
3Yan committed
411
def print_graph(labels, ds, drls):
Yan's avatar
Yan committed
412
    printfig = Figure(figsize=(5, 2), dpi=100)
Yan's avatar
Yan committed
413
414
415
    printplot = printfig.add_subplot(111)
    printcanvas = FigureCanvas(printfig)
    gt.pop_plot(printplot, labels)
3Yan's avatar
3Yan committed
416
    update_drlspectrum(ds, drls, printplot)
Yan's avatar
Yan committed
417
    widget = QtWidgets.QDialog(None, windowTitle='Print preview')
Yan's avatar
Yan committed
418
419
    layout = QtWidgets.QVBoxLayout(widget)
    layout.addWidget(printcanvas)
Yan's avatar
Yan committed
420
    widget.resize(600, 400)
Yan's avatar
Yan committed
421
422
423
424
425
426
427
    widget.show()
    dialog = QtPrintSupport.QPrintDialog()
    if dialog.exec_() == QtWidgets.QDialog.Accepted:
        printcanvas.render(dialog.printer())
    widget.close()


3Yan's avatar
3Yan committed
428
def clip_range(drls):
429
    activeObject = QtWidgets.QApplication.focusWidget()
3Yan's avatar
3Yan committed
430
    if activeObject in (drls['pt'], drls['dt']):
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
        table = activeObject
        if len(table.selectedRanges()) == 0:
            return
        if len(table.selectedRanges()) > 1:
            QtWidgets.QMessageBox.warning(
                None, "Operation not supported",
                "Operation not supported for multiple ranges,\n"
                "cancelling request")
            return
        sr = table.selectedRanges()[0]
        rows = []
        for row in range(sr.topRow(), sr.bottomRow() + 1):
            line = []
            for col in range(sr.leftColumn(), sr.rightColumn() + 1):
                if isinstance(table.cellWidget(row, col),
                            QtWidgets.QComboBox):
                    line.append(
                        table.cellWidget(row, col).currentText())
                elif isinstance(table.item(row, col),
                              QtWidgets.QTableWidgetItem):
                    line.append(table.item(row, col).text())
            rows.append(("\t").join(line))
        QtWidgets.QApplication.clipboard().setText(("\n").join(rows))


3Yan's avatar
3Yan committed
456
def paste_clip(drls, ds, drlspectrum):
457
    activeObject = QtWidgets.QApplication.focusWidget()
3Yan's avatar
3Yan committed
458
    if activeObject in (drls['pt'], drls['dt'])\
459
460
461
462
463
464
465
466
467
468
469
470
471
472
        and activeObject.selectedRanges() != []:
        table = activeObject
        if len(table.selectedRanges()) > 1:
            QtWidgets.QMessageBox.warning(
                None, "Operation not supported",
                "Operation not supported for multiple ranges,\n"
                "cancelling request")
        cliptext = QtWidgets.QApplication.clipboard().text()
        rows = cliptext.split("\n")
        startrow = table.selectedRanges()[0].topRow()
        startcol = table.selectedRanges()[0].leftColumn()
        for i, row in enumerate(rows, start=startrow):
            cols = row.split("\t")
            for j, col in enumerate(cols, start=startcol):
3Yan's avatar
3Yan committed
473
                if table == drls['pt'] and j < 3:
474
                    if i >= (table.rowCount()):
3Yan's avatar
3Yan committed
475
                        add_line(ds, drls, drlspectrum)
476
                    table.item(i, j).setText(col)
3Yan's avatar
3Yan committed
477
                if table == drls['dt'] and j == 2\
478
479
480
481
                     and i < table.rowCount():
                     table.item(i,j).setText(col)


3Yan's avatar
3Yan committed
482
def key_pressed(event, ds, drls, drlspectrum):
483
    if event.key() == QtCore.Qt.Key_Delete:
484
        rows = reversed(list(map(lambda x: x.row(),
3Yan's avatar
3Yan committed
485
486
            drls['pt'].selectionModel().selectedRows())))
        remove_rows(ds, drls, drlspectrum, rows)
Yan's avatar
Yan committed
487
    if event.key() == QtCore.Qt.Key_F5:
3Yan's avatar
3Yan committed
488
489
490
        update_drlspectrum(ds, drls, drlspectrum)
        for row in range(drls['pt'].rowCount()):
            update_profile(drls['pt'], row, ds)
491
492
    if event.key() == QtCore.Qt.Key_C\
        and event.modifiers().__int__() == QtCore.Qt.ControlModifier:
3Yan's avatar
3Yan committed
493
        clip_range(drls)
494
495
    if event.key() == QtCore.Qt.Key_V\
        and event.modifiers().__int__() == QtCore.Qt.ControlModifier:
3Yan's avatar
3Yan committed
496
        paste_clip(ds, drls, drlspectrum)
497
498


Yan's avatar
Yan committed
499
def main_window(parent, ds, filename, cache):
500
    """constructs a dialog window"""
3Yan's avatar
3Yan committed
501
502
    def saveonclose(widget, event, buffer, drls, canvas):
        buffer[0], buffer[1] = drls, canvas
Yan's avatar
Yan committed
503
        QtWidgets.QMainWindow.closeEvent(widget, event)
Yan's avatar
Yan committed
504

3Yan's avatar
3Yan committed
505
506
507
508
    # pt = parenttable
    # dt = daughtertable
    drls = dict(pt=None, dt=None, tshift=None)

Yan's avatar
Yan committed
509
    window = QtWidgets.QMainWindow(
Yan's avatar
Yan committed
510
        parent, windowTitle='Delayed reactant labelling')
Yan's avatar
Yan committed
511
512
    main_widget = QtWidgets.QWidget(window)
    window.setCentralWidget(main_widget)
Yan's avatar
Yan committed
513

Yan's avatar
Yan committed
514
    window.closeEvent = lambda event: saveonclose(
3Yan's avatar
3Yan committed
515
        window, event, cache, drls, graph_canvas)
Yan's avatar
Yan committed
516

Yan's avatar
Yan committed
517
518
    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
519
520
521
    graph_canvas = FigureCanvas(dial_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
Yan's avatar
Yan committed
522
    graphlabels = dict(x=[0], y=[0], line=None, name="",
Yan's avatar
Yan committed
523
524
                       xlabel="time(min)",
                       ylabel="relative intensity")
Yan's avatar
Yan committed
525
526
527
528
    gt.pan_factory(chromplot)
    gt.zoom_factory(chromplot, 1.15)
    gt.pop_plot(chromplot, graphlabels)

3Yan's avatar
3Yan committed
529
530
531
532
    time_title = QtWidgets.QLabel("Time shift (min):")
    drls['tshift'] = QtWidgets.QDoubleSpinBox(
            minimum=-100, maximum=1440, decimals=3)

533
534
535
    drl_load = QtWidgets.QPushButton("&Load")
    drl_save = QtWidgets.QPushButton("&Save")
    drl_export = QtWidgets.QPushButton("&Export")
Yan's avatar
Yan committed
536
    drl_print = QtWidgets.QPushButton("&Print")
537
    close = QtWidgets.QPushButton("&Close")
Yan's avatar
Yan committed
538
    close.clicked.connect(window.close)
539

Yan's avatar
Yan committed
540
541
542
    btn_add = QtWidgets.QPushButton("&Add")
    btn_rem = QtWidgets.QPushButton("Remove")

3Yan's avatar
3Yan committed
543
544
    if cache == [None, None]:
        drls['dt'] = iontable(["Name", "corrected for", "factor"])
545

3Yan's avatar
3Yan committed
546
547
548
        drls['pt'] = iontable(["Name", "start (m/z)", "end (m/z)",
                               "profile"])
        add_line(ds, drls, chromplot)
Yan's avatar
Yan committed
549
    else:
3Yan's avatar
3Yan committed
550
551
        drls = cache[0]
        graph_canvas = cache[1]
552

553
    window.keyPressEvent = lambda event: key_pressed(
3Yan's avatar
3Yan committed
554
        event, ds, drls, chromplot)
555

556
    btn_add.clicked.connect(lambda: add_line(
3Yan's avatar
3Yan committed
557
        ds, drls, chromplot))
558
    btn_rem.clicked.connect(lambda: remove_rows(
3Yan's avatar
3Yan committed
559
        ds, drls, chromplot))
Yan's avatar
Yan committed
560
    drl_load.clicked.connect(lambda: load_drltables(
3Yan's avatar
3Yan committed
561
        main_widget, ds, drls, chromplot))
Yan's avatar
Yan committed
562
    drl_save.clicked.connect(lambda: save_drlconfig(
3Yan's avatar
3Yan committed
563
        drls, main_widget))
Yan's avatar
Yan committed
564
    drl_print.clicked.connect(lambda: print_graph(
3Yan's avatar
3Yan committed
565
        graphlabels, ds, drls))
Yan's avatar
Yan committed
566
    drl_export.clicked.connect(lambda: export_drlspectrum(
3Yan's avatar
3Yan committed
567
568
569
570
        main_widget, filename, ds, drls))

    drls['pt'].itemChanged.connect(lambda item: ptable_changed(
        item.row(), item.column(), ds, drls, chromplot))
571

3Yan's avatar
3Yan committed
572
573
    drls['dt'].itemChanged.connect(lambda item: dtable_changed(
        item.row(), item.column(), ds, drls, chromplot))
574

3Yan's avatar
3Yan committed
575
576
    drls['tshift'].valueChanged.connect(lambda: update_drlspectrum(
        ds, drls, chromplot))
577

Yan's avatar
Yan committed
578
    main_layout = QtWidgets.QVBoxLayout(main_widget)
Yan's avatar
Yan committed
579
    sub_layout = QtWidgets.QHBoxLayout()
3Yan's avatar
3Yan committed
580
581
    graph_layout = QtWidgets.QVBoxLayout()
    graphparams_layout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
582
    tablelayout = QtWidgets.QVBoxLayout()
Yan's avatar
Yan committed
583
    pt_butlayout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
584
    main_butlayout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
585

Yan's avatar
Yan committed
586
587
588
589
    pt_butlayout.addWidget(btn_add)
    pt_butlayout.addWidget(btn_rem)
    pt_butlayout.addStretch(0)

590
591
    main_layout.addLayout(sub_layout)
    main_layout.addWidget(HBar())
Yan's avatar
Yan committed
592
    main_layout.addLayout(main_butlayout)
593

Yan's avatar
Yan committed
594
595
    main_butlayout.addWidget(drl_load)
    main_butlayout.addWidget(drl_save)
Yan's avatar
Yan committed
596
    main_butlayout.addWidget(drl_print)
Yan's avatar
Yan committed
597
598
    main_butlayout.addStretch(1)
    main_butlayout.addWidget(drl_export)
599
    main_butlayout.addWidget(close)
Yan's avatar
Yan committed
600

3Yan's avatar
3Yan committed
601
    sub_layout.addLayout(graph_layout, stretch=1)
Yan's avatar
Yan committed
602
    sub_layout.addLayout(tablelayout)
3Yan's avatar
3Yan committed
603
604
605
606
607
    graph_layout.addWidget(graph_canvas, stretch=1)
    graph_layout.addLayout(graphparams_layout)
    graphparams_layout.addWidget(time_title)
    graphparams_layout.addWidget(drls['tshift'])
    graphparams_layout.addStretch(1)
608

Yan's avatar
Yan committed
609
    tablelayout.addWidget(QtWidgets.QLabel("Raw ions table:"))
3Yan's avatar
3Yan committed
610
    tablelayout.addWidget(drls['pt'])
Yan's avatar
Yan committed
611
612
    tablelayout.addLayout(pt_butlayout)
    tablelayout.addWidget(QtWidgets.QLabel("Corrected ions table:"))
3Yan's avatar
3Yan committed
613
    tablelayout.addWidget(drls['dt'])
614

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