zcetools.py 7.84 KB
Newer Older
Yan's avatar
Yan committed
1
2
3
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from PyQt5 import QtCore
3Yan's avatar
3Yan committed
4
from PyQt5 import QtGui
Yan's avatar
Yan committed
5
from PyQt5 import QtWidgets
Yan's avatar
Yan committed
6
from PyQt5 import QtPrintSupport
3Yan's avatar
3Yan committed
7
from prasopes.zcetools_help import helpstr
3Yan's avatar
3Yan committed
8
from io import BytesIO
Yan's avatar
Yan committed
9
10
11
12
13
import numpy as np
import prasopes.graphtools as gt
import prasopes.filetools as ft
import os.path
import pkg_resources
14
15
16
17
import logging


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


Yan's avatar
Yan committed
20
def pop_dial(zcespec, gradspect, data_set, coff_d, grad_d,
Yan's avatar
Yan committed
21
             textfield, fn, parent):
22
    logger.debug("populating ZCE dialog")
23
    if fn is None:
Yan's avatar
Yan committed
24
25
        QtWidgets.QMessageBox.warning(
            parent, "ZCE calculation",
Yan's avatar
Yan committed
26
            "No spectrum opened, nothing to display")
Yan's avatar
Yan committed
27
28
29
30
        return
    zcespec.clear()
    gradspect.clear()

3Yan's avatar
3Yan committed
31
32
33
34
35
36
37
    coff_x = data_set[0]['masses'] - 196
    coff_y = np.mean(data_set[0]['matrix'], axis=0)
    grad_x = coff_x
    halfl = int(len(grad_x)/2)
    grad_y = -np.gradient(coff_y)\
            if np.sum(coff_y[:halfl]) > np.sum(coff_y[halfl:])\
            else np.gradient(coff_y)
Yan's avatar
Yan committed
38
39
    gradspect.axhline(0, color="#FF000088", linestyle=":")
    zcespec.axhline(0, color="#0000FF88", linestyle=":")
3Yan's avatar
3Yan committed
40
41
    gt.pop_plot(coff_x, coff_y, zcespec, coff_d)
    gt.pop_plot(grad_x, grad_y, gradspect, grad_d)
Yan's avatar
Yan committed
42
    gradspect.lines[-1].set_color("red")
Yan's avatar
Yan committed
43
44
45
    gradspect.set_ylim(bottom=gradspect.get_ylim()[1] * -0.1)
    zcespec.set_title("COFF", loc="center")

3Yan's avatar
3Yan committed
46
47
48
49
    maxarg = np.argmax(grad_y)
    grad_d['gmax'] = coff_x[maxarg]
    halfmax = np.max(grad_y) / 2
    peakargs = np.where(grad_y > halfmax)[0]
Yan's avatar
Yan committed
50
51
    start = [peakargs[0]-1, peakargs[0]]
    end = [peakargs[-1]+1, peakargs[-1]]
Yan's avatar
Yan committed
52
53
    grad_d['fwhm_y'] = [halfmax, halfmax]
    grad_d['fwhm_x'] = [
3Yan's avatar
3Yan committed
54
55
        np.interp(halfmax, grad_y[start], grad_x[start]),
        np.interp(halfmax, grad_y[end], grad_x[end])]
Yan's avatar
Yan committed
56
57
58
59
60
61
62
63
64
65
    grad_d['fwhm'] = grad_d['fwhm_x'][1] - grad_d['fwhm_x'][0]

    gradspect.plot(grad_d['fwhm_x'], grad_d['fwhm_y'], "#880088")
    textfield.setText(
        "ZCE = {:.2f}\nFWHM = {:.2f}\nCenter(HM) = {:.2f}".format(
            grad_d['gmax'], grad_d['fwhm'],
            np.mean(grad_d['fwhm_x'])))
    gradspect.annotate(' FWHM = {:.2f}'.format(grad_d['fwhm']),
                       xy=(grad_d['fwhm_x'][1], grad_d['fwhm_y'][1]))
    gradspect.annotate('{:.2f}'.format(grad_d['gmax']),
3Yan's avatar
3Yan committed
66
                       xy=(grad_x[maxarg], grad_y[maxarg]))
