drltools.py 27.2 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
3Yan's avatar
3Yan committed
8
from copy import copy
Yan's avatar
Yan committed
9
10
import matplotlib
import numpy as np
Yan's avatar
Yan committed
11
12
import prasopes.datatools as dt
import prasopes.graphtools as gt
Yan's avatar
Yan committed
13
import prasopes.filetools as ft
Yan's avatar
Yan committed
14
import os.path
Yan's avatar
Yan committed
15
import logging
Yan's avatar
Yan committed
16
17
matplotlib.use("Qt5Agg")

Yan's avatar
Yan committed
18

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


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


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

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

Yan's avatar
Yan committed
67

3Yan's avatar
3Yan committed
68
69
70
def get_intensity(row, ds, drls):
    startm = floatize(drls['pt'], row, 1)
    endm = floatize(drls['pt'], row, 2)
Yan's avatar
Yan committed
71
    massargs = dt.argsubselect(ds['masses'], startm, endm)
Yan's avatar
Yan committed
72
73
74
75
    #prevent division by 0
    intensity = np.divide(np.sum( ds['matrix'].T[massargs].T, axis=1),
            np.clip(ds['chrom_dat'][1], np.nextafter(
                0, 1, dtype=np.float32), None))
Yan's avatar
Yan committed
76
77
78
    return intensity


3Yan's avatar
3Yan committed
79
def get_daughterset(ds, drls):
Yan's avatar
Yan committed
80
81
    """Fuction to acquire the curves of the daugher ions"""
    logger.info("getting set of the daughter ions")
Yan's avatar
Yan committed
82
    # TODO: write a less resources demanding function - probably "per-line"
Yan's avatar
Yan committed
83
    names = []
3Yan's avatar
3Yan committed
84
    times = ds['chrom_dat'][0, :] - drls['tshift'].value()
Yan's avatar
Yan committed
85
    intensities = []
3Yan's avatar
3Yan committed
86
87
88
    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
89
90
91
92
            corlist = []
            for i in range(drls['cors']):
                cor = drls['dt'].cellWidget(row, 1+i*2).currentIndex() - 1
                if cor not in (-2, -1):
Yan's avatar
Yan committed
93
                    factor = floatize(drls['dt'], row, 2+i*2, False)
3Yan's avatar
3Yan committed
94
95
96
97
98
99
                    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
100
            intensities.append(intensity)
3Yan's avatar
3Yan committed
101
            names.append("{} - ({})".format(
3Yan's avatar
3Yan committed
102
                drls['dt'].item(row, 0).text(),
3Yan's avatar
3Yan committed
103
                cortext))
Yan's avatar
Yan committed
104
105
106
    return names, times, intensities


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


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

138
    # TODO: write a less resources demanding function
3Yan's avatar
3Yan committed
139
    names, times, intensities = get_daughterset(ds, drls)
Yan's avatar
Yan committed
140
141
    for i in range(len(drlspectrum.lines)):
        drlspectrum.lines[0].remove()
142

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

145
    i = 0
3Yan's avatar
3Yan committed
146
147
148
149
    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(
150
                QtGui.QColor(*colors[row % len(colors)], alpha=50)))
3Yan's avatar
3Yan committed
151
152
            drls['dt'].blockSignals(False)
            label = " {}".format(drls['pt'].item(row, 0).text())
3Yan's avatar
3Yan committed
153
154
            intensity = intensities[i]
            if drls['rel'].checkState() == 2:
Yan's avatar
Yan committed
155
156
157
                #Do not divide by 0
                intensity = np.divide(intensity, np.clip(np.sum(
                    intensities, 0), np.nextafter(
3Yan's avatar
3Yan committed
158
                        0, 1, dtype=np.float32), None), dtype=np.float64)
3Yan's avatar
3Yan committed
159
            drlspectrum.plot(times, intensity, label=label,
160
161
                             color=(colors[row % len(colors)] / 255))
            i += 1
162
        else:
3Yan's avatar
3Yan committed
163
            drls['dt'].item(row, 0).setBackground(QtGui.QBrush())
164

165
    if len(names) != 0:
