drltools.py 24.7 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 = []
3Yan's avatar
3Yan committed
76
77
78
    for row in range(drls['dt'].rowCount()):
        if drls['dt'].cellWidget(row, 0).checkState() == 2:
            intensity = get_intensity(row, ds, drls)
3Yan's avatar
3Yan committed
79
80
81
82
83
84
85
86
87
88
89
            corlist = []
            for i in range(drls['cors']):
                cor = drls['dt'].cellWidget(row, 1+i*2).currentIndex() - 1
                if cor not in (-2, -1):
                    factor = floatize(drls['dt'], row, 2+i*2)
                    correction = get_intensity(cor, ds, drls) * factor
                    intensity = intensity - correction
                    corlist.append("{} * {}".format(
                        drls['dt'].item(row,2+i*2).text(),
                        drls['dt'].cellWidget(row,1+i*2).currentText()))
            cortext = " + ".join(corlist)
Yan's avatar
Yan committed
90
            intensities.append(intensity)
3Yan's avatar
3Yan committed
91
            names.append("{} - ({})".format(
3Yan's avatar
3Yan committed
92
                drls['dt'].item(row, 0).text(),
3Yan's avatar
3Yan committed
93
                cortext))
Yan's avatar
Yan committed
94
95
96
    return names, times, intensities


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


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

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

3Yan's avatar
3Yan committed
131
    drlspectrum.axvline(0, color="#FF000088", linestyle=":")
3Yan's avatar
3Yan committed
132

133
    i = 0
3Yan's avatar
3Yan committed
134
135
136
137
    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(
138
                QtGui.QColor(*colors[row % len(colors)], alpha=50)))
3Yan's avatar
3Yan committed
139
140
            drls['dt'].blockSignals(False)
            label = " {}".format(drls['pt'].item(row, 0).text())
3Yan's avatar
3Yan committed
141
142
143
144
            intensity = intensities[i]
            if drls['rel'].checkState() == 2:
                intensity = intensity / np.sum(intensities, 0)
            drlspectrum.plot(times, intensity, label=label,
145
146
                             color=(colors[row % len(colors)] / 255))
            i += 1
147
        else:
3Yan's avatar
3Yan committed
148
            drls['dt'].item(row, 0).setBackground(QtGui.QBrush())
149

150
    if len(names) != 0:
3Yan's avatar
3Yan committed
151
152
153
154
        gmax = np.amax(intensities)
        if drls['rel'].checkState() == 2:
            gmax = 1
        drlspectrum.set_ylim(top=gmax*1.1, bottom=gmax*-0.01)
155
        drlspectrum.legend(loc=2)
156
157
    drlspectrum.figure.canvas.draw()

Yan's avatar
Yan committed
158

Yan's avatar
Yan committed
159
def gettableitemlist(ptable):
160
    ion_list = []
Yan's avatar
Yan committed
161
162
163
    for row in range(ptable.rowCount()):
        text = []
        for i in range(3):
164
165
            if not isinstance(ptable.item(row, i), type(None)):
                frg = ptable.item(row, i).text()
Yan's avatar
Yan committed
166
167
168
169
170
            else:
                frg = ""
            text.append(frg)
        line = "{} ({}-{})".format(*text)
        ion_list.append(line)
171
172
173
    return ion_list


3Yan's avatar
3Yan committed
174
def update_corrfors(drls):
175
    """update corrections selection layout of the daughter table"""
3Yan's avatar
3Yan committed
176
177
    ionlist = gettableitemlist(drls['pt'])
    for row in range(drls['dt'].rowCount()):
3Yan's avatar
3Yan committed
178
179
180
181
182
183
184
185
186
        for i in range(drls['cors']):
            corfor = drls['dt'].cellWidget(row, 1+i*2)
            index = corfor.currentIndex()
            corfor.blockSignals(True)
            corfor.clear()
            corfor.addItem("")
            corfor.addItems(ionlist)
            corfor.setCurrentIndex(index)
            corfor.blockSignals(False)
Yan's avatar
Yan committed
187

188

3Yan's avatar
3Yan committed
189
def ptable_changed(row, column, ds, drls, drlspectrum):
190
    """routine called by change of the ptable spectra"""
3Yan's avatar
3Yan committed
191
192
    update_corrfors(drls)
    drls['dt'].item(row, 0).setText(gettableitemlist(drls['pt'])[row])