Yan's avatar
Yan committed
67
68
69
70
71
    zcespec.figure.canvas.draw()


def exp_zce(zce_spec, zcegrad_spec, fn, parent):
    """export the ZCE graph into the .dat file format"""
72
    if fn is None:
Yan's avatar
Yan committed
73
74
75
76
        QtWidgets.QMessageBox.warning(
            parent, "Export ZCE spectrum",
            "Nothing to export, cancelling request")
        return
Yan's avatar
Yan committed
77
78
    exp_f_name = ft.get_save_filename(
        "Export ZCE spectrum", "dat table (*.dat)", "dat", parent)
Yan's avatar
Yan committed
79
80
81
82
83
    if exp_f_name is not '':
        expf = open(exp_f_name, 'w')
        expf.write("mass ion_count ion_count_gradient fwhm_x fwhm_y\n"
                   "m/z\n"
                   "{} zce={} fwhm={} hmcenter={}\n".format(
84
                       os.path.basename(fn), zcegrad_spec['gmax'],
Yan's avatar
Yan committed
85
86
87
88
89
90
91
92
93
94
95
96
97
                       zcegrad_spec['fwhm'],
                       np.mean(zcegrad_spec['fwhm_x'])))
        for i in range(len(zce_spec['x'])):
            fwhm = ["", ""]
            if i <= 1:
                fwhm = [zcegrad_spec['fwhm_x'][i],
                        zcegrad_spec['fwhm_y'][i]]
            expf.write("{} {} {} {} {}\n".format(
                zce_spec['x'][i], zce_spec['y'][i], zcegrad_spec['y'][i],
                fwhm[0], fwhm[1]))
        expf.close()


98
def help_msg(pw):
3Yan's avatar
3Yan committed
99
100
    QtWidgets.QMessageBox.information(
            pw, "TSQ zce tool help", "{}".format(helpstr))
101
102


3Yan's avatar
3Yan committed
103
104
105
def paint_zcegraph(ds, coff, coffgrad, filename):
    paintfig = Figure(figsize=(5, 2), dpi=300, constrained_layout=True)
    printplot = paintfig.add_subplot(111)
Yan's avatar
Yan committed
106
    printplot_overlay = printplot.twinx()
3Yan's avatar
3Yan committed
107
    canvas = FigureCanvas(paintfig)
Yan's avatar
Yan committed
108
109
110
    textfield = QtWidgets.QLabel()
    pop_dial(printplot, printplot_overlay, ds, coff, coffgrad,
             textfield, filename, None)
3Yan's avatar
3Yan committed
111
112
113
114
115
116
117
118
119
    cache_file = BytesIO()
    paintfig.savefig(cache_file)
    cache_file.seek(0)
    image = QtGui.QImage.fromData(cache_file.read())
    return image


def clip_spect_img(ds, coff, coffgrad, filename):
    image = paint_zcegraph(ds, coff, coffgrad, filename)
3Yan's avatar
3Yan committed
120
    QtWidgets.QApplication.clipboard().clear()
Yan's avatar
Yan committed
121
    [QtWidgets.QApplication.clipboard().setImage(image, i) for i in range(2)]
3Yan's avatar
3Yan committed
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145


def print_graph(ds, coff, coffgrad, filename):
    def printimage(printdevice, img):
        printer.setResolution(600)
        painter = QtGui.QPainter(printdevice)
        painter.drawImage(0,0,img)
        painter.end()
    #TODO: substitute the QPrintPreviewDialog with QPrintPreviewWidget
    printPreview = QtPrintSupport.QPrintPreviewDialog()
    printer = printPreview.printer()
    printer.setPageSize(printer.A5)
    printer.setDuplex(printer.DuplexNone)
    image = paint_zcegraph(ds, coff, coffgrad, filename)
    printPreview.paintRequested.connect(lambda:
                                        printimage(printer, image))
    printPreview.exec()


def key_pressed(event, ds, coff, coffgrad, filename):
    print("trigged")
    if event.key() == QtCore.Qt.Key_C:
        if event.modifiers().__int__() == QtCore.Qt.ControlModifier:
            clip_spect_img(ds, coff, coffgrad, filename)