3Yan's avatar
3Yan committed
166
167
168
169
        gmax = np.amax(intensities)
        if drls['rel'].checkState() == 2:
            gmax = 1
        drlspectrum.set_ylim(top=gmax*1.1, bottom=gmax*-0.01)
170
        drlspectrum.legend(loc=2)
171
172
    drlspectrum.figure.canvas.draw()

Yan's avatar
Yan committed
173

Yan's avatar
Yan committed
174
def gettableitemlist(ptable):
175
    ion_list = []
Yan's avatar
Yan committed
176
177
178
    for row in range(ptable.rowCount()):
        text = []
        for i in range(3):
179
180
            if not isinstance(ptable.item(row, i), type(None)):
                frg = ptable.item(row, i).text()
Yan's avatar
Yan committed
181
182
183
184
185
            else:
                frg = ""
            text.append(frg)
        line = "{} ({}-{})".format(*text)
        ion_list.append(line)
186
187
188
    return ion_list


3Yan's avatar
3Yan committed
189
def update_corrfors(drls):
190
    """update corrections selection layout of the daughter table"""
3Yan's avatar
3Yan committed
191
192
    ionlist = gettableitemlist(drls['pt'])
    for row in range(drls['dt'].rowCount()):
3Yan's avatar
3Yan committed
193
194
195
196
197
198
199
200
201
        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
202

203

3Yan's avatar
3Yan committed
204
def ptable_changed(row, column, ds, drls, drlspectrum):
205
    """routine called by change of the ptable spectra"""
Yan's avatar
Yan committed
206
    logger.debug("ptable changed routine called")
3Yan's avatar
3Yan committed
207
208
    update_corrfors(drls)
    drls['dt'].item(row, 0).setText(gettableitemlist(drls['pt'])[row])
209
    if column in (1, 2):
3Yan's avatar
3Yan committed
210
        update_profile(drls['pt'], row, ds)
211

212

3Yan's avatar
3Yan committed
213
def dtable_changed(row, column, ds, drls, drlspectrum):
214
    """routine called by change of the dtable spectra"""
Yan's avatar
Yan committed
215
    logger.info("Change in the daughter ion table detected")
3Yan's avatar
3Yan committed
216
    if drls['dt'].cellWidget(row, 0).checkState() == 2:
Yan's avatar
Yan committed
217
218
219
        if (column == 0) or (column % 2 == 0 and drls['dt'].cellWidget(
            row, column-1).currentIndex() != 0):
            update_drlspectrum(ds, drls, drlspectrum)
220

Yan's avatar
Yan committed
221

3Yan's avatar
3Yan committed
222
def corr_changed(correction, ds, drls, drlspectrum):
223
    """routine called by change of correction for ion"""
Yan's avatar
Yan committed
224
    logger.info('''Change of the "correct to" detected''')
3Yan's avatar
3Yan committed
225
226
227
228
    for i in range(drls['dt'].rowCount()):
        for j in range(drls['dt'].columnCount()):
            if correction == drls['dt'].cellWidget(i, 1+j*2):
                row, column = i, 1 + j*2
3Yan's avatar
3Yan committed
229
    if (drls['dt'].cellWidget(row, 0).checkState() == 2
3Yan's avatar
3Yan committed
230
       and floatize(drls['dt'], row, column+1, False) != 0):
3Yan's avatar
3Yan committed
231
        update_drlspectrum(ds, drls, drlspectrum)
232
233


3Yan's avatar
3Yan committed
234
def remove_rows(ds, drls, drlspectrum, rows=None):
Yan's avatar
Yan committed
235
    # TODO: maybe nicer selection in future, but this works for now
3Yan's avatar
3Yan committed
236
    logger.info("remowing rows")
237
238
    if rows == None:
        rows = reversed(list(set(
3Yan's avatar
3Yan committed
239
            map(lambda x: x.row(), drls['pt'].selectedIndexes()))))
240
    for row in rows:
3Yan's avatar
3Yan committed
241
242
243
        drls['dt'].cellWidget(row,0).setCheckState(0)
        drls['dt'].removeRow(row)
        drls['pt'].removeRow(row)
3Yan's avatar
3Yan committed
244
        cors = []
3Yan's avatar
3Yan committed
245
        for i in range(drls['dt'].rowCount()):
