prasopes.py 8.8 KB
Newer Older
Yan's avatar
Yan committed
1
2
3
4
5
6
7
#!/usr/bin/env python3

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.widgets import SpanSelector
from PyQt5 import QtCore
from PyQt5 import QtWidgets
Yan's avatar
Yan committed
8
from rawFin2 import load_raw
Yan's avatar
Yan committed
9
10
11
12
13
14
15
16
from scipy.signal import find_peaks
import sys
import matplotlib
import numpy as np
import logging
matplotlib.use("Qt5Agg")


17
def zoom_factory(ax, base_scale, plot=None, an=None):
Yan's avatar
Yan committed
18
    def zoom_fun(event, chart, ann):
Yan's avatar
Yan committed
19
20
        if event.inaxes == ax:
            if event.button == 'up':
21
                #zoom in
Yan's avatar
Yan committed
22
23
                scale_factor = 1/base_scale
            elif event.button == 'down':
24
                #zoom out
Yan's avatar
Yan committed
25
26
                scale_factor = base_scale
            else:
27
                #should not happen
Yan's avatar
Yan committed
28
29
                scale_factor = 1
                print(event.button)
30
31
32

            if event.key == 'shift':
                data = event.ydata
Yan's avatar
Yan committed
33
34
                new_top = data + (ax.get_ylim()[1] - data)*scale_factor
                ax.set_ylim([new_top*-0.01,new_top])
35
36
            else:
                data = event.xdata
Yan's avatar
Yan committed
37
38
39
40
41
42
43
                x_left = data - ax.get_xlim()[0]
                x_right = ax.get_xlim()[1] - data
                ax.set_xlim([data - x_left*scale_factor,
                            data + x_right*scale_factor])
            if ann is not None:
                if type(chart['x']) != type(None):
                    ann_spec(event.inaxes, chart['x'], chart['y'], ann)
44
            ax.figure.canvas.draw()
Yan's avatar
Yan committed
45
46
47

    fig = ax.get_figure()  # get the figure of interest
    # attach the call back
48
    fig.canvas.mpl_connect('scroll_event', lambda event: zoom_fun(event, plot, an))
Yan's avatar
Yan committed
49
50
51
52
53

    # return the function
    return zoom_fun


Yan's avatar
Yan committed
54
def pan_factory(axis, plot=None, an=None):
55
    def pan_fun(event, ax):
Yan's avatar
Yan committed
56
57
58
59
        if event.dblclick and event.inaxes == ax:
            ax.get_figure()
            ax.autoscale(True)
            ax.set_ylim(ax.get_ylim()[1]*-0.01,ax.get_ylim()[1]*1.1)
Yan's avatar
Yan committed
60
            ann_spec(spectrum, plot['x'], plot['y'], an)
Yan's avatar
Yan committed
61
62
            ax.figure.canvas.draw()
        elif event.button == 1 and event.inaxes == ax:
Yan's avatar
Yan committed
63
            ax.start_pan(event.x, event.y, event.button)
64
            id_drag = fig.canvas.mpl_connect('motion_notify_event', lambda action: drag_fun(action, ax))
Yan's avatar
Yan committed
65
            id_release = fig.canvas.mpl_connect('button_release_event',
66
                                                lambda action: drag_end(action, id_drag, id_release, plot, an, ax))
Yan's avatar
Yan committed
67

68
    def drag_fun(event, ax):
Yan's avatar
Yan committed
69
70
71
        ax.drag_pan(1, 'x', event.x, event.y)
        ax.figure.canvas.draw()

Yan's avatar
Yan committed
72
    def drag_end(event, id_drag, id_release, chart, ann, ax):
Yan's avatar
Yan committed
73
74
75
        if event.button == 1:
            fig.canvas.mpl_disconnect(id_drag)
            fig.canvas.mpl_disconnect(id_release)
Yan's avatar
Yan committed
76
77
78
            if ann is not None:
                if type(chart['x']) != type(None):
                    ann_spec(ax, chart['x'], chart['y'], ann)
79
            ax.figure.canvas.draw()
Yan's avatar
Yan committed
80
81
    fig = axis.get_figure()
    fig.canvas.mpl_connect('button_press_event', lambda action: pan_fun(action, axis))
Yan's avatar
Yan committed
82

Yan's avatar
Yan committed
83
84
85
def pick_masses(x_min, x_max, ax, an, plot):
    ax.set_xlim(x_min, x_max)
    ann_spec(spectrum, plot['x'], plot['y'], an)
Yan's avatar
Yan committed
86
    ax.figure.canvas.draw()
Yan's avatar
Yan committed
87