193
    if column in (1, 2):
3Yan's avatar
3Yan committed
194
        update_profile(drls['pt'], row, ds)
195

196

3Yan's avatar
3Yan committed
197
def dtable_changed(row, column, ds, drls, drlspectrum):
198
    """routine called by change of the dtable spectra"""
3Yan's avatar
3Yan committed
199
    #TODO: multiple corrections not incorporated!!!
3Yan's avatar
3Yan committed
200
    if drls['dt'].cellWidget(row, 0).checkState() == 2:
201
202
        if (column == 0)\
           or (column == 2
3Yan's avatar
3Yan committed
203
204
               and drls['dt'].cellWidget(row, 1).currentIndex() != 0):
                update_drlspectrum(ds, drls, drlspectrum)
205

Yan's avatar
Yan committed
206

3Yan's avatar
3Yan committed
207
def corr_changed(row, ds, drls, drlspectrum):
208
    """routine called by change of correction for ion"""
3Yan's avatar
3Yan committed
209
    #TODO: multiple corrections not incorporated!!!
3Yan's avatar
3Yan committed
210
211
212
    if (drls['dt'].cellWidget(row, 0).checkState() == 2
       and floatize(drls['dt'], row, 2) != 0):
        update_drlspectrum(ds, drls, drlspectrum)
213
214


3Yan's avatar
3Yan committed
215
def remove_rows(ds, drls, drlspectrum, rows=None):
Yan's avatar
Yan committed
216
    # TODO: maybe nicer selection in future, but this works for now
217
218
    if rows == None:
        rows = reversed(list(set(
3Yan's avatar
3Yan committed
219
            map(lambda x: x.row(), drls['pt'].selectedIndexes()))))
220
    for row in rows:
3Yan's avatar
3Yan committed
221
222
223
224
        drls['dt'].cellWidget(row,0).setCheckState(0)
        drls['dt'].removeRow(row)
        drls['pt'].removeRow(row)
        for i in range(drls['dt'].rowCount()):
3Yan's avatar
3Yan committed
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
            for cornum in range(drls['cors']):
                corfor = drls['dt'].cellWidget(i, 1+cornum*2)
                corfor.disconnect()
                index = corfor.currentIndex()
                corfor.clear()
                corfor.addItem("")
                corfor.addItems(gettableitemlist(drls['pt']))
                if index == row+1:
                    corfor.setCurrentIndex(0)
                    corr_changed(i, ds, drls, drlspectrum)
                elif index > row+1:
                    corfor.setCurrentIndex(index-1)
                else:
                    corfor.setCurrentIndex(index)
                    corfor.currentIndexChanged.connect(lambda:
                        corr_changed(i, ds, drls, drlspectrum))
241
242


3Yan's avatar
3Yan committed
243
def add_line(ds, drls, drlspectrum):
244
    """add parent ion to the table"""
3Yan's avatar
3Yan committed
245
    newrow = drls['pt'].rowCount()
246

3Yan's avatar
3Yan committed
247
248
    drls['pt'].blockSignals(True)
    drls['dt'].blockSignals(True)
249

3Yan's avatar
3Yan committed
250
    drls['pt'].setRowCount(newrow + 1)
251
    for i in range(3):
3Yan's avatar
3Yan committed
252
        drls['pt'].setItem(newrow, i, QtWidgets.QTableWidgetItem())
253
        if newrow is not 0:
3Yan's avatar
3Yan committed
254
255
            drls['pt'].item(newrow, i).setText(str(floatize(
                    drls['pt'], newrow-1, i)+1))
256

257
    ion_graph = Figure(figsize=(3, 1.5), dpi=100, facecolor="None")
258
259
    ion_graph.add_subplot(111, facecolor=(1, 1, 1, 0.8),
                          position=(-0.01, -0.01, 1.02, 1.02))
