drltools.py 25.1 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
import logging
Yan's avatar
Yan committed
15
16
matplotlib.use("Qt5Agg")

Yan's avatar
Yan committed
17

Yan's avatar
Yan committed
18
19
20
logger = logging.getLogger('drlLogger')


Yan's avatar
Yan committed
21
class HBar(QtWidgets.QFrame):
22
    """horizontal bar class"""
Yan's avatar
Yan committed
23
24
25
26
27
28
    def __init__(self):
        super(HBar, self).__init__()
        self._main = QtWidgets.QWidget()
        self.setFrameShape(QtWidgets.QFrame.HLine)


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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):
Yan's avatar
Yan committed
44
    """parent table profile spectrum updating procedure"""
Yan's avatar
Yan committed
45
    # Dont do anything to graph when the spectrum is not populated
Yan's avatar
Yan committed
46
    logger.debug("updating parent table row {} profile".format(row))
Yan's avatar
Yan committed
47
    if isinstance(dataset['masses'], type(None)):
48
49
        return

50
    spectrum = pt.cellWidget(row, 3).figure.get_axes()[0]
Yan's avatar
Yan committed
51
    masses = dataset['masses']
52
53
    massargs = dt.argsubselect(
        masses, floatize(pt, row, 1), floatize(pt, row, 2))
54
    yshape = np.mean(dataset['matrix'], axis=0)
Yan's avatar
Yan committed
55
    spectrum.clear()
56
57
58
    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
59
60
61
    spectrum.set_xlim(masses[massargs[0]]-xex,
                      masses[massargs[-1]]+xex)
    ymax = max(yshape[massargs])
62
63
64
    spectrum.set_ylim(ymax*-0.1, ymax*1.2)
    spectrum.figure.canvas.draw()

Yan's avatar
Yan committed
65

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


3Yan's avatar
3Yan committed
76
def get_daughterset(ds, drls):
Yan's avatar
Yan committed
77
    # TODO: write a less resources demanding function - probably "per-line"
Yan's avatar
Yan committed
78
    names = []
3Yan's avatar
3Yan committed
79
    times = ds['chrom_dat'][0, :] - drls['tshift'].value()
Yan's avatar
Yan committed
80
    intensities = []
3Yan's avatar
3Yan committed
81
82
83
    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
84
85
86
87
88
89
90
91
92
93
94
            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
95
            intensities.append(intensity)
3Yan's avatar
3Yan committed
96
            names.append("{} - ({})".format(
3Yan's avatar
3Yan committed
97
                drls['dt'].item(row, 0).text(),
3Yan's avatar
3Yan committed
98
                cortext))
Yan's avatar
Yan committed
99
100
101
    return names, times, intensities


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


3Yan's avatar
3Yan committed
122
def update_drlspectrum(ds, drls, drlspectrum):
Yan's avatar
Yan committed
123
124
    """Generic DRL spectrum updating procedure"""
    logger.info("updating DRL spectrum")
125
    # Dont do anything when the dataset is not populated
Yan's avatar
Yan committed
126
    if isinstance(ds['masses'], type(None)):
Yan's avatar
Yan committed
127
        return