3Yan's avatar
3Yan committed
246
247
            for cornum in range(drls['cors']):
                corfor = drls['dt'].cellWidget(i, 1+cornum*2)
3Yan's avatar
3Yan committed
248
                cors.append(corfor)
3Yan's avatar
3Yan committed
249
250
251
252
253
254
255
                corfor.disconnect()
                index = corfor.currentIndex()
                corfor.clear()
                corfor.addItem("")
                corfor.addItems(gettableitemlist(drls['pt']))
                if index == row+1:
                    corfor.setCurrentIndex(0)
3Yan's avatar
3Yan committed
256
                    corr_changed(corfor, ds, drls, drlspectrum)
3Yan's avatar
3Yan committed
257
258
259
260
                elif index > row+1:
                    corfor.setCurrentIndex(index-1)
                else:
                    corfor.setCurrentIndex(index)
3Yan's avatar
3Yan committed
261
262
    list(map(lambda x: x.currentIndexChanged.connect(lambda:
        corr_changed(x, ds, drls, drlspectrum)), cors))
263
264


3Yan's avatar
3Yan committed
265
def add_line(ds, drls, drlspectrum):
266
    """add parent ion to the table"""
Yan's avatar
Yan committed
267
    logger.debug("adding line")
3Yan's avatar
3Yan committed
268
    newrow = drls['pt'].rowCount()
269

3Yan's avatar
3Yan committed
270
271
    drls['pt'].blockSignals(True)
    drls['dt'].blockSignals(True)
272

3Yan's avatar
3Yan committed
273
    drls['pt'].setRowCount(newrow + 1)
274
    for i in range(3):
3Yan's avatar
3Yan committed
275
        drls['pt'].setItem(newrow, i, QtWidgets.QTableWidgetItem())
276
        if newrow is not 0:
3Yan's avatar
3Yan committed
277
278
            drls['pt'].item(newrow, i).setText(str(floatize(
                    drls['pt'], newrow-1, i)+1))
279

280
    ion_graph = Figure(figsize=(3, 1.5), dpi=100, facecolor="None")
281
282
    ion_graph.add_subplot(111, facecolor=(1, 1, 1, 0.8),
                          position=(-0.01, -0.01, 1.02, 1.02))
283
284
285
    graph_canvas = FigureCanvas(ion_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
3Yan's avatar
3Yan committed
286
    drls['pt'].setCellWidget(newrow, 3, graph_canvas)
287

3Yan's avatar
3Yan committed
288
    drls['dt'].setRowCount(newrow + 1)
Yan's avatar
Yan committed
289
    checkbox = QtWidgets.QCheckBox()
3Yan's avatar
3Yan committed
290
    checkbox.setFocusProxy(drls['dt'])
291
292
    dname = QtWidgets.QTableWidgetItem()
    dname.setFlags(dname.flags() & ~QtCore.Qt.ItemIsEditable)
Yan's avatar
Yan committed
293
    dname.setTextAlignment(QtCore.Qt.AlignRight)
3Yan's avatar
3Yan committed
294
295
    drls['dt'].setItem(newrow, 0, dname)
    drls['dt'].setCellWidget(newrow, 0, checkbox)
3Yan's avatar
3Yan committed
296
297

    for i in range(drls['cors']):
3Yan's avatar
3Yan committed
298
299
300
301
        col = copy(1+i*2)
        drls['dt'].setCellWidget(newrow, col, QtWidgets.QComboBox())
        drls['dt'].cellWidget(newrow, col).setFrame(False)
        drls['dt'].setItem(newrow, col+1, QtWidgets.QTableWidgetItem())
302

3Yan's avatar
3Yan committed
303
304
    drls['pt'].blockSignals(False)
    drls['dt'].blockSignals(False)
305

3Yan's avatar
3Yan committed
306
307
308
309
310
311
312
313
    #dirty hack, but if if cycle is applied it assigns all cellWidgets
    #to a maximal value of i (as this is the value of i after the end
    #of the cycle)
    cors = list(map(lambda x: drls['dt'].cellWidget(newrow, 1+x*2),
                    range(drls['cors'])))
    list(map(lambda x: x.currentIndexChanged.connect(lambda:
        corr_changed(x, ds, drls, drlspectrum)), cors))

3Yan's avatar
3Yan committed
314
    ptable_changed(newrow, 1, ds, drls, drlspectrum)
315
    select_all_btn_up(ds, drls, drlspectrum)
316

Yan's avatar
Yan committed
317
    checkbox.stateChanged.connect(lambda: update_drlspectrum(
3Yan's avatar
3Yan committed
318
        ds, drls, drlspectrum))
319
320
    checkbox.stateChanged.connect(lambda: select_all_btn_up(
        ds, drls, drlspectrum))
321
322


Yan's avatar
Yan committed
323
def iontable(labels):
324
325
    """creates a table for ions"""
    table = QtWidgets.QTableWidget(columnCount=len(labels))
326
    table.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
327
328
                        QtWidgets.QSizePolicy.Expanding)
    table.setHorizontalHeaderLabels(labels)