Yan's avatar
Yan committed
88
def pick_times(x_min, x_max, mpl_spectrum, data_set, mpl_chromatogram, an, ms_s):
Yan's avatar
Yan committed
89
90
    start_scan = None
    end_scan = None 
Yan's avatar
Yan committed
91
92
    for i, j in enumerate(data_set['chrom_dat'][0, :]):
        if j > x_min and start_scan is None:
Yan's avatar
Yan committed
93
            start_scan = i
Yan's avatar
Yan committed
94
        if j > x_max and end_scan is None:
Yan's avatar
Yan committed
95
            end_scan = i
Yan's avatar
Yan committed
96
    mpl_spectrum.clear()
97
    an.clear()
Yan's avatar
Yan committed
98
99
100
101
102
103
104
105
    ms_s['x'] = data_set['masses']
    ms_s['y'] = np.mean(data_set['matrix'][start_scan:end_scan], axis=0)
    spectrum_plot(spectrum, ms['x'], ms['y'], an)
    mpl_chromatogram.clear()
    chrom_plot(mpl_chromatogram, data_set['chrom_dat'][0, :], data_set['chrom_dat'][1, :])
    mpl_chromatogram.plot(data_set['chrom_dat'][0, start_scan:end_scan], data_set['chrom_dat'][1, start_scan:end_scan], 'b.')

def populate(mpl_chromatogram, mpl_spectrum, data_set, time_sel, an, ms_s):
106
    an.clear()
Yan's avatar
Yan committed
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    def update_span_selector(chrom, spec, d_set, ms_spec):
        time_selector = SpanSelector(chrom, lambda x_min, x_max: pick_times(x_min, x_max, spec, d_set, chrom, an, ms_spec), 'horizontal', useblit=True, rectprops=dict(alpha=0.15, facecolor='purple'), button=3)
        return time_selector
    mpl_spectrum.clear()
    mpl_chromatogram.clear()
    ms_s['x'] = data_set['masses']
    ms_s['y'] = np.mean(data_set['matrix'], axis=0)
    spectrum_plot(mpl_spectrum, ms_s['x'], ms_s['y'], an)
    chrom_plot(mpl_chromatogram, data_set['chrom_dat'][0, :], data_set['chrom_dat'][1, :])
    time_sel[0] = update_span_selector(mpl_chromatogram, mpl_spectrum, data_set, ms_s)
    mpl_chromatogram.figure.canvas.draw()
    mpl_spectrum.figure.canvas.draw()

def ann_spec(ms_spec, mass, intensity, an):
    def sub_peaks(peakz, x_value, y_value, x, y):
Yan's avatar
Yan committed
122
123
        gp=[]
        sp=[]
Yan's avatar
Yan committed
124
125
        for g in peakz:
            if gp == [] or (abs(max(y_value[gp]) - y_value[g]) * 10 < y and abs(x_value[gp[np.argmax(y_value[gp])]] - x_value[g]) * 20 < x):
Yan's avatar
Yan committed
126
127
                gp.append(g)
            else:
Yan's avatar
Yan committed
128
                sp.append(gp[np.argmax(y_value[gp])])
Yan's avatar
Yan committed
129
                gp = [g]
Yan's avatar
Yan committed
130
131
            if g == peakz[-1]:
                sp.append(gp[np.argmax(y_value[gp])])
Yan's avatar
Yan committed
132
        return sp
133

Yan's avatar
Yan committed
134
    borders=ms_spec.get_xlim()
135
136
137
138
    start = np.argmax(mass>borders[0])
    end = np.argmax(mass>borders[1])
    if end == 0:
        end = np.argmax(mass)
Yan's avatar
Yan committed
139
    peaks = find_peaks(intensity[start:end], height=ms_spec.get_ylim()[1] / 100)
140
    peaks = peaks[0] + start
Yan's avatar
Yan committed
141
    s_peaks = sub_peaks(peaks, mass, intensity, ms_spec.get_xlim()[1] - ms_spec.get_xlim()[0], ms_spec.get_ylim()[1] - ms_spec.get_ylim()[0])
142
143
144
145
    
    for j in an:
        j.remove()
    an.clear()
Yan's avatar
Yan committed
146

Yan's avatar
Yan committed
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
    for i in s_peaks:
        an.append(ms_spec.annotate('{0:.2f}'.format(mass[i]), xy=(mass[i], intensity[i]), textcoords='data'))

def spectrum_plot(spc, mass, intensity, an):
    spc.plot(mass, intensity)
    spc.set_title("Spectrum:", loc ="right")
    spc.set_xlabel("m/z")
    spc.set_ylabel("ion count")
    spc.set_ylim(spc.get_ylim()[1] * -0.01, )
    spc.ticklabel_format(scilimits=(0, 0), axis='y')
    ann_spec(spc, mass, intensity, an)