128
    colors = np.array([[0, 0, 0], [255, 0, 0], [0, 255, 0], [0, 0, 255],
129
130
131
                       [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
132

133
    # TODO: write a less resources demanding function
3Yan's avatar
3Yan committed
134
    names, times, intensities = get_daughterset(ds, drls)
Yan's avatar
Yan committed
135
136
    for i in range(len(drlspectrum.lines)):
        drlspectrum.lines[0].remove()
137

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

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

157
    if len(names) != 0:
3Yan's avatar
3Yan committed
158
159
160
161
        gmax = np.amax(intensities)
        if drls['rel'].checkState() == 2:
            gmax = 1
        drlspectrum.set_ylim(top=gmax*1.1, bottom=gmax*-0.01)
162
        drlspectrum.legend(loc=2)
163
164
    drlspectrum.figure.canvas.draw()

Yan's avatar
Yan committed
165

Yan's avatar
Yan committed
166
def gettableitemlist(ptable):
167
    ion_list = []
Yan's avatar
Yan committed
168
169
170
    for row in range(ptable.rowCount()):
        text = []
        for i in range(3):
171
172
            if not isinstance(ptable.item(row, i), type(None)):
                frg = ptable.item(row, i).text()
Yan's avatar
Yan committed
173
174
175
176
177
            else:
                frg = ""
            text.append(frg)
        line = "{} ({}-{})".format(*text)
        ion_list.append(line)
178
179
180
    return ion_list


3Yan's avatar
3Yan committed
181
def update_corrfors(drls):
182
    """update corrections selection layout of the daughter table"""
3Yan's avatar
3Yan committed
183
184
    ionlist = gettableitemlist(drls['pt'])
    for row in range(drls['dt'].rowCount()):
3Yan's avatar
3Yan committed
185
186
187
188
189
190
191
192
193
        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
194

195

3Yan's avatar
3Yan committed
196
def ptable_changed(row, column, ds, drls, drlspectrum):
197
    """routine called by change of the ptable spectra"""
Yan's avatar
Yan committed
198
    logger.debug("ptable changed routine called")
3Yan's avatar
3Yan committed
199
200
    update_corrfors(drls)
    drls['dt'].item(row, 0).setText(gettableitemlist(drls['pt'])[row])
201
    if column in (1, 2):
3Yan's avatar
3Yan committed
202
        update_profile(drls['pt'], row, ds)
203

204

3Yan's avatar
3Yan committed
205
def dtable_changed(row, column, ds, drls, drlspectrum):
206
    """routine called by change of the dtable spectra"""
3Yan's avatar
3Yan committed
207
    #TODO: multiple corrections not incorporated!!!
3Yan's avatar
3Yan committed
208
    if drls['dt'].cellWidget(row, 0).checkState() == 2:
209
210
        if (column == 0)\
           or (column == 2
3Yan's avatar
3Yan committed
211
212
               and drls['dt'].cellWidget(row, 1).currentIndex() != 0):
                update_drlspectrum(ds, drls, drlspectrum)
213

Yan's avatar
Yan committed
214

3Yan's avatar
3Yan committed
215
def corr_changed(row, ds, drls, drlspectrum):
216
    """routine called by change of correction for ion"""
3Yan's avatar
3Yan committed
217
    #TODO: multiple corrections not incorporated!!!
3Yan's avatar
3Yan committed
218
219
220
    if (drls['dt'].cellWidget(row, 0).checkState() == 2
       and floatize(drls['dt'], row, 2) != 0):
        update_drlspectrum(ds, drls, drlspectrum)
221
222


3Yan's avatar
3Yan committed
223
def remove_rows(ds, drls, drlspectrum, rows=None):
Yan's avatar
Yan committed
224
    # TODO: maybe nicer selection in future, but this works for now
225
226
    if rows == None:
        rows = reversed(list(set(
3Yan's avatar
3Yan committed
227
            map(lambda x: x.row(), drls['pt'].selectedIndexes()))))
228
    for row in rows:
3Yan's avatar
3Yan committed
229
230
231
232
        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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
            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))
249
250


3Yan's avatar
3Yan committed
251
def add_line(ds, drls, drlspectrum):
252
    """add parent ion to the table"""
Yan's avatar
Yan committed
253
    logger.debug("adding line")
3Yan's avatar
3Yan committed
254
    newrow = drls['pt'].rowCount()
255

3Yan's avatar
3Yan committed
256
257
    drls['pt'].blockSignals(True)
    drls['dt'].blockSignals(True)
258

3Yan's avatar
3Yan committed
259
    drls['pt'].setRowCount(newrow + 1)
260
    for i in range(3):
3Yan's avatar
3Yan committed
261
        drls['pt'].setItem(newrow, i, QtWidgets.QTableWidgetItem())
262
        if newrow is not 0:
3Yan's avatar
3Yan committed
263
264
            drls['pt'].item(newrow, i).setText(str(floatize(
                    drls['pt'], newrow-1, i)+1))
265

266
    ion_graph = Figure(figsize=(3, 1.5), dpi=100, facecolor="None")
267
268
    ion_graph.add_subplot(111, facecolor=(1, 1, 1, 0.8),
                          position=(-0.01, -0.01, 1.02, 1.02))
269
270
271
    graph_canvas = FigureCanvas(ion_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
3Yan's avatar
3Yan committed
272
    drls['pt'].setCellWidget(newrow, 3, graph_canvas)
273

3Yan's avatar
3Yan committed
274
    drls['dt'].setRowCount(newrow + 1)
Yan's avatar
Yan committed
275
    checkbox = QtWidgets.QCheckBox()
3Yan's avatar
3Yan committed
276
    checkbox.setFocusProxy(drls['dt'])
277
278
    dname = QtWidgets.QTableWidgetItem()
    dname.setFlags(dname.flags() & ~QtCore.Qt.ItemIsEditable)
Yan's avatar
Yan committed
279
    dname.setTextAlignment(QtCore.Qt.AlignRight)
3Yan's avatar
3Yan committed
280
281
    drls['dt'].setItem(newrow, 0, dname)
    drls['dt'].setCellWidget(newrow, 0, checkbox)
3Yan's avatar
3Yan committed
282
283
284

    for i in range(drls['cors']):
        corfor = QtWidgets.QComboBox()
Yan's avatar
Yan committed
285
286
        #TODO: verify on windows that this fixed the weird selection issues
        #corfor.setFocusProxy(drls['dt'])
3Yan's avatar
3Yan committed
287
288
289
290
291
        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))
