drltools.py 25.3 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)


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

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

Yan's avatar
Yan committed
66

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


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


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


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

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

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

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

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

Yan's avatar
Yan committed
168

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


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

198

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

207

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

Yan's avatar
Yan committed
217

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


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


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

3Yan's avatar
3Yan committed
259
260
    drls['pt'].blockSignals(True)
    drls['dt'].blockSignals(True)
261

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

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

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

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

3Yan's avatar
3Yan committed
296
297
    drls['pt'].blockSignals(False)
    drls['dt'].blockSignals(False)
298

3Yan's avatar
3Yan committed
299
    ptable_changed(newrow, 1, ds, drls, drlspectrum)
300

Yan's avatar
Yan committed
301
    checkbox.stateChanged.connect(lambda: update_drlspectrum(
3Yan's avatar
3Yan committed
302
        ds, drls, drlspectrum))
303
304


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

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

318
    return table
319
320


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

3Yan's avatar
3Yan committed
332

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


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

Yan's avatar
Yan committed
396

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

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

Yan's avatar
Yan committed
448

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


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


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


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

3Yan's avatar
3Yan committed
543
544
    # pt = parenttable
    # dt = daughtertable
3Yan's avatar
3Yan committed
545
    drls = dict(pt=None, dt=None, tshift=None, cors=3, rel=None)
3Yan's avatar
3Yan committed
546

Yan's avatar
Yan committed
547
    window = QtWidgets.QMainWindow(
Yan's avatar
Yan committed
548
        parent, windowTitle='Delayed reactant labelling')
Yan's avatar
Yan committed
549
550
    main_widget = QtWidgets.QWidget(window)
    window.setCentralWidget(main_widget)
Yan's avatar
Yan committed
551

Yan's avatar
Yan committed
552
    window.closeEvent = lambda event: saveonclose(
3Yan's avatar
3Yan committed
553
        window, event, cache, drls, graph_canvas)
Yan's avatar
Yan committed
554

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

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

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

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

Yan's avatar
Yan committed
580
581
582
    btn_add = QtWidgets.QPushButton("&Add")
    btn_rem = QtWidgets.QPushButton("Remove")

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

600
    window.keyPressEvent = lambda event: key_pressed(
3Yan's avatar
3Yan committed
601
        event, ds, drls, chromplot)
602

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

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

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

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

3Yan's avatar
3Yan committed
625
626
627
    drls['rel'].stateChanged.connect(lambda: update_drlspectrum(
        ds, drls, chromplot))

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

Yan's avatar
Yan committed
636
637
638
639
    pt_butlayout.addWidget(btn_add)
    pt_butlayout.addWidget(btn_rem)
    pt_butlayout.addStretch(0)

640
641
    main_layout.addLayout(sub_layout)
    main_layout.addWidget(HBar())
Yan's avatar
Yan committed
642
    main_layout.addLayout(main_butlayout)
643

Yan's avatar
Yan committed
644
645
    main_butlayout.addWidget(drl_load)
    main_butlayout.addWidget(drl_save)
Yan's avatar
Yan committed
646
    main_butlayout.addWidget(drl_print)
Yan's avatar
Yan committed
647
648
    main_butlayout.addStretch(1)
    main_butlayout.addWidget(drl_export)
649
    main_butlayout.addWidget(close)
Yan's avatar
Yan committed
650

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

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

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