260
261
262
    graph_canvas = FigureCanvas(ion_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
3Yan's avatar
3Yan committed
263
    drls['pt'].setCellWidget(newrow, 3, graph_canvas)
264

3Yan's avatar
3Yan committed
265
    drls['dt'].setRowCount(newrow + 1)
Yan's avatar
Yan committed
266
    checkbox = QtWidgets.QCheckBox()
3Yan's avatar
3Yan committed
267
    checkbox.setFocusProxy(drls['dt'])
268
269
    dname = QtWidgets.QTableWidgetItem()
    dname.setFlags(dname.flags() & ~QtCore.Qt.ItemIsEditable)
Yan's avatar
Yan committed
270
    dname.setTextAlignment(QtCore.Qt.AlignRight)
3Yan's avatar
3Yan committed
271
272
    drls['dt'].setItem(newrow, 0, dname)
    drls['dt'].setCellWidget(newrow, 0, checkbox)
3Yan's avatar
3Yan committed
273
274
275
276
277
278
279
280
281

    for i in range(drls['cors']):
        corfor = QtWidgets.QComboBox()
        corfor.setFocusProxy(drls['dt'])
        corfor.setFrame(False)
        drls['dt'].setCellWidget(newrow, 1+i*2, corfor)
        drls['dt'].setItem(newrow, 2+i*2, QtWidgets.QTableWidgetItem())
        corfor.currentIndexChanged.connect(lambda: corr_changed(
            newrow, ds, drls, drlspectrum))
282

3Yan's avatar
3Yan committed
283
284
    drls['pt'].blockSignals(False)
    drls['dt'].blockSignals(False)
285

3Yan's avatar
3Yan committed
286
    ptable_changed(newrow, 1, ds, drls, drlspectrum)
287

Yan's avatar
Yan committed
288
    checkbox.stateChanged.connect(lambda: update_drlspectrum(
3Yan's avatar
3Yan committed
289
        ds, drls, drlspectrum))
290
291


Yan's avatar
Yan committed
292
def iontable(labels):
293
294
    """creates a table for ions"""
    table = QtWidgets.QTableWidget(columnCount=len(labels))
295
    table.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
296
297
                        QtWidgets.QSizePolicy.Expanding)
    table.setHorizontalHeaderLabels(labels)
298
299
300
301
302
    table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)

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

305
    return table
306
307


3Yan's avatar
3Yan committed
308
def load_drltables(parent, dataset, drls, drlspectrum):
Yan's avatar
Yan committed
309
310
311
312
313
314
315
316
317
318
319
    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 = []

3Yan's avatar
3Yan committed
320

Yan's avatar
Yan committed
321
322
        with open(filename, 'r') as cfile:
            rawdata = cfile.read().splitlines()
Yan's avatar
Yan committed
323
324
        for i in range(1, len(rawdata)):
            rawline = rawdata[i].split(",")
325
            # TODO: rawline[4] can be -1 - decide if accept this behaviour
3Yan's avatar
3Yan committed
326
327
            # TODO: not checking if multiple corrections are sane
            if len(rawline) < 6 or int(rawline[3]) not in range(3) \
328
                    or int(rawline[4]) not in range(-1,len(rawdata)):
Yan's avatar
Yan committed
329
330
331
332
333
334
                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
335
                                   states, corrected_to, corr_factors)):
Yan's avatar
Yan committed
336
                k.append(rawline[j])
3Yan's avatar
3Yan committed
337
338
339
        for row in reversed(range(drls['pt'].rowCount())):
            drls['dt'].removeRow(row)
            drls['pt'].removeRow(row)
340
        # first populate only the parent table
Yan's avatar
Yan committed
341
        for i in range(len(names)):
3Yan's avatar
3Yan committed
342
343
344
345
            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])
346
        # and after that the daughter table
Yan's avatar
Yan committed
347
        for i in range(len(names)):
3Yan's avatar
3Yan committed
348
349
350
351
            for j in range((len(names)-1)/2):
                drls['dt'].cellWidget(i, 1+j*2).setCurrentIndex(
                    int(corrected_to[i]))
                drls['dt'].item(i, 2+j*2).setText(corr_factors[i])
3Yan's avatar
3Yan committed
352
            drls['dt'].cellWidget(i, 0).setCheckState(int(states[i]))
Yan's avatar
Yan committed
353
354


3Yan's avatar
3Yan committed
355
def save_drlconfig(drls, parent, exp_f_name=None):
Yan's avatar
Yan committed
356
    """safe DRL table layout so it can be summoned when needed"""
357
358
359
360
    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
361
    if exp_f_name is not '':
3Yan's avatar
3Yan committed
362
363
364
365
366
        corlist = []
        for i in range(drls['cors']):
            corlist.append("corrected_to_{}, factor_{} ".format(
                i+1, i+1))
        cortext = ", ".join(corlist)