292

3Yan's avatar
3Yan committed
293
294
    drls['pt'].blockSignals(False)
    drls['dt'].blockSignals(False)
295

3Yan's avatar
3Yan committed
296
    ptable_changed(newrow, 1, ds, drls, drlspectrum)
297

Yan's avatar
Yan committed
298
    checkbox.stateChanged.connect(lambda: update_drlspectrum(
3Yan's avatar
3Yan committed
299
        ds, drls, drlspectrum))
300
301


Yan's avatar
Yan committed
302
def iontable(labels):
303
304
    """creates a table for ions"""
    table = QtWidgets.QTableWidget(columnCount=len(labels))
305
    table.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
306
307
                        QtWidgets.QSizePolicy.Expanding)
    table.setHorizontalHeaderLabels(labels)
308
309
310
311
312
    table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)

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

315
    return table
316
317


3Yan's avatar
3Yan committed
318
def load_drltables(parent, dataset, drls, drlspectrum):
Yan's avatar
Yan committed
319
320
321
322
323
324
325
326
    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 = []
3Yan's avatar
3Yan committed
327
        corrections = []
Yan's avatar
Yan committed
328

3Yan's avatar
3Yan committed
329

Yan's avatar
Yan committed
330
331
        with open(filename, 'r') as cfile:
            rawdata = cfile.read().splitlines()
3Yan's avatar
3Yan committed
332
333
        for i in range(len(rawdata[0].split(","))-4):
            corrections.append([])
Yan's avatar
Yan committed
334
335
        for i in range(1, len(rawdata)):
            rawline = rawdata[i].split(",")
336
            # TODO: rawline[4] can be -1 - decide if accept this behaviour
Yan's avatar
Yan committed
337
338
339
340
            n = len(rawline)
            if n < 6 or not n % 2 == 0 or (int(rawline[3]) not in
                range(3)) or not (set(map(int, rawline[4:n:2])) &
                set(range(-1, n))):
Yan's avatar
Yan committed
341
342
343
344
345
346
                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,
3Yan's avatar
3Yan committed
347
                                   states, *corrections)):
Yan's avatar
Yan committed
348
                k.append(rawline[j])
3Yan's avatar
3Yan committed
349
350
351
        for row in reversed(range(drls['pt'].rowCount())):
            drls['dt'].removeRow(row)
            drls['pt'].removeRow(row)
352
        # first populate only the parent table
Yan's avatar
Yan committed
353
        for i in range(len(names)):
3Yan's avatar
3Yan committed
354
355
356
357
            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])
358
        # and after that the daughter table
Yan's avatar
Yan committed
359
        for i in range(len(names)):
3Yan's avatar
3Yan committed
360
            for j in range(int((len(rawline)-4)/2)):
3Yan's avatar
3Yan committed
361
                drls['dt'].cellWidget(i, 1+j*2).setCurrentIndex(
3Yan's avatar
3Yan committed
362
363
                    int(corrections[0+j*2][i]))
                drls['dt'].item(i, 2+j*2).setText(corrections[1+j*2][i])
3Yan's avatar
3Yan committed
364
            drls['dt'].cellWidget(i, 0).setCheckState(int(states[i]))