Yan's avatar
Yan committed
146
147


148
def dialog(parent, augCanvas, update_signal):
3Yan's avatar
3Yan committed
149
150
151
152
    coff = dict(name="", xlabel="Voltage (V)", ylabel="ion count")
    coffgrad = dict(c_ymin=-0.1, name="", xlabel="",
                    ylabel="ion count gradient", gmax=None, fwhm_x=None,
                    fwhm_y=None, fwhm=None)
Yan's avatar
Yan committed
153

154
155
156
157
158
159
    def onclose(widget, event, update_fnc):
        logger.debug("ZCE window custom close routine called")
        update_signal.signal.disconnect(update_fnc)
        QtWidgets.QDialog.closeEvent(widget, event)

    def update_fnc():
160
161
        pop_dial(coffspect, coffspect_grad, augCanvas.ds, coff, coffgrad,
                 textfield, augCanvas.filename, parent)
162

Yan's avatar
Yan committed
163
164
    dial_widget = QtWidgets.QDialog(
            parent, windowTitle='TSQ zero collision energy calculator')
165
166
167
    dial_widget.closeEvent = lambda event: onclose(
        dial_widget, event, update_fnc)
    update_signal.signal.connect(update_fnc)
Yan's avatar
Yan committed
168

Yan's avatar
Yan committed
169
    dial_graph = Figure(figsize=(5, 2), dpi=100, facecolor="None")
Yan's avatar
Yan committed
170
171
172
173
174
175
176
177
178
179
180
    coffspect = dial_graph.add_subplot(111, facecolor=(1, 1, 1, 0.8))
    coffspect_grad = coffspect.twinx()
    graph_canvas = FigureCanvas(dial_graph)
    graph_canvas.setStyleSheet("background-color:transparent;")
    graph_canvas.setAutoFillBackground(False)

    gt.zoom_factory(coffspect_grad, 1.15, coffgrad)
    gt.pan_factory(coffspect_grad, coffgrad)

    zce_export = QtWidgets.QPushButton("Export ZCE")
    zce_export.clicked.connect(lambda: exp_zce(
181
        coff, coffgrad, augCanvas.filename, parent))
Yan's avatar
Yan committed
182
183
    zce_print = QtWidgets.QPushButton("Print ZCE")
    zce_print.clicked.connect(lambda: print_graph(
184
        augCanvas.ds, coff, coffgrad, augCanvas.filename))
Yan's avatar
Yan committed
185
    zce_help = QtWidgets.QPushButton("Help")
186
    zce_help.clicked.connect(lambda: help_msg(parent))
Yan's avatar
Yan committed
187
188
189
    close_button = QtWidgets.QPushButton("Close")
    close_button.clicked.connect(dial_widget.close)

3Yan's avatar
3Yan committed
190
    dial_widget.keyPressEvent = lambda event: key_pressed(
Yan's avatar
Yan committed
191
            event, augCanvas.ds, coff, coffgrad, augCanvas.filename)
3Yan's avatar
3Yan committed
192

Yan's avatar
Yan committed
193
194
195
196
197
198
    butt_layout = QtWidgets.QHBoxLayout()
    butt_layout.addWidget(zce_help)
    butt_layout.addStretch(1)
    textfield = QtWidgets.QLabel(coffgrad['gmax'])
    butt_layout.addWidget(textfield)
    butt_layout.addStretch(1)
Yan's avatar
Yan committed
199
    butt_layout.addWidget(zce_print)
Yan's avatar
Yan committed
200
201
202
203
204
205
    butt_layout.addWidget(zce_export)
    butt_layout.addWidget(close_button)

    dial_layout = QtWidgets.QVBoxLayout(dial_widget)
    dial_layout.addWidget(graph_canvas)
    dial_layout.addLayout(butt_layout)
3Yan's avatar
3Yan committed
206
    dial_widget.setFocus()
Yan's avatar
Yan committed
207
    dial_widget.show()
208
209
    pop_dial(coffspect, coffspect_grad, augCanvas.ds, coff, coffgrad,
             textfield, augCanvas.filename, parent)