Yan's avatar
Yan committed
367
368
        expf = open(exp_f_name, 'w')
        expf.write("#ion_name, start m/z, end m/z, visible,"
3Yan's avatar
3Yan committed
369
                   "{}\n".format(cortext))
3Yan's avatar
3Yan committed
370
        for row in range(drls['pt'].rowCount()):
Yan's avatar
Yan committed
371
372
            vals = []
            for i in range(3):
3Yan's avatar
3Yan committed
373
374
                vals.append(drls['pt'].item(row, i).text())
            vals.append(drls['dt'].cellWidget(row, 0).checkState())
3Yan's avatar
3Yan committed
375
376
377
            for i in range(drls['cors']):
                vals.append(drls['dt'].cellWidget(row, 1+i*2).currentIndex())
                vals.append(drls['dt'].item(row, 2+i*2).text())
Yan's avatar
Yan committed
378
379
380
            expf.write("{}\n".format((",".join(map(str, vals)))))
        expf.close()

Yan's avatar
Yan committed
381

3Yan's avatar
3Yan committed
382
def export_drlspectrum(parent, fn, ds, drls):
Yan's avatar
Yan committed
383
384
    if fn[0] is None:
        QtWidgets.QMessageBox.warning(
385
            None, "Export DRL dataset",
Yan's avatar
Yan committed
386
387
            "Nothing to export, cancelling request")
        return
3Yan's avatar
3Yan committed
388
389
390
391
392
393
    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)
394
395
396
397
398
399
400
401
402
403
404
405
406
407
    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
408
409
410
411
412
413
414
415
416
417
    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
418
419
420
421
422
423
424
    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
425
            dataset = list()
426
427
428
            dataset.append(times[j])
            for intensity in table[1]:
                dataset.append(intensity[j])
Yan's avatar
Yan committed
429
430
            expf.write("{}\n".format((",".join(map(str, dataset)))))
        expf.close()
3Yan's avatar
3Yan committed
431
    save_drlconfig(drls, parent, exp_f_name[2])
Yan's avatar
Yan committed
432

Yan's avatar
Yan committed
433

3Yan's avatar
3Yan committed
434
def print_graph(labels, ds, drls):
Yan's avatar
Yan committed
435
    printfig = Figure(figsize=(5, 2), dpi=100)
Yan's avatar
Yan committed
436
437
438
    printplot = printfig.add_subplot(111)
    printcanvas = FigureCanvas(printfig)
    gt.pop_plot(printplot, labels)
3Yan's avatar
3Yan committed
439
    update_drlspectrum(ds, drls, printplot)
Yan's avatar
Yan committed
440
    widget = QtWidgets.QDialog(None, windowTitle='Print preview')
Yan's avatar
Yan committed
441
442
    layout = QtWidgets.QVBoxLayout(widget)
    layout.addWidget(printcanvas)
Yan's avatar
Yan committed
443
    widget.resize(600, 400)
Yan's avatar
Yan committed
444
445
446
447
448
449
450
    widget.show()
    dialog = QtPrintSupport.QPrintDialog()
    if dialog.exec_() == QtWidgets.QDialog.Accepted:
        printcanvas.render(dialog.printer())
    widget.close()


3Yan's avatar
3Yan committed
451
def clip_range(drls):
452
    activeObject = QtWidgets.QApplication.focusWidget()
3Yan's avatar
3Yan committed
453
    if activeObject in (drls['pt'], drls['dt']):
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
        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
479
def paste_clip(ds, drls, drlspectrum):
480
    activeObject = QtWidgets.QApplication.focusWidget()
3Yan's avatar
3Yan committed
481
    if activeObject in (drls['pt'], drls['dt'])\
482
483
484
485
486
487
488
489
490
491
492
493
494
495
        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
496
                if table == drls['pt'] and j < 3:
497
                    if i >= (table.rowCount()):
3Yan's avatar
3Yan committed
498
                        add_line(ds, drls, drlspectrum)
499
                    table.item(i, j).setText(col)
3Yan's avatar
3Yan committed
500
                if table == drls['dt'] and j == 2\
501
502
503
504
                     and i < table.rowCount():
                     table.item(i,j).setText(col)


3Yan's avatar
3Yan committed
505
def key_pressed(event, ds, drls, drlspectrum):
506
    if event.key() == QtCore.Qt.Key_Delete:
507
        rows = reversed(list(map(lambda x: x.row(),
3Yan's avatar
3Yan committed
508
509
            drls['pt'].selectionModel().selectedRows())))
        remove_rows(ds, drls, drlspectrum, rows)
Yan's avatar
Yan committed
510
    if event.key() == QtCore.Qt.Key_F5:
3Yan's avatar
3Yan committed
511
512
513
        update_drlspectrum(ds, drls, drlspectrum)
        for row in range(drls['pt'].rowCount()):
            update_profile(drls['pt'], row, ds)
514
515
    if event.key() == QtCore.Qt.Key_C\
        and event.modifiers().__int__() == QtCore.Qt.ControlModifier:
3Yan's avatar
3Yan committed
516
        clip_range(drls)
517
518
    if event.key() == QtCore.Qt.Key_V\
        and event.modifiers().__int__() == QtCore.Qt.ControlModifier:
3Yan's avatar
3Yan committed
519
        paste_clip(ds, drls, drlspectrum)
520
521


Yan's avatar
Yan committed
522
def main_window(parent, ds, filename, cache):
523
    """constructs a dialog window"""
3Yan's avatar
3Yan committed
524
525
    def saveonclose(widget, event, buffer, drls, canvas):
        buffer[0], buffer[1] = drls, canvas
Yan's avatar
Yan committed
526
        QtWidgets.QMainWindow.closeEvent(widget, event)
Yan's avatar
Yan committed
527

3Yan's avatar
3Yan committed
528
529
    # pt = parenttable
    # dt = daughtertable
3Yan's avatar
3Yan committed
530
    drls = dict(pt=None, dt=None, tshift=None, cors=3, rel=None)
3Yan's avatar
3Yan committed
531

Yan's avatar
Yan committed
532
    window = QtWidgets.QMainWindow(
Yan's avatar
Yan committed
533
        parent, windowTitle='Delayed reactant labelling')
Yan's avatar
Yan committed
534
535
    main_widget = QtWidgets.QWidget(window)
    window.setCentralWidget(main_widget)
Yan's avatar
Yan committed
536

Yan's avatar
Yan committed
537
    window.closeEvent = lambda event: saveonclose(
3Yan's avatar
3Yan committed
538
        window, event, cache, drls, graph_canvas)
Yan's avatar
Yan committed
539

Yan's avatar
Yan committed
540
541
    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