Yan's avatar
Yan committed
365
366


3Yan's avatar
3Yan committed
367
def save_drlconfig(drls, parent, exp_f_name=None):
Yan's avatar
Yan committed
368
    """safe DRL table layout so it can be summoned when needed"""
369
370
371
372
    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
373
    if exp_f_name is not '':
3Yan's avatar
3Yan committed
374
375
376
377
378
        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
379
380
        expf = open(exp_f_name, 'w')
        expf.write("#ion_name, start m/z, end m/z, visible,"
3Yan's avatar
3Yan committed
381
                   "{}\n".format(cortext))
3Yan's avatar
3Yan committed
382
        for row in range(drls['pt'].rowCount()):
Yan's avatar
Yan committed
383
384
            vals = []
            for i in range(3):
3Yan's avatar
3Yan committed
385
386
                vals.append(drls['pt'].item(row, i).text())
            vals.append(drls['dt'].cellWidget(row, 0).checkState())
3Yan's avatar
3Yan committed
387
388
389
            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
390
391
392
            expf.write("{}\n".format((",".join(map(str, vals)))))
        expf.close()

Yan's avatar
Yan committed
393

3Yan's avatar
3Yan committed
394
def export_drlspectrum(parent, fn, ds, drls):
Yan's avatar
Yan committed
395
396
    if fn[0] is None:
        QtWidgets.QMessageBox.warning(
397
            None, "Export DRL dataset",
Yan's avatar
Yan committed
398
399
            "Nothing to export, cancelling request")
        return
3Yan's avatar
3Yan committed
400
401
402
    names, times, intensities = get_daughterset(ds, drls)
    subset = np.where(times > 0)[0]
    times = times[subset]
Yan's avatar
Yan committed
403
    intensities = list(map(lambda x: x[subset], intensities))
3Yan's avatar
3Yan committed
404
405

    pnames, ptimes, pintensities = get_parentset(ds, drls)
406
407
408
409
410
411
412
413
414
415
416
417
418
419
    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
420
421
422
423
424
425
426
427
428
429
    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
430
431
432
433
434
435
436
    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
437
            dataset = list()
438
439
440
            dataset.append(times[j])
            for intensity in table[1]:
                dataset.append(intensity[j])
Yan's avatar
Yan committed
441
442
            expf.write("{}\n".format((",".join(map(str, dataset)))))
        expf.close()
3Yan's avatar
3Yan committed
443
    save_drlconfig(drls, parent, exp_f_name[2])
Yan's avatar
Yan committed
444

Yan's avatar
Yan committed
445

3Yan's avatar
3Yan committed
446
def print_graph(labels, ds, drls):
Yan's avatar
Yan committed
447
    printfig = Figure(figsize=(5, 2), dpi=100)
Yan's avatar
Yan committed
448
449
450
    printplot = printfig.add_subplot(111)
    printcanvas = FigureCanvas(printfig)
    gt.pop_plot(printplot, labels)
3Yan's avatar
3Yan committed
451
    update_drlspectrum(ds, drls, printplot)
Yan's avatar
Yan committed
452
    widget = QtWidgets.QDialog(None, windowTitle='Print preview')
Yan's avatar
Yan committed
453
454
    layout = QtWidgets.QVBoxLayout(widget)
    layout.addWidget(printcanvas)
Yan's avatar
Yan committed
455
    widget.resize(600, 400)
Yan's avatar
Yan committed
456
457
458
459
460
461
462
    widget.show()
    dialog = QtPrintSupport.QPrintDialog()
    if dialog.exec_() == QtWidgets.QDialog.Accepted:
        printcanvas.render(dialog.printer())
    widget.close()


3Yan's avatar
3Yan committed
463
def clip_range(drls):
464
    activeObject = QtWidgets.QApplication.focusWidget()
3Yan's avatar
3Yan committed
465
    if activeObject in (drls['pt'], drls['dt']):
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
        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
491
def paste_clip(ds, drls, drlspectrum):
492
    activeObject = QtWidgets.QApplication.focusWidget()
3Yan's avatar
3Yan committed
493
    if activeObject in (drls['pt'], drls['dt'])\
494
495
496
497
498
499
500
501
502
503
504
505
506
507
        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
508
                if table == drls['pt'] and j < 3:
509
                    if i >= (table.rowCount()):
