drltools.py 29.6 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
23
class StretchWidget(QtWidgets.QWidget):
    """horizontal stretch class"""
Yan's avatar
Yan committed
24
    def __init__(self):
Yan's avatar
Yan committed
25
        super(StretchWidget, self).__init__()
Yan's avatar
Yan committed
26
        self._main = QtWidgets.QWidget()
Yan's avatar
Yan committed
27
28
        self.setSizePolicy(QtWidgets.QSizePolicy.Expanding
                          ,QtWidgets.QSizePolicy.Preferred)
Yan's avatar
Yan committed
29
30


Yan's avatar
Yan committed
31
def floatize(table, row, column, nonneg=True):
32
33
34
35
    """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
36
37
    if nonneg == True:
        validator.setBottom(0)
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


46
47
48
49
50
51
52
def get_massargs(pt, row, ds):
    startm = floatize(pt, row, 1) - (floatize(pt, row, 2) / 2)
    endm = floatize(pt, row, 1) + (floatize(pt, row, 2) / 2)
    massargs = dt.argsubselect(ds['masses'], startm, endm)
    return massargs


53
def update_profile(pt, row, dataset):
Yan's avatar
Yan committed
54
    """parent table profile spectrum updating procedure"""
Yan's avatar
Yan committed
55
    # Dont do anything to graph when the spectrum is not populated
Yan's avatar
Yan committed
56
    logger.debug("updating parent table row {} profile".format(row))
Yan's avatar
Yan committed
57
    if isinstance(dataset['masses'], type(None)):
58
59
        return

60
    spectrum = pt.cellWidget(row, 3).figure.get_axes()[0]
Yan's avatar
Yan committed
61
    masses = dataset['masses']
62
    massargs = get_massargs(pt, row, dataset)
63
    yshape = np.mean(dataset['matrix'], axis=0)
Yan's avatar
Yan committed
64
    spectrum.clear()
65
66
67
    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
68
69
70
    spectrum.set_xlim(masses[massargs[0]]-xex,
                      masses[massargs[-1]]+xex)
    ymax = max(yshape[massargs])
71
72
73
    spectrum.set_ylim(ymax*-0.1, ymax*1.2)
    spectrum.figure.canvas.draw()

Yan's avatar
Yan committed
74

3Yan's avatar
3Yan committed
75
def get_intensity(row, ds, drls):
76
    massargs = get_massargs(drls['pt'], row, ds)
Yan's avatar
Yan committed
77
78
79
80
    #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
81
82
83
    return intensity


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


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


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

3Yan's avatar
3Yan committed
141
    names, times, intensities = get_daughterset(ds, drls)
Yan's avatar
Yan committed
142
143
    for i in range(len(drlspectrum.lines)):
        drlspectrum.lines[0].remove()
144

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

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

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

Yan's avatar
Yan committed
175

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


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

205

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

214

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

Yan's avatar
Yan committed
223

3Yan's avatar
3Yan committed
224
def corr_changed(correction, ds, drls, drlspectrum):
225
    """routine called by change of correction for ion"""
Yan's avatar
Yan committed
226
    logger.info('''Change of the "correct to" detected''')
3Yan's avatar
3Yan committed
227
228
229
230
    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
Yan's avatar
Yan committed
231
232
233
                logger.debug('''Change of the "correct to" on '''
                             '''row {}, column {}'''.format(
                                 row + 1, column + 1))
3Yan's avatar
3Yan committed
234
    if (drls['dt'].cellWidget(row, 0).checkState() == 2
3Yan's avatar
3Yan committed
235
       and floatize(drls['dt'], row, column+1, False) != 0):
3Yan's avatar
3Yan committed
236
        update_drlspectrum(ds, drls, drlspectrum)
237
238


Yan's avatar
Yan committed
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
def corcount_changed(ds, drls, drlspectrum):
    """routine called by change of the correction factors count"""
    logger.info('''change in the correction count detected''')
    diff = int(drls['cors'].value() - ((drls['dt'].columnCount() - 1) / 2))
    if diff == 0:
        return
    elif diff > 0:
        drls['dt'].setColumnCount(1 + (drls['cors'].value() * 2))
        newcors = []
        for col in range(drls['dt'].columnCount() - (diff * 2),
                       drls['dt'].columnCount(), 2):
            for row in range(drls['dt'].rowCount()):
                    drls['dt'].setCellWidget(
                        row, col, QtWidgets.QComboBox())
                    drls['dt'].cellWidget(row, col).setFrame(False)
                    drls['dt'].setItem(
                        row, col+1, QtWidgets.QTableWidgetItem())
                    newcors.append(drls['dt'].cellWidget(row, col))
        list(map(lambda x: x.currentIndexChanged.connect(lambda:
            corr_changed(x, ds, drls, drlspectrum)), newcors))
        update_corrfors(drls)
        dcolums = ["Name"]
        for i in range(drls['cors'].value()):
            dcolums.append("corrected for ({})".format(i+1))
            dcolums.append("factor ({})".format(i+1))
        drls['dt'].setHorizontalHeaderLabels(dcolums)
    else:
        drls['dt'].setColumnCount(1 + (drls['cors'].value() * 2))
        update_drlspectrum(ds, drls, drlspectrum)


3Yan's avatar
3Yan committed
270
def remove_rows(ds, drls, drlspectrum, rows=None):
3Yan's avatar
3Yan committed
271
    logger.info("remowing rows")
272
273
    if rows == None:
        rows = reversed(list(set(
3Yan's avatar
3Yan committed
274
            map(lambda x: x.row(), drls['pt'].selectedIndexes()))))
275
    cors = []
276
    for row in rows:
3Yan's avatar
3Yan committed
277
278
279
280
        drls['dt'].cellWidget(row,0).setCheckState(0)
        drls['dt'].removeRow(row)
        drls['pt'].removeRow(row)
        for i in range(drls['dt'].rowCount()):
Yan's avatar
Yan committed
281
            for cornum in range(drls['cors'].value()):
3Yan's avatar
3Yan committed
282
                corfor = drls['dt'].cellWidget(i, 1+cornum*2)
3Yan's avatar
3Yan committed
283
                cors.append(corfor)
3Yan's avatar
3Yan committed
284
285
286
287
288
289
290
                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
291
                    corr_changed(corfor, ds, drls, drlspectrum)
3Yan's avatar
3Yan committed
292
293
294
295
                elif index > row+1:
                    corfor.setCurrentIndex(index-1)
                else:
                    corfor.setCurrentIndex(index)
Yan's avatar
Yan committed
296
297
        list(map(lambda x: x.currentIndexChanged.connect(lambda:
            corr_changed(x, ds, drls, drlspectrum)), cors))
298
299


3Yan's avatar
3Yan committed
300
def add_line(ds, drls, drlspectrum):
301
    """add parent ion to the table"""
Yan's avatar
Yan committed
302
    logger.debug("adding line")
3Yan's avatar
3Yan committed
303
    newrow = drls['pt'].rowCount()
304

3Yan's avatar
3Yan committed
305
306
    drls['pt'].blockSignals(True)
    drls['dt'].blockSignals(True)
307

3Yan's avatar
3Yan committed
308
    drls['pt'].setRowCount(newrow + 1)
309
    for i in range(3):
3Yan's avatar
3Yan committed
310
        drls['pt'].setItem(newrow, i, QtWidgets.QTableWidgetItem())
311
        if newrow is not 0:
3Yan's avatar
3Yan committed
312
313
            drls['pt'].item(newrow, i).setText(str(floatize(
                    drls['pt'], newrow-1, i)+1))
314

315
    ion_graph = Figure(figsize=(3, 1.5), dpi=100, facecolor="None")
316
317
    ion_graph.add_subplot(111, facecolor=(1, 1, 1, 0.8),
                          position=(-0.01, -0.01, 1.02, 1.02))
318
319
320
    graph_canvas = FigureCanvas(ion_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
3Yan's avatar
3Yan committed
321
    drls['pt'].setCellWidget(newrow, 3, graph_canvas)
322

3Yan's avatar
3Yan committed
323
    drls['dt'].setRowCount(newrow + 1)
Yan's avatar
Yan committed
324
    checkbox = QtWidgets.QCheckBox()
3Yan's avatar
3Yan committed
325
    checkbox.setFocusProxy(drls['dt'])
326
327
    dname = QtWidgets.QTableWidgetItem()
    dname.setFlags(dname.flags() & ~QtCore.Qt.ItemIsEditable)
Yan's avatar
Yan committed
328
    dname.setTextAlignment(QtCore.Qt.AlignRight)
3Yan's avatar
3Yan committed
329
330
    drls['dt'].setItem(newrow, 0, dname)
    drls['dt'].setCellWidget(newrow, 0, checkbox)
3Yan's avatar
3Yan committed
331

Yan's avatar
Yan committed
332
    for i in range(drls['cors'].value()):
3Yan's avatar
3Yan committed
333
334
335
336
        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())
337

3Yan's avatar
3Yan committed
338
339
    drls['pt'].blockSignals(False)
    drls['dt'].blockSignals(False)
340

3Yan's avatar
3Yan committed
341
    cors = list(map(lambda x: drls['dt'].cellWidget(newrow, 1+x*2),
Yan's avatar
Yan committed
342
                    range(drls['cors'].value())))
3Yan's avatar
3Yan committed
343
344
345
    list(map(lambda x: x.currentIndexChanged.connect(lambda:
        corr_changed(x, ds, drls, drlspectrum)), cors))

3Yan's avatar
3Yan committed
346
    ptable_changed(newrow, 1, ds, drls, drlspectrum)
347
    select_all_btn_up(ds, drls, drlspectrum)
348

Yan's avatar
Yan committed
349
    checkbox.stateChanged.connect(lambda: update_drlspectrum(
3Yan's avatar
3Yan committed
350
        ds, drls, drlspectrum))
351
352
    checkbox.stateChanged.connect(lambda: select_all_btn_up(
        ds, drls, drlspectrum))
353
354


Yan's avatar
Yan committed
355
def iontable(labels):
356
357
    """creates a table for ions"""
    table = QtWidgets.QTableWidget(columnCount=len(labels))
358
    table.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
359
360
                        QtWidgets.QSizePolicy.Expanding)
    table.setHorizontalHeaderLabels(labels)
361
362
363
364
365
    table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)

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

368
    return table
369
370


3Yan's avatar
3Yan committed
371
def load_drltables(parent, dataset, drls, drlspectrum):
Yan's avatar
Yan committed
372
373
374
375
376
    filename = QtWidgets.QFileDialog.getOpenFileName(
            caption="Load DRL config tables",
            filter="comma-separated values (*.csv)")[0]
    if filename is not '':
        names = []
377
378
        masses = []
        peak_widths = []
Yan's avatar
Yan committed
379
        states = []
3Yan's avatar
3Yan committed
380
        corrections = []
Yan's avatar
Yan committed
381

3Yan's avatar
3Yan committed
382

Yan's avatar
Yan committed
383
384
        with open(filename, 'r') as cfile:
            rawdata = cfile.read().splitlines()
3Yan's avatar
3Yan committed
385
386
        for i in range(len(rawdata[0].split(","))-4):
            corrections.append([])
Yan's avatar
Yan committed
387
388
        for i in range(1, len(rawdata)):
            rawline = rawdata[i].split(",")
Yan's avatar
Yan committed
389
390
391
392
            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
393
394
395
396
397
                QtWidgets.QMessageBox.warning(
                    parent, "Load DRL config tables",
                    "Config file corrupted on line {},"
                    " cancelling request".format(i+1))
                return
398
            for j, k in enumerate((names, masses, peak_widths,
3Yan's avatar
3Yan committed
399
                                   states, *corrections)):
Yan's avatar
Yan committed
400
                k.append(rawline[j])
3Yan's avatar
3Yan committed
401
402
403
        for row in reversed(range(drls['pt'].rowCount())):
            drls['dt'].removeRow(row)
            drls['pt'].removeRow(row)
404
        # first populate only the parent table
Yan's avatar
Yan committed
405
        for i in range(len(names)):
3Yan's avatar
3Yan committed
406
407
            add_line(dataset, drls, drlspectrum)
            drls['pt'].item(i, 0).setText(names[i])
408
409
            drls['pt'].item(i, 1).setText(masses[i])
            drls['pt'].item(i, 2).setText(peak_widths[i])
410
        # and after that the daughter table
Yan's avatar
Yan committed
411
        drls['cors'].setValue(int(1 + (len(names) / 2)))
Yan's avatar
Yan committed
412
        for i in range(len(names)):
3Yan's avatar
3Yan committed
413
            for j in range(int((len(rawline)-4)/2)):
3Yan's avatar
3Yan committed
414
                drls['dt'].cellWidget(i, 1+j*2).setCurrentIndex(
3Yan's avatar
3Yan committed
415
416
                    int(corrections[0+j*2][i]))
                drls['dt'].item(i, 2+j*2).setText(corrections[1+j*2][i])
3Yan's avatar
3Yan committed
417
            drls['dt'].cellWidget(i, 0).setCheckState(int(states[i]))
Yan's avatar
Yan committed
418
419


3Yan's avatar
3Yan committed
420
def save_drlconfig(drls, parent, exp_f_name=None):
Yan's avatar
Yan committed
421
    """safe DRL table layout so it can be summoned when needed"""
422
423
424
425
    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
426
    if exp_f_name is not '':
3Yan's avatar
3Yan committed
427
        corlist = []
Yan's avatar
Yan committed
428
        for i in range(drls['cors'].value()):
3Yan's avatar
3Yan committed
429
430
431
            corlist.append("corrected_to_{}, factor_{} ".format(
                i+1, i+1))
        cortext = ", ".join(corlist)
Yan's avatar
Yan committed
432
        expf = open(exp_f_name, 'w')
433
        expf.write("#ion_name, m/z, peak_width, visible,"
3Yan's avatar
3Yan committed
434
                   "{}\n".format(cortext))
3Yan's avatar
3Yan committed
435
        for row in range(drls['pt'].rowCount()):
Yan's avatar
Yan committed
436
437
            vals = []
            for i in range(3):
3Yan's avatar
3Yan committed
438
439
                vals.append(drls['pt'].item(row, i).text())
            vals.append(drls['dt'].cellWidget(row, 0).checkState())
Yan's avatar
Yan committed
440
            for i in range(drls['cors'].value()):
3Yan's avatar
3Yan committed
441
442
                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
443
444
445
            expf.write("{}\n".format((",".join(map(str, vals)))))
        expf.close()

Yan's avatar
Yan committed
446

3Yan's avatar
3Yan committed
447
def export_drlspectrum(parent, fn, ds, drls):
Yan's avatar
Yan committed
448
449
    if fn[0] is None:
        QtWidgets.QMessageBox.warning(
Yan's avatar
Yan committed
450
451
            None, "Export DRL dat aset",
            "No file opened. Nothing to export, canceling request")
Yan's avatar
Yan committed
452
        return
3Yan's avatar
3Yan committed
453
454
455
    names, times, intensities = get_daughterset(ds, drls)
    subset = np.where(times > 0)[0]
    times = times[subset]
Yan's avatar
Yan committed
456
    intensities = list(map(lambda x: x[subset], intensities))
3Yan's avatar
3Yan committed
457
458

    pnames, ptimes, pintensities = get_parentset(ds, drls)
459
460
    if names == []:
        QtWidgets.QMessageBox.warning(
Yan's avatar
Yan committed
461
462
463
            None, "Export DRL data set",
            "No rows in the Corrected ions table selected. "
            "Nothing to export, canceling request")
464
465
466
467
        return
    fname = QtWidgets.QFileDialog.getSaveFileName(
            None,"Export DRL data",
        options=(QtWidgets.QFileDialog.DontConfirmOverwrite |
Yan's avatar
Yan committed
468
469
        QtWidgets.QFileDialog.HideNameFilterDetails),
        directory=os.path.basename(fn[0][:-4]))[0]
470
471
472
473
474
    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
475
476
477
478
479
480
481
482
483
484
    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
485
486
487
488
489
490
    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]))))
491
        expf.write("timeshift = {}".format(drls['tshift'].value()))
492
        for j in range(len(times)):
Yan's avatar
Yan committed
493
            dataset = list()
494
495
496
            dataset.append(times[j])
            for intensity in table[1]:
                dataset.append(intensity[j])
Yan's avatar
Yan committed
497
498
            expf.write("{}\n".format((",".join(map(str, dataset)))))
        expf.close()
3Yan's avatar
3Yan committed
499
    save_drlconfig(drls, parent, exp_f_name[2])
Yan's avatar
Yan committed
500

Yan's avatar
Yan committed
501

3Yan's avatar
3Yan committed
502
def print_graph(labels, ds, drls):
Yan's avatar
Yan committed
503
    printfig = Figure(figsize=(5, 2), dpi=100)
Yan's avatar
Yan committed
504
505
506
    printplot = printfig.add_subplot(111)
    printcanvas = FigureCanvas(printfig)
    gt.pop_plot(printplot, labels)
3Yan's avatar
3Yan committed
507
    update_drlspectrum(ds, drls, printplot)
Yan's avatar
Yan committed
508
    widget = QtWidgets.QDialog(None, windowTitle='Print preview')
Yan's avatar
Yan committed
509
510
    layout = QtWidgets.QVBoxLayout(widget)
    layout.addWidget(printcanvas)
Yan's avatar
Yan committed
511
    widget.resize(600, 400)
Yan's avatar
Yan committed
512
513
514
515
516
517
518
    widget.show()
    dialog = QtPrintSupport.QPrintDialog()
    if dialog.exec_() == QtWidgets.QDialog.Accepted:
        printcanvas.render(dialog.printer())
    widget.close()


3Yan's avatar
3Yan committed
519
def clip_range(drls):
520
    activeObject = QtWidgets.QApplication.focusWidget()
3Yan's avatar
3Yan committed
521
    if activeObject in (drls['pt'], drls['dt']):
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
        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
547
def paste_clip(ds, drls, drlspectrum):
548
    activeObject = QtWidgets.QApplication.focusWidget()
3Yan's avatar
3Yan committed
549
    if activeObject in (drls['pt'], drls['dt'])\
550
551
552
553
554
555
556
557
558
559
560
561
562
563
        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
564
                if table == drls['pt'] and j < 3:
565
                    if i >= (table.rowCount()):
3Yan's avatar
3Yan committed
566
                        add_line(ds, drls, drlspectrum)
567
                    table.item(i, j).setText(col)
568
                if table == drls['dt'] and j != 0 and j % 2 == 0\
569
570
571
572
                     and i < table.rowCount():
                     table.item(i,j).setText(col)


3Yan's avatar
3Yan committed
573
def key_pressed(event, ds, drls, drlspectrum):
574
    if event.key() == QtCore.Qt.Key_Delete:
575
        rows = reversed(list(map(lambda x: x.row(),
3Yan's avatar
3Yan committed
576
577
            drls['pt'].selectionModel().selectedRows())))
        remove_rows(ds, drls, drlspectrum, rows)
Yan's avatar
Yan committed
578
    if event.key() == QtCore.Qt.Key_F5:
3Yan's avatar
3Yan committed
579
580
581
        update_drlspectrum(ds, drls, drlspectrum)
        for row in range(drls['pt'].rowCount()):
            update_profile(drls['pt'], row, ds)
582
583
    if event.key() == QtCore.Qt.Key_C\
        and event.modifiers().__int__() == QtCore.Qt.ControlModifier:
3Yan's avatar
3Yan committed
584
        clip_range(drls)
585
586
    if event.key() == QtCore.Qt.Key_V\
        and event.modifiers().__int__() == QtCore.Qt.ControlModifier:
3Yan's avatar
3Yan committed
587
        paste_clip(ds, drls, drlspectrum)
588

Yan's avatar
Yan committed
589

590
591
def select_all_btn_up(ds, drls, drlspectrum, state=None):
    logger.info('''Change of the select-all button detected''')
592
593
594
595
596
597
598
599
600
601
    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)
    elif state == 1:
        drls['checkAll'].setCheckState(2)
    else:
        drls['checkAll'].blockSignals(True)
602
603
604
        btns = []
        for row in range(drls['dt'].rowCount()):
            btns.append(drls['dt'].cellWidget(row, 0).checkState())
605
        if all(btns):
606
            drls['checkAll'].setCheckState(2)
607
608
        elif any(btns):
            drls['checkAll'].setCheckState(1)
609
610
        else:
            drls['checkAll'].setCheckState(0)
611
        drls['checkAll'].blockSignals(False)
612

613

Yan's avatar
Yan committed
614
def main_window(parent, ds, filename, cache):
615
    """constructs a dialog window"""
3Yan's avatar
3Yan committed
616
617
    def saveonclose(widget, event, buffer, drls, canvas):
        buffer[0], buffer[1] = drls, canvas
Yan's avatar
Yan committed
618
        QtWidgets.QMainWindow.closeEvent(widget, event)
Yan's avatar
Yan committed
619

3Yan's avatar
3Yan committed
620
621
    # pt = parenttable
    # dt = daughtertable
Yan's avatar
Yan committed
622
    drls = dict(pt=None, dt=None, tshift=None, cors=None, rel=None,
623
                checkAll=None)
3Yan's avatar
3Yan committed
624

Yan's avatar
Yan committed
625
    window = QtWidgets.QMainWindow(
Yan's avatar
Yan committed
626
        parent, windowTitle='Delayed reactant labeling')
Yan's avatar
Yan committed
627
628
    main_widget = QtWidgets.QWidget(window)
    window.setCentralWidget(main_widget)
Yan's avatar
Yan committed
629

Yan's avatar
Yan committed
630
    window.closeEvent = lambda event: saveonclose(
3Yan's avatar
3Yan committed
631
        window, event, cache, drls, graph_canvas)
Yan's avatar
Yan committed
632

Yan's avatar
Yan committed
633
634
    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
635
636
637
    graph_canvas = FigureCanvas(dial_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)
Yan's avatar
Yan committed
638
    graphlabels = dict(x=[0], y=[0], line=None, name="",
Yan's avatar
Yan committed
639
640
                       xlabel="time(min)",
                       ylabel="relative intensity")
Yan's avatar
Yan committed
641
642
643
644
    gt.pan_factory(chromplot)
    gt.zoom_factory(chromplot, 1.15)
    gt.pop_plot(chromplot, graphlabels)

3Yan's avatar
3Yan committed
645
646
647
    time_title = QtWidgets.QLabel("Time shift (min):")
    drls['tshift'] = QtWidgets.QDoubleSpinBox(
            minimum=-100, maximum=1440, decimals=3)
3Yan's avatar
3Yan committed
648
    drls['rel'] = QtWidgets.QCheckBox("Steady state approximation")
649
    drls['checkAll'] = QtWidgets.QCheckBox("Select all")
Yan's avatar
Yan committed
650
    drls['cors'] = QtWidgets.QSpinBox(minimum=0)
651

652
653
654
    drl_load = QtWidgets.QPushButton("&Load")
    drl_save = QtWidgets.QPushButton("&Save")
    drl_export = QtWidgets.QPushButton("&Export")
Yan's avatar
Yan committed
655
    drl_print = QtWidgets.QPushButton("&Print")
656
    close = QtWidgets.QPushButton("&Close")
Yan's avatar
Yan committed
657
    close.clicked.connect(window.close)
658

Yan's avatar
Yan committed
659
660
661
    btn_add = QtWidgets.QPushButton("&Add")
    btn_rem = QtWidgets.QPushButton("Remove")

3Yan's avatar
3Yan committed
662
    if cache == [None, None]:
3Yan's avatar
3Yan committed
663
        dcolums = ["Name"]
Yan's avatar
Yan committed
664
665
        drls['cors'].setValue(3)
        for i in range(drls['cors'].value()):
3Yan's avatar
3Yan committed
666
667
668
            dcolums.append("corrected for ({})".format(i+1))
            dcolums.append("factor ({})".format(i+1))
        drls['dt'] = iontable(dcolums)
669
        drls['pt'] = iontable(["Name", "Mass (m/z)", "Peak width",
3Yan's avatar
3Yan committed
670
                               "profile"])
3Yan's avatar
3Yan committed
671
672
673
674
        #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
675
        add_line(ds, drls, chromplot)
Yan's avatar
Yan committed
676
    else:
3Yan's avatar
3Yan committed
677
678
        drls = cache[0]
        graph_canvas = cache[1]
679

680
    window.keyPressEvent = lambda event: key_pressed(
3Yan's avatar
3Yan committed
681
        event, ds, drls, chromplot)
682

683
    btn_add.clicked.connect(lambda: add_line(
3Yan's avatar
3Yan committed
684
        ds, drls, chromplot))
685
    btn_rem.clicked.connect(lambda: remove_rows(
3Yan's avatar
3Yan committed
686
        ds, drls, chromplot))
Yan's avatar
Yan committed
687
    drl_load.clicked.connect(lambda: load_drltables(
3Yan's avatar
3Yan committed
688
        main_widget, ds, drls, chromplot))
Yan's avatar
Yan committed
689
    drl_save.clicked.connect(lambda: save_drlconfig(
3Yan's avatar
3Yan committed
690
        drls, main_widget))
Yan's avatar
Yan committed
691
    drl_print.clicked.connect(lambda: print_graph(
3Yan's avatar
3Yan committed
692
        graphlabels, ds, drls))
Yan's avatar
Yan committed
693
    drl_export.clicked.connect(lambda: export_drlspectrum(
3Yan's avatar
3Yan committed
694
695
696
697
698
699
700
701
        main_widget, filename, ds, drls))

    drls['pt'].itemChanged.connect(lambda item: ptable_changed(
        item.row(), item.column(), ds, drls, chromplot))
    drls['dt'].itemChanged.connect(lambda item: dtable_changed(
        item.row(), item.column(), ds, drls, chromplot))
    drls['tshift'].valueChanged.connect(lambda: update_drlspectrum(
        ds, drls, chromplot))
Yan's avatar
Yan committed
702
703
    drls['cors'].valueChanged.connect(lambda: corcount_changed(
        ds, drls, chromplot))
3Yan's avatar
3Yan committed
704
705
    drls['rel'].stateChanged.connect(lambda: update_drlspectrum(
        ds, drls, chromplot))
706
707
708
    drls['checkAll'].stateChanged.connect(lambda state:
        select_all_btn_up(ds, drls, chromplot, state))

709
710
711
712
713
714
715
716
717
    actionBar = QtWidgets.QToolBar(window)
    window.addToolBar(QtCore.Qt.BottomToolBarArea, actionBar)
    actionBar.setAllowedAreas(QtCore.Qt.BottomToolBarArea)
    actionBar.setFloatable(False)
    actionBar.setMovable(False)
    actionBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
    actionBar.addWidget(drl_load)
    actionBar.addWidget(drl_save)
    actionBar.addWidget(drl_print)
Yan's avatar
Yan committed
718
    actionBar.addWidget(StretchWidget())
719
720
721
722
723
724
725
    actionBar.addWidget(drl_export)
    actionBar.addWidget(close)

    dtdock = QtWidgets.QDockWidget()
    dtdock.setWidget(QtWidgets.QWidget())
    dtdock_layout = QtWidgets.QVBoxLayout(dtdock.widget())
    dtdock.setWindowTitle("Corrected ions table")
Yan's avatar
Yan committed
726
727
728
729
730
731
732
    dt_butlayout = QtWidgets.QHBoxLayout()
    dt_butlayout.addWidget(drls['checkAll'])
    dt_butlayout.addWidget(StretchWidget())
    dt_butlayout.addWidget(QtWidgets.QLabel("Number of corrections:"))
    dt_butlayout.addWidget(drls['cors'])
    dt_butlayout.addWidget(StretchWidget())
    dtdock_layout.addLayout(dt_butlayout)
733
    dtdock_layout.addWidget(drls['dt'])
Yan's avatar
Yan committed
734
    window.addDockWidget(QtCore.Qt.BottomDockWidgetArea, dtdock)
735
736
737
738
739
740

    ptdock = QtWidgets.QDockWidget()
    ptdock.setWidget(QtWidgets.QWidget())
    ptdock_layout = QtWidgets.QVBoxLayout(ptdock.widget())
    ptdock.setWindowTitle("Raw ions table")
    ptdock_layout.addWidget(drls['pt'])
Yan's avatar
Yan committed
741
742
743
744
    pt_butlayout = QtWidgets.QHBoxLayout()
    pt_butlayout.addWidget(btn_add)
    pt_butlayout.addWidget(btn_rem)
    pt_butlayout.addStretch(0)
745
746
747
748
749
750
751
    ptdock_layout.addLayout(pt_butlayout)
    window.addDockWidget(QtCore.Qt.RightDockWidgetArea, ptdock)

    main_layout = QtWidgets.QVBoxLayout(main_widget)
    graphparams_layout = QtWidgets.QHBoxLayout()
    main_layout.addWidget(graph_canvas, stretch=1)
    main_layout.addLayout(graphparams_layout)
3Yan's avatar
3Yan committed
752
753
754
    graphparams_layout.addWidget(time_title)
    graphparams_layout.addWidget(drls['tshift'])
    graphparams_layout.addStretch(1)
3Yan's avatar
3Yan committed
755
756
    graphparams_layout.addWidget(drls['rel'])
    graphparams_layout.addStretch(1)
757
758


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