542
543
544
    graph_canvas = FigureCanvas(dial_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
Yan's avatar
Yan committed
545
    graphlabels = dict(x=[0], y=[0], line=None, name="",
Yan's avatar
Yan committed
546
547
                       xlabel="time(min)",
                       ylabel="relative intensity")
Yan's avatar
Yan committed
548
549
550
551
    gt.pan_factory(chromplot)
    gt.zoom_factory(chromplot, 1.15)
    gt.pop_plot(chromplot, graphlabels)

3Yan's avatar
3Yan committed
552
553
554
555
    time_title = QtWidgets.QLabel("Time shift (min):")
    drls['tshift'] = QtWidgets.QDoubleSpinBox(
            minimum=-100, maximum=1440, decimals=3)

3Yan's avatar
3Yan committed
556
557
    drls['rel'] = QtWidgets.QCheckBox("Steady state approximation")

558
559
560
    drl_load = QtWidgets.QPushButton("&Load")
    drl_save = QtWidgets.QPushButton("&Save")
    drl_export = QtWidgets.QPushButton("&Export")
Yan's avatar
Yan committed
561
    drl_print = QtWidgets.QPushButton("&Print")
562
    close = QtWidgets.QPushButton("&Close")
Yan's avatar
Yan committed
563
    close.clicked.connect(window.close)
564

Yan's avatar
Yan committed
565
566
567
    btn_add = QtWidgets.QPushButton("&Add")
    btn_rem = QtWidgets.QPushButton("Remove")

3Yan's avatar
3Yan committed
568
    if cache == [None, None]:
3Yan's avatar
3Yan committed
569
570
571
572
573
        dcolums = ["Name"]
        for i in range(drls['cors']):
            dcolums.append("corrected for ({})".format(i+1))
            dcolums.append("factor ({})".format(i+1))
        drls['dt'] = iontable(dcolums)
3Yan's avatar
3Yan committed
574
575
        drls['pt'] = iontable(["Name", "start (m/z)", "end (m/z)",
                               "profile"])
3Yan's avatar
3Yan committed
576
577
578
579
        #TODO: DIRTY, DIRTY, DIRTY !!! do it nicer when I'll know how i want it
        for n in range(drls['dt'].columnCount()):
            drls['dt'].horizontalHeader().setSectionResizeMode(
                n, QtWidgets.QHeaderView.Interactive)
3Yan's avatar
3Yan committed
580
        add_line(ds, drls, chromplot)
Yan's avatar
Yan committed
581
    else:
3Yan's avatar
3Yan committed
582
583
        drls = cache[0]
        graph_canvas = cache[1]
584

585
    window.keyPressEvent = lambda event: key_pressed(
3Yan's avatar
3Yan committed
586
        event, ds, drls, chromplot)
587

588
    btn_add.clicked.connect(lambda: add_line(
3Yan's avatar
3Yan committed
589
        ds, drls, chromplot))
590
    btn_rem.clicked.connect(lambda: remove_rows(
3Yan's avatar
3Yan committed
591
        ds, drls, chromplot))
Yan's avatar
Yan committed
592
    drl_load.clicked.connect(lambda: load_drltables(
3Yan's avatar
3Yan committed
593
        main_widget, ds, drls, chromplot))
Yan's avatar
Yan committed
594
    drl_save.clicked.connect(lambda: save_drlconfig(
3Yan's avatar
3Yan committed
595
        drls, main_widget))
Yan's avatar
Yan committed
596
    drl_print.clicked.connect(lambda: print_graph(
3Yan's avatar
3Yan committed
597
        graphlabels, ds, drls))
Yan's avatar
Yan committed
598
    drl_export.clicked.connect(lambda: export_drlspectrum(
3Yan's avatar
3Yan committed
599
600
601
602
        main_widget, filename, ds, drls))

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

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

3Yan's avatar
3Yan committed
607
608
    drls['tshift'].valueChanged.connect(lambda: update_drlspectrum(
        ds, drls, chromplot))
609

3Yan's avatar
3Yan committed
610
611
612
    drls['rel'].stateChanged.connect(lambda: update_drlspectrum(
        ds, drls, chromplot))

Yan's avatar
Yan committed
613
    main_layout = QtWidgets.QVBoxLayout(main_widget)
Yan's avatar
Yan committed
614
    sub_layout = QtWidgets.QHBoxLayout()
3Yan's avatar
3Yan committed
615
616
    graph_layout = QtWidgets.QVBoxLayout()
    graphparams_layout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
617
    tablelayout = QtWidgets.QVBoxLayout()
Yan's avatar
Yan committed
618
    pt_butlayout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
619
    main_butlayout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
620

Yan's avatar
Yan committed
621
622
623
624
    pt_butlayout.addWidget(btn_add)
    pt_butlayout.addWidget(btn_rem)
    pt_butlayout.addStretch(0)

625
626
    main_layout.addLayout(sub_layout)
    main_layout.addWidget(HBar())
Yan's avatar
Yan committed
627
    main_layout.addLayout(main_butlayout)
628

Yan's avatar
Yan committed
629
630
    main_butlayout.addWidget(drl_load)
    main_butlayout.addWidget(drl_save)
Yan's avatar
Yan committed
631
    main_butlayout.addWidget(drl_print)
Yan's avatar
Yan committed
632
633
    main_butlayout.addStretch(1)
    main_butlayout.addWidget(drl_export)
634
    main_butlayout.addWidget(close)
Yan's avatar
Yan committed
635

3Yan's avatar
3Yan committed
636
    sub_layout.addLayout(graph_layout, stretch=1)
Yan's avatar
Yan committed
637
    sub_layout.addLayout(tablelayout)
3Yan's avatar
3Yan committed
638
639
640
641
642
    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)
3Yan's avatar
3Yan committed
643
644
    graphparams_layout.addWidget(drls['rel'])
    graphparams_layout.addStretch(1)
645

Yan's avatar
Yan committed
646
    tablelayout.addWidget(QtWidgets.QLabel("Raw ions table:"))
3Yan's avatar
3Yan committed
647
    tablelayout.addWidget(drls['pt'])
Yan's avatar
Yan committed
648
649
    tablelayout.addLayout(pt_butlayout)
    tablelayout.addWidget(QtWidgets.QLabel("Corrected ions table:"))
3Yan's avatar
3Yan committed
650
    tablelayout.addWidget(drls['dt'])
651

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