329
330
331
332
333
    table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)

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

336
    return table
337
338


3Yan's avatar
3Yan committed
339
def load_drltables(parent, dataset, drls, drlspectrum):
Yan's avatar
Yan committed
340
341
342
343
344
345
346
347
    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
348
        corrections = []
Yan's avatar
Yan committed
349

3Yan's avatar
3Yan committed
350

Yan's avatar
Yan committed
351
352
        with open(filename, 'r') as cfile:
            rawdata = cfile.read().splitlines()
3Yan's avatar
3Yan committed
353
354
        for i in range(len(rawdata[0].split(","))-4):
            corrections.append([])
Yan's avatar
Yan committed
355
356
        for i in range(1, len(rawdata)):
            rawline = rawdata[i].split(",")
357
            # TODO: rawline[4] can be -1 - decide if accept this behaviour
Yan's avatar
Yan committed
358
359
360
361
            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
362
363
364
365
366
367
                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
368
                                   states, *corrections)):
Yan's avatar
Yan committed
369
                k.append(rawline[j])
3Yan's avatar
3Yan committed
370
371
372
        for row in reversed(range(drls['pt'].rowCount())):
            drls['dt'].removeRow(row)
            drls['pt'].removeRow(row)
373
        # first populate only the parent table
Yan's avatar
Yan committed
374
        for i in range(len(names)):
3Yan's avatar
3Yan committed
375
376
377
378
            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])
379
        # and after that the daughter table
Yan's avatar
Yan committed
380
        for i in range(len(names)):
3Yan's avatar
3Yan committed
381
            for j in range(int((len(rawline)-4)/2)):
3Yan's avatar
3Yan committed
382
                drls['dt'].cellWidget(i, 1+j*2).setCurrentIndex(
3Yan's avatar
3Yan committed
383
384
                    int(corrections[0+j*2][i]))
                drls['dt'].item(i, 2+j*2).setText(corrections[1+j*2][i])
3Yan's avatar
3Yan committed
385
            drls['dt'].cellWidget(i, 0).setCheckState(int(states[i]))
Yan's avatar
Yan committed
386
387


3Yan's avatar
3Yan committed
388
def save_drlconfig(drls, parent, exp_f_name=None):
Yan's avatar
Yan committed
389
    """safe DRL table layout so it can be summoned when needed"""
390
391
392
393
    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
394
    if exp_f_name is not '':
3Yan's avatar
3Yan committed
395
396
397
398
399
        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
400
401
        expf = open(exp_f_name, 'w')
        expf.write("#ion_name, start m/z, end m/z, visible,"
3Yan's avatar
3Yan committed
402
                   "{}\n".format(cortext))
3Yan's avatar
3Yan committed
403
        for row in range(drls['pt'].rowCount()):
Yan's avatar
Yan committed
404
405
            vals = []
            for i in range(3):
3Yan's avatar
3Yan committed
406
407
                vals.append(drls['pt'].item(row, i).text())
            vals.append(drls['dt'].cellWidget(row, 0).checkState())
3Yan's avatar
3Yan committed
408
409
410
            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
411
412
413
            expf.write("{}\n".format((",".join(map(str, vals)))))
        expf.close()

Yan's avatar
Yan committed
414

3Yan's avatar
3Yan committed
415
def export_drlspectrum(parent, fn, ds, drls):
Yan's avatar
Yan committed
416
417
    if fn[0] is None:
        QtWidgets.QMessageBox.warning(
418
            None, "Export DRL dataset",
Yan's avatar
Yan committed
419
420
            "Nothing to export, cancelling request")
        return