def chrom_plot(chrom, times, tic):
    chrom.plot(times, tic)
    chrom.set_ylim(chrom.get_ylim()[1] * -0.011, chrom.get_ylim()[1] * 1.1)
    chrom.set_title("Chromatogram:", loc ="right")
    chrom.set_xlabel("time (min)")
    chrom.set_ylabel("total ion count")
    chrom.ticklabel_format(scilimits=(0, 0), axis='y')

def open_file(chrom, spc, d_set, time_sel, an, ms_s):
Yan's avatar
Yan committed
168
169
170
    filename=QtWidgets.QFileDialog.getOpenFileName(caption = "Open spectrum", filter="Finnigan RAW files (*.raw, *.RAW)")[0]
    if filename is '':
        return
Yan's avatar
Yan committed
171
172
    d_set['chrom_dat'], d_set['masses'], d_set['matrix'] = load_raw(filename)
    populate(chrom, spc, d_set, time_sel, an, ms_s)
Yan's avatar
Yan committed
173
174
175
176


if __name__=="__main__":
    #ds for data_set
Yan's avatar
Yan committed
177
    ds = dict(chrom_dat=None,masses=None,matrix=None)
178
179
    #mass spectrometry set
    ms = dict(x=None,y=None)
Yan's avatar
Yan committed
180

Yan's avatar
Yan committed
181
    p_logger = logging.getLogger('parseLogger')
Yan's avatar
Yan committed
182
    logging.basicConfig()
Yan's avatar
Yan committed
183
    p_logger.setLevel("WARN")
Yan's avatar
Yan committed
184
185
186
187
188
189
190
191
192
193
194

    graph = Figure(figsize=(5,4),dpi=100)
    graph.patch.set_facecolor("None")

    chromatogram = graph.add_subplot(211,facecolor=(1,1,1,0.8))
    spectrum = graph.add_subplot(212,facecolor=(1,1,1,0.8))
    graph.tight_layout()

    mpl_canvas = FigureCanvas(graph)
    mpl_canvas.setStyleSheet("background-color:transparent;")
    mpl_canvas.setAutoFillBackground(False)
195
    mpl_canvas.setFocusPolicy( QtCore.Qt.ClickFocus )
Yan's avatar
Yan committed
196
197
198
199
    
    timeSelector=[None]
    annotation=[]

200
    pan_factory(chromatogram)
Yan's avatar
Yan committed
201
    zoom_factory(chromatogram, 1.15)
202
203
    pan_factory(spectrum, ms, annotation)
    zoom_factory(spectrum, 1.15, ms, annotation)
Yan's avatar
Yan committed
204
    mass_selector = SpanSelector(spectrum, lambda x_min, x_max: pick_masses(x_min, x_max, spectrum, annotation, ms), 'horizontal', useblit=True, rectprops=dict(alpha=0.15, facecolor='purple'), button=3)
Yan's avatar
Yan committed
205
206
207
208
209
210

    app = QtWidgets.QApplication(sys.argv)
    main_window = QtWidgets.QMainWindow()

    file_menu = QtWidgets.QMenu('&File',main_window)
    main_window.menuBar().addMenu(file_menu)
Yan's avatar
Yan committed
211
    file_menu.addAction('&Open..', lambda: open_file(chromatogram, spectrum, ds, timeSelector, annotation, ms), QtCore.Qt.CTRL + QtCore.Qt.Key_O)
Yan's avatar
Yan committed
212
213
214
215
216
217
218
    file_menu.addAction('&Quit', main_window.close, QtCore.Qt.CTRL + QtCore.Qt.Key_Q)

    main_widget = QtWidgets.QWidget(main_window)
    main_window.setCentralWidget(main_widget)

    layout = QtWidgets.QVBoxLayout(main_widget)
    layout.addWidget(mpl_canvas)
219
    mpl_canvas.setFocus()
Yan's avatar
Yan committed
220

Yan's avatar
Yan committed
221
222
223
224

    if len(sys.argv) == 2:
        raw_file=sys.argv[1]
        ds['chrom_dat'],ds['masses'],ds['matrix'] = load_raw(raw_file)
225
        populate(chromatogram, spectrum, ds, timeSelector,annotation, ms)
Yan's avatar
Yan committed
226
227
228
    else:
        spectrum_plot(spectrum, [0], [0], annotation)
        chrom_plot(chromatogram, [0], [0])
Yan's avatar
Yan committed
229
230
231
232

    main_window.show()
    sys.exit(app.exec_())