3Yan's avatar
3Yan committed
510
                        add_line(ds, drls, drlspectrum)
511
                    table.item(i, j).setText(col)
3Yan's avatar
3Yan committed
512
                if table == drls['dt'] and j == 2\
513
514
515
516
                     and i < table.rowCount():
                     table.item(i,j).setText(col)


3Yan's avatar
3Yan committed
517
def key_pressed(event, ds, drls, drlspectrum):
518
    if event.key() == QtCore.Qt.Key_Delete:
519
        rows = reversed(list(map(lambda x: x.row(),
3Yan's avatar
3Yan committed
520
521
            drls['pt'].selectionModel().selectedRows())))
        remove_rows(ds, drls, drlspectrum, rows)
Yan's avatar
Yan committed
522
    if event.key() == QtCore.Qt.Key_F5:
3Yan's avatar
3Yan committed
523
524
525
        update_drlspectrum(ds, drls, drlspectrum)
        for row in range(drls['pt'].rowCount()):
            update_profile(drls['pt'], row, ds)
526
527
    if event.key() == QtCore.Qt.Key_C\
        and event.modifiers().__int__() == QtCore.Qt.ControlModifier:
3Yan's avatar
3Yan committed
528
        clip_range(drls)
529
530
    if event.key() == QtCore.Qt.Key_V\
        and event.modifiers().__int__() == QtCore.Qt.ControlModifier:
3Yan's avatar
3Yan committed
531
        paste_clip(ds, drls, drlspectrum)
532
533


Yan's avatar
Yan committed
534
def main_window(parent, ds, filename, cache):
535
    """constructs a dialog window"""
3Yan's avatar
3Yan committed
536
537
    def saveonclose(widget, event, buffer, drls, canvas):
        buffer[0], buffer[1] = drls, canvas
Yan's avatar
Yan committed
538
        QtWidgets.QMainWindow.closeEvent(widget, event)
Yan's avatar
Yan committed
539

3Yan's avatar
3Yan committed
540
541
    # pt = parenttable
    # dt = daughtertable
3Yan's avatar
3Yan committed
542
    drls = dict(pt=None, dt=None, tshift=None, cors=3, rel=None)
3Yan's avatar
3Yan committed
543

Yan's avatar
Yan committed
544
    window = QtWidgets.QMainWindow(
Yan's avatar
Yan committed
545
        parent, windowTitle='Delayed reactant labelling')
Yan's avatar
Yan committed
546
547
    main_widget = QtWidgets.QWidget(window)
    window.setCentralWidget(main_widget)
Yan's avatar
Yan committed
548

Yan's avatar
Yan committed
549
    window.closeEvent = lambda event: saveonclose(
3Yan's avatar
3Yan committed
550
        window, event, cache, drls, graph_canvas)
Yan's avatar
Yan committed
551

Yan's avatar
Yan committed
552
553
    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