3Yan's avatar
3Yan committed
421
422
423
    names, times, intensities = get_daughterset(ds, drls)
    subset = np.where(times > 0)[0]
    times = times[subset]
Yan's avatar
Yan committed
424
    intensities = list(map(lambda x: x[subset], intensities))
3Yan's avatar
3Yan committed
425
426

    pnames, ptimes, pintensities = get_parentset(ds, drls)
427
428
429
430
431
432
433
434
435
436
437
438
439
440
    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
441
442
443
444
445
446
447
448
449
450
    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
451
452
453
454
455
456
457
    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
458
            dataset = list()
459
460
461
            dataset.append(times[j])
            for intensity in table[1]:
                dataset.append(intensity[j])
Yan's avatar
Yan committed
462
463
            expf.write("{}\n".format((",".join(map(str, dataset)))))
        expf.close()
3Yan's avatar
3Yan committed
464
    save_drlconfig(drls, parent, exp_f_name[2])
Yan's avatar
Yan committed
465

Yan's avatar
Yan committed
466

3Yan's avatar
3Yan committed
467
def print_graph(labels, ds, drls):
Yan's avatar
Yan committed
468
    printfig = Figure(figsize=(5, 2), dpi=100)
Yan's avatar
Yan committed
469
470
471
    printplot = printfig.add_subplot(111)
    printcanvas = FigureCanvas(printfig)
    gt.pop_plot(printplot, labels)
3Yan's avatar
3Yan committed
472
    update_drlspectrum(ds, drls, printplot)
Yan's avatar
Yan committed
473
    widget = QtWidgets.QDialog(None, windowTitle='Print preview')
Yan's avatar
Yan committed
474
475
    layout = QtWidgets.QVBoxLayout(widget)
    layout.addWidget(printcanvas)
Yan's avatar
Yan committed
476
    widget.resize(600, 400)
Yan's avatar
Yan committed
477
478
479
480
481
482
483
    widget.show()
    dialog = QtPrintSupport.QPrintDialog()
    if dialog.exec_() == QtWidgets.QDialog.Accepted:
        printcanvas.render(dialog.printer())
    widget.close()


3Yan's avatar
3Yan committed
484
def clip_range(drls):
485
    activeObject = QtWidgets.QApplication.focusWidget()
3Yan's avatar
3Yan committed
486
    if activeObject in (drls['pt'], drls['dt']):
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
        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
512
def paste_clip(ds, drls, drlspectrum):
513
    activeObject = QtWidgets.QApplication.focusWidget()
3Yan's avatar
3Yan committed
514
    if activeObject in (drls['pt'], drls['dt'])\
515
516
517
518
519
520
521
522
523
524
525
526
527
528
        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
529
                if table == drls['pt'] and j < 3:
530
                    if i >= (table.rowCount()):
3Yan's avatar
3Yan committed
531
                        add_line(ds, drls, drlspectrum)
532
                    table.item(i, j).setText(col)
3Yan's avatar
3Yan committed
533
                if table == drls['dt'] and j == 2\
534
535
536
537
                     and i < table.rowCount():
                     table.item(i,j).setText(col)


3Yan's avatar
3Yan committed
538
def key_pressed(event, ds, drls, drlspectrum):
539
    if event.key() == QtCore.Qt.Key_Delete:
540
        rows = reversed(list(map(lambda x: x.row(),
3Yan's avatar
3Yan committed
541
542
            drls['pt'].selectionModel().selectedRows())))
        remove_rows(ds, drls, drlspectrum, rows)
Yan's avatar
Yan committed
543
    if event.key() == QtCore.Qt.Key_F5:
3Yan's avatar
3Yan committed
544
545
546
        update_drlspectrum(ds, drls, drlspectrum)
        for row in range(drls['pt'].rowCount()):
            update_profile(drls['pt'], row, ds)
547
548
    if event.key() == QtCore.Qt.Key_C\
        and event.modifiers().__int__() == QtCore.Qt.ControlModifier:
3Yan's avatar
3Yan committed
549
        clip_range(drls)
550
551
    if event.key() == QtCore.Qt.Key_V\
        and event.modifiers().__int__() == QtCore.Qt.ControlModifier:
3Yan's avatar
3Yan committed
552
        paste_clip(ds, drls, drlspectrum)
553

554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
def select_all_btn_up(ds, drls, drlspectrum, state=None):
    logger.info('''Change of the select-all button detected''')
    if state == None:
        btns = []
        for row in range(drls['dt'].rowCount()):
            btns.append(drls['dt'].cellWidget(row, 0).checkState())
        if any(btns):
            drls['checkAll'].setCheckState(1)
        elif all(btns):
            drls['checkAll'].setCheckState(2)
        else:
            drls['checkAll'].setCheckState(0)
    if state in (0, 2):
        for row in range(drls['dt'].rowCount()):
            drls['dt'].cellWidget(row, 0).blockSignals(True)
            drls['dt'].cellWidget(row, 0).setCheckState(state)
            drls['dt'].cellWidget(row, 0).blockSignals(False)
        update_drlspectrum(ds, drls, drlspectrum)

573

Yan's avatar
Yan committed
574
def main_window(parent, ds, filename, cache):
575
    """constructs a dialog window"""
3Yan's avatar
3Yan committed
576
577
    def saveonclose(widget, event, buffer, drls, canvas):
        buffer[0], buffer[1] = drls, canvas
Yan's avatar
Yan committed
578
        QtWidgets.QMainWindow.closeEvent(widget, event)
Yan's avatar
Yan committed
579

3Yan's avatar
3Yan committed
580
581
    # pt = parenttable
    # dt = daughtertable
582
583
    drls = dict(pt=None, dt=None, tshift=None, cors=3, rel=None,
                checkAll=None)
3Yan's avatar
3Yan committed
584

Yan's avatar
Yan committed
585
    window = QtWidgets.QMainWindow(
Yan's avatar
Yan committed
586
        parent, windowTitle='Delayed reactant labelling')
Yan's avatar
Yan committed
587
588
    main_widget = QtWidgets.QWidget(window)
    window.setCentralWidget(main_widget)
Yan's avatar
Yan committed
589

Yan's avatar
Yan committed
590
    window.closeEvent = lambda event: saveonclose(
3Yan's avatar
3Yan committed
591
        window, event, cache, drls, graph_canvas)
Yan's avatar
Yan committed
592

Yan's avatar
Yan committed
593
594
    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