554
555
556
    graph_canvas = FigureCanvas(dial_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
Yan's avatar
Yan committed
557
    graphlabels = dict(x=[0], y=[0], line=None, name="",
Yan's avatar
Yan committed
558
559
                       xlabel="time(min)",
                       ylabel="relative intensity")
Yan's avatar
Yan committed
560
561
562
563
    gt.pan_factory(chromplot)
    gt.zoom_factory(chromplot, 1.15)
    gt.pop_plot(chromplot, graphlabels)

3Yan's avatar
3Yan committed
564
565
566
567
    time_title = QtWidgets.QLabel("Time shift (min):")
    drls['tshift'] = QtWidgets.QDoubleSpinBox(
            minimum=-100, maximum=1440, decimals=3)

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

570
571
572
    drl_load = QtWidgets.QPushButton("&Load")
    drl_save = QtWidgets.QPushButton("&Save")
    drl_export = QtWidgets.QPushButton("&Export")
Yan's avatar
Yan committed
573
    drl_print = QtWidgets.QPushButton("&Print")
574
    close = QtWidgets.QPushButton("&Close")
Yan's avatar
Yan committed
575
    close.clicked.connect(window.close)
576

Yan's avatar
Yan committed
577
578
579
    btn_add = QtWidgets.QPushButton("&Add")
    btn_rem = QtWidgets.QPushButton("Remove")

3Yan's avatar
3Yan committed
580
    if cache == [None, None]:
3Yan's avatar
3Yan committed
581
582
583
584
585
        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
586
587
        drls['pt'] = iontable(["Name", "start (m/z)", "end (m/z)",
                               "profile"])
3Yan's avatar
3Yan committed
588
589
590
591
        #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
592
        add_line(ds, drls, chromplot)
Yan's avatar
Yan committed
593
    else:
3Yan's avatar
3Yan committed
594
595
        drls = cache[0]
        graph_canvas = cache[1]
596

597
    window.keyPressEvent = lambda event: key_pressed(
3Yan's avatar
3Yan committed
598
        event, ds, drls, chromplot)
599

600
    btn_add.clicked.connect(lambda: add_line(
3Yan's avatar
3Yan committed
601
        ds, drls, chromplot))
602
    btn_rem.clicked.connect(lambda: remove_rows(
3Yan's avatar
3Yan committed
603
        ds, drls, chromplot))
Yan's avatar
Yan committed
604
    drl_load.clicked.connect(lambda: load_drltables(
3Yan's avatar
3Yan committed
605
        main_widget, ds, drls, chromplot))
Yan's avatar
Yan committed
606
    drl_save.clicked.connect(lambda: save_drlconfig(
3Yan's avatar
3Yan committed
607
        drls, main_widget))
Yan's avatar
Yan committed
608
    drl_print.clicked.connect(lambda: print_graph(
3Yan's avatar
3Yan committed
609
        graphlabels, ds, drls))
Yan's avatar
Yan committed
610
    drl_export.clicked.connect(lambda: export_drlspectrum(
3Yan's avatar
3Yan committed
611
612
613
614
        main_widget, filename, ds, drls))

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

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

3Yan's avatar
3Yan committed
619
620
    drls['tshift'].valueChanged.connect(lambda: update_drlspectrum(
        ds, drls, chromplot))
621

3Yan's avatar
3Yan committed
622
623
624
    drls['rel'].stateChanged.connect(lambda: update_drlspectrum(
        ds, drls, chromplot))

Yan's avatar
Yan committed
625
    main_layout = QtWidgets.QVBoxLayout(main_widget)
Yan's avatar
Yan committed
626
    sub_layout = QtWidgets.QHBoxLayout()
3Yan's avatar
3Yan committed
627
628
    graph_layout = QtWidgets.QVBoxLayout()
    graphparams_layout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
629
    tablelayout = QtWidgets.QVBoxLayout()
Yan's avatar
Yan committed
630
    pt_butlayout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
631
    main_butlayout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
632

Yan's avatar
Yan committed
633
634
635
636
    pt_butlayout.addWidget(btn_add)
    pt_butlayout.addWidget(btn_rem)
    pt_butlayout.addStretch(0)

637
638
    main_layout.addLayout(sub_layout)
    main_layout.addWidget(HBar())
Yan's avatar
Yan committed
639
    main_layout.addLayout(main_butlayout)
640

Yan's avatar
Yan committed
641
642
    main_butlayout.addWidget(drl_load)
    main_butlayout.addWidget(drl_save)
Yan's avatar
Yan committed
643
    main_butlayout.addWidget(drl_print)
Yan's avatar
Yan committed
644
645
    main_butlayout.addStretch(1)
    main_butlayout.addWidget(drl_export)
646
    main_butlayout.addWidget(close)
Yan's avatar
Yan committed
647

3Yan's avatar
3Yan committed
648
    sub_layout.addLayout(graph_layout, stretch=1)
Yan's avatar
Yan committed
649
    sub_layout.addLayout(tablelayout)
3Yan's avatar
3Yan committed
650
651
652
653
654
    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
655
656
    graphparams_layout.addWidget(drls['rel'])
    graphparams_layout.addStretch(1)
657

Yan's avatar
Yan committed
658
    tablelayout.addWidget(QtWidgets.QLabel("Raw ions table:"))
3Yan's avatar
3Yan committed
659
    tablelayout.addWidget(drls['pt'])
Yan's avatar
Yan committed
660
661
    tablelayout.addLayout(pt_butlayout)
    tablelayout.addWidget(QtWidgets.QLabel("Corrected ions table:"))
3Yan's avatar
3Yan committed
662
    tablelayout.addWidget(drls['dt'])
663

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