595
596
597
    graph_canvas = FigureCanvas(dial_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
Yan's avatar
Yan committed
598
    graphlabels = dict(x=[0], y=[0], line=None, name="",
Yan's avatar
Yan committed
599
600
                       xlabel="time(min)",
                       ylabel="relative intensity")
Yan's avatar
Yan committed
601
602
603
604
    gt.pan_factory(chromplot)
    gt.zoom_factory(chromplot, 1.15)
    gt.pop_plot(chromplot, graphlabels)

3Yan's avatar
3Yan committed
605
606
607
608
    time_title = QtWidgets.QLabel("Time shift (min):")
    drls['tshift'] = QtWidgets.QDoubleSpinBox(
            minimum=-100, maximum=1440, decimals=3)

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

611
612
    drls['checkAll'] = QtWidgets.QCheckBox("Select all")

613
614
615
    drl_load = QtWidgets.QPushButton("&Load")
    drl_save = QtWidgets.QPushButton("&Save")
    drl_export = QtWidgets.QPushButton("&Export")
Yan's avatar
Yan committed
616
    drl_print = QtWidgets.QPushButton("&Print")
617
    close = QtWidgets.QPushButton("&Close")
Yan's avatar
Yan committed
618
    close.clicked.connect(window.close)
619

Yan's avatar
Yan committed
620
621
622
    btn_add = QtWidgets.QPushButton("&Add")
    btn_rem = QtWidgets.QPushButton("Remove")

3Yan's avatar
3Yan committed
623
    if cache == [None, None]:
3Yan's avatar
3Yan committed
624
625
626
627
628
        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
629
630
        drls['pt'] = iontable(["Name", "start (m/z)", "end (m/z)",
                               "profile"])
3Yan's avatar
3Yan committed
631
632
633
634
        #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
635
        add_line(ds, drls, chromplot)
Yan's avatar
Yan committed
636
    else:
3Yan's avatar
3Yan committed
637
638
        drls = cache[0]
        graph_canvas = cache[1]
639

640
    window.keyPressEvent = lambda event: key_pressed(
3Yan's avatar
3Yan committed
641
        event, ds, drls, chromplot)
642

643
    btn_add.clicked.connect(lambda: add_line(
3Yan's avatar
3Yan committed
644
        ds, drls, chromplot))
645
    btn_rem.clicked.connect(lambda: remove_rows(
3Yan's avatar
3Yan committed
646
        ds, drls, chromplot))
Yan's avatar
Yan committed
647
    drl_load.clicked.connect(lambda: load_drltables(
3Yan's avatar
3Yan committed
648
        main_widget, ds, drls, chromplot))
Yan's avatar
Yan committed
649
    drl_save.clicked.connect(lambda: save_drlconfig(
3Yan's avatar
3Yan committed
650
        drls, main_widget))
Yan's avatar
Yan committed
651
    drl_print.clicked.connect(lambda: print_graph(
3Yan's avatar
3Yan committed
652
        graphlabels, ds, drls))
Yan's avatar
Yan committed
653
    drl_export.clicked.connect(lambda: export_drlspectrum(
3Yan's avatar
3Yan committed
654
655
656
657
        main_widget, filename, ds, drls))

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

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

3Yan's avatar
3Yan committed
662
663
    drls['tshift'].valueChanged.connect(lambda: update_drlspectrum(
        ds, drls, chromplot))
664

3Yan's avatar
3Yan committed
665
666
667
    drls['rel'].stateChanged.connect(lambda: update_drlspectrum(
        ds, drls, chromplot))

668
669
670
    drls['checkAll'].stateChanged.connect(lambda state:
        select_all_btn_up(ds, drls, chromplot, state))

Yan's avatar
Yan committed
671
    main_layout = QtWidgets.QVBoxLayout(main_widget)
Yan's avatar
Yan committed
672
    sub_layout = QtWidgets.QHBoxLayout()
3Yan's avatar
3Yan committed
673
674
    graph_layout = QtWidgets.QVBoxLayout()
    graphparams_layout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
675
    tablelayout = QtWidgets.QVBoxLayout()
Yan's avatar
Yan committed
676
    pt_butlayout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
677
    main_butlayout = QtWidgets.QHBoxLayout()
Yan's avatar
Yan committed
678

Yan's avatar
Yan committed
679
680
681
682
    pt_butlayout.addWidget(btn_add)
    pt_butlayout.addWidget(btn_rem)
    pt_butlayout.addStretch(0)

683
684
    main_layout.addLayout(sub_layout)
    main_layout.addWidget(HBar())
Yan's avatar
Yan committed
685
    main_layout.addLayout(main_butlayout)
686

Yan's avatar
Yan committed
687
688
    main_butlayout.addWidget(drl_load)
    main_butlayout.addWidget(drl_save)
Yan's avatar
Yan committed
689
    main_butlayout.addWidget(drl_print)
Yan's avatar
Yan committed
690
691
    main_butlayout.addStretch(1)
    main_butlayout.addWidget(drl_export)
692
    main_butlayout.addWidget(close)
Yan's avatar
Yan committed
693

3Yan's avatar
3Yan committed
694
    sub_layout.addLayout(graph_layout, stretch=1)
Yan's avatar
Yan committed
695
    sub_layout.addLayout(tablelayout)
3Yan's avatar
3Yan committed
696
697
698
699
700
    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
701
702
    graphparams_layout.addWidget(drls['rel'])
    graphparams_layout.addStretch(1)
703

Yan's avatar
Yan committed
704
    tablelayout.addWidget(QtWidgets.QLabel("Raw ions table:"))
3Yan's avatar
3Yan committed
705
    tablelayout.addWidget(drls['pt'])
Yan's avatar
Yan committed
706
707
    tablelayout.addLayout(pt_butlayout)
    tablelayout.addWidget(QtWidgets.QLabel("Corrected ions table:"))
708
    tablelayout.addWidget(drls['checkAll'])
3Yan's avatar
3Yan committed
709
    tablelayout.addWidget(drls['dt'])
710

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