graphtools.py 9.23 KB
Newer Older
Yan's avatar
Yan committed
1
import numpy as np
Yan's avatar
Yan committed
2
import prasopes.datatools as dt
Yan's avatar
Yan committed
3

Yan's avatar
Yan committed
4
5

def zoom_factory(axis, base_scale, plot_data=None):
Yan's avatar
Yan committed
6
    """returns zooming functionality to axis"""
Yan's avatar
Yan committed
7
    def zoom_fun(event, pd, ax, scale):
Yan's avatar
Yan committed
8
        """zoom when scrolling"""
Yan's avatar
Yan committed
9
        if event.inaxes == axis:
Yan's avatar
Yan committed
10
            if event.button == 'up':
Yan's avatar
Yan committed
11
                # zoom in
Yan's avatar
Yan committed
12
                scale_factor = 1/scale
Yan's avatar
Yan committed
13
            elif event.button == 'down':
Yan's avatar
Yan committed
14
                # zoom out
Yan's avatar
Yan committed
15
                scale_factor = scale
Yan's avatar
Yan committed
16
            else:
Yan's avatar
Yan committed
17
                #  should not happen
Yan's avatar
Yan committed
18
19
                scale_factor = 1
                print(event.button)
20
21
22

            if event.key == 'shift':
                data = event.ydata
Yan's avatar
Yan committed
23
24
                new_top = data + (ax.get_ylim()[1] - data) \
                    * scale_factor
Yan's avatar
Yan committed
25
26
27
28
                ymin = -0.01
                if type(pd) is dict and "c_ymin" in pd:
                    ymin = pd['c_ymin']
                axis.set_ylim([new_top * ymin, new_top])
29
30
            else:
                data = event.xdata
Yan's avatar
Yan committed
31
32
                x_left = data - ax.get_xlim()[0]
                x_right = ax.get_xlim()[1] - data
Yan's avatar
Yan committed
33
                ax.set_xlim([data - x_left * scale_factor,
Yan's avatar
Yan committed
34
                            data + x_right * scale_factor])
Yan's avatar
Yan committed
35
            if type(pd) is dict and "annotation" in pd:
Yan's avatar
Yan committed
36
                ann_spec(event.inaxes, pd)
37
            ax.figure.canvas.draw()
Yan's avatar
Yan committed
38

Yan's avatar
Yan committed
39
    fig = axis.get_figure()
40
41
    fig.canvas.mpl_connect('scroll_event', lambda event: zoom_fun(
        event, plot_data, axis, base_scale))
Yan's avatar
Yan committed
42
43


Yan's avatar
Yan committed
44
def pan_factory(axis, plot=None):
Yan's avatar
Yan committed
45
    """pan spectrum when you press a button"""
Yan's avatar
Yan committed
46
    def pan_fun(event, ax, pd):
Yan's avatar
Yan committed
47
        # rescale to origin if doubleclicked
Yan's avatar
Yan committed
48
49
50
        if event.dblclick and event.inaxes == ax:
            ax.get_figure()
            ax.autoscale(True)
Yan's avatar
Yan committed
51
52
53
54
55
56
            if type(pd) is dict and "annotation" in pd:
                ann_spec(ax, pd)
            ymin = -0.01
            if type(pd) is dict and "c_ymin" in pd:
                ymin = pd['c_ymin']
            ax.set_ylim(ax.get_ylim()[1]*ymin, ax.get_ylim()[1]*1.1)
Yan's avatar
Yan committed
57
            ax.figure.canvas.draw()
Yan's avatar
Yan committed
58
        # otherwise pan
Yan's avatar
Yan committed
59
        elif event.button == 1 and event.inaxes == ax:
Yan's avatar
Yan committed
60
            ax.start_pan(event.x, event.y, event.button)
Yan's avatar
Yan committed
61
62
63
            id_drag = fig.canvas.mpl_connect(
                'motion_notify_event',
                lambda action: drag_fun(action, ax))
Yan's avatar
Yan committed
64
            id_release = fig.canvas.mpl_connect(
Yan's avatar
Yan committed
65
66
                'button_release_event',
                lambda action: drag_end(
Yan's avatar
Yan committed
67
                    action, id_drag, id_release, pd, ax))
Yan's avatar
Yan committed
68

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

Yan's avatar
Yan committed
73
    def drag_end(event, id_drag, id_release, pd, ax):
Yan's avatar
Yan committed
74
75
76
        if event.button == 1:
            fig.canvas.mpl_disconnect(id_drag)
            fig.canvas.mpl_disconnect(id_release)
Yan's avatar
Yan committed
77
78
            if type(pd) is dict and "annotation" in pd:
                ann_spec(ax, pd)
79
            ax.figure.canvas.draw()
Yan's avatar
Yan committed
80

Yan's avatar
Yan committed
81
    fig = axis.get_figure()
Yan's avatar
Yan committed
82
    fig.canvas.mpl_connect('button_press_event',
Yan's avatar
Yan committed
83
                           lambda action: pan_fun(action, axis, plot))
Yan's avatar
Yan committed
84

Yan's avatar
Yan committed
85

Yan's avatar
Yan committed
86
def pick_masses(x_min, x_max, ms_spec, msdata):
Yan's avatar
Yan committed
87
    """zoom the spectrum in x axis by mass range"""
Yan's avatar
Yan committed
88
89
90
    ms_spec.set_xlim(x_min, x_max)
    autozoomy(msdata['autoy'], ms_spec, msdata)
    ann_spec(ms_spec, msdata)
Yan's avatar
Yan committed
91

Yan's avatar
Yan committed
92

93
94
def plot_subtime(mpl_spectrum, mpl_chromatogram, data_set, mass_spect,
                 chrom_spect):
Yan's avatar
Yan committed
95
    """plot averaged spectrum of subselected part of the chromatogram"""
Yan's avatar
Yan committed
96
    slims = [mpl_spectrum.get_xlim(), mpl_spectrum.get_ylim()]
Yan's avatar
Yan committed
97
    mpl_spectrum.clear()
Yan's avatar
Yan committed
98
    mass_spect['annotation'].clear()
Yan's avatar
Yan committed
99
    mass_spect['x'] = data_set['masses']
Yan's avatar
Yan committed
100
    mass_spect['y'] = np.mean(
101
        data_set['matrix'][chrom_spect['timesarg']], axis=0)
Yan's avatar
Yan committed
102
    pop_plot(mpl_spectrum, mass_spect)
Yan's avatar
Yan committed
103
    mpl_spectrum.set_xlim(slims[0])
Yan's avatar
Yan committed
104
105
    if mass_spect['autoy'] is False:
        mpl_spectrum.set_ylim(slims[1])
Yan's avatar
Yan committed
106

Yan's avatar
Yan committed
107
    mpl_chromatogram.clear()
Yan's avatar
Yan committed
108
    pop_plot(mpl_chromatogram, chrom_spect)
109
110
    dots_x = data_set['chrom_dat'][0, chrom_spect['timesarg']]
    dots_y = data_set['chrom_dat'][1, chrom_spect['timesarg']]
Yan's avatar
Yan committed
111
    mpl_chromatogram.plot(dots_x, dots_y, 'b.')
Yan's avatar
Yan committed
112
    ann_spec(mpl_spectrum, mass_spect)
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
    mpl_chromatogram.get_figure().canvas.draw()


def pick_times(x_min, x_max, mpl_spectrum, data_set, mpl_chromatogram,
               mass_spect, chrom_spect):
    """subselect part of the chromatogram and plot it"""
    chrom_spect['t_start'] = x_min
    chrom_spect['t_end'] = x_max
    times = data_set['chrom_dat'][0, :]
    chrom_spect['timesarg'] = dt.argsubselect(times, x_min, x_max)
    plot_subtime(mpl_spectrum, mpl_chromatogram, data_set, mass_spect,
                 chrom_spect)


def arrow_factory(spectrum, chromatogram, ds, mass_spect,
                  chrom_spect):
    def arrow_fun(event, mpl_spectrum, mpl_chromatogram, data_set,
                  mass_spect, chrom_spect):
3Yan's avatar
3Yan committed
131
132
133
134
135
136
137
138
139
        arrows = dict(left=-1, right=+1)
        if event.key in arrows.keys() and not isinstance(
                chrom_spect['timesarg'], type(None)):
            times = np.arange(len(data_set['chrom_dat'][0]))
            chrom_spect['timesarg'] = dt.argsubselect(
                times, chrom_spect['timesarg'][0]+arrows[event.key],
                chrom_spect['timesarg'][-1]+arrows[event.key])
            plot_subtime(mpl_spectrum, mpl_chromatogram, data_set,
                         mass_spect, chrom_spect)
140
141
142
143

    fig = chromatogram.get_figure()
    fig.canvas.mpl_connect('key_press_event', lambda event: arrow_fun(
        event, spectrum, chromatogram, ds, mass_spect, chrom_spect))
Yan's avatar
Yan committed
144

Yan's avatar
Yan committed
145
146
147
148
149
def autozoomy(state, ms_spec, msdata):
    if state is True:
        msdata['autoy'] = True
        ms_spec.autoscale(True, 'y')
        ymin = -0.01
Yan's avatar
Yan committed
150
151
152
153
        argvis = dt.argsubselect(msdata['x'], *ms_spec.get_xlim())
        ymax = max(msdata['y'][argvis])
        ms_spec.set_ylim(ymax*ymin,
                         ymax*1.1)
Yan's avatar
Yan committed
154
155
156
157
        ms_spec.figure.canvas.draw()
    else:
        msdata['autoy'] = False

Yan's avatar
Yan committed
158

Yan's avatar
Yan committed
159
def ann_spec(ms_spec, msdata, ann_limit=0.01):
Yan's avatar
Yan committed
160
    """annotate spectrum
161
162
163
164
165
166

    First define the array, in which the annotation should occur.
    Then remove values which are invalid as local maximas. Then select
    local maximas from the array by forcycling. Local maximas are then
    reduced to a representation of the important ones by the sub_peaks
    function"""
Yan's avatar
Yan committed
167
168
169
    def sub_peaks(peakz, x_value, y_value, xrange, yrange, coef_x=10,
                  coef_y=10):
        """Returns reasonable subselection of local maximas"""
Yan's avatar
Yan committed
170
171
172
        sort_peaks = sorted(
            peakz, key=lambda h: y_value[h], reverse=True)
        subtracted_peaks = []
Yan's avatar
Yan committed
173
174
175
        red_x = xrange / coef_x
        red_y = yrange / coef_y
        for peak in sort_peaks:
176
            add = True
Yan's avatar
Yan committed
177
178
179
180
181
            yv = y_value[peak]
            xv = x_value[peak]
            for u in subtracted_peaks:
                if abs(yv - y_value[u]) < red_y \
                        and abs(xv - x_value[u]) < red_x:
182
183
                    add = False
            if add:
Yan's avatar
Yan committed
184
185
                subtracted_peaks.append(peak)
        return subtracted_peaks
186

187
    argvis = dt.argsubselect(msdata['x'], *ms_spec.get_xlim())
Yan's avatar
Yan committed
188
189
190
    #remove tails which cannot be evaluated as maximas
    argvis = argvis[np.where((argvis != 0)
                             & (argvis != (len(msdata['x'])-1)))]
Yan's avatar
Yan committed
191
    lim = ms_spec.get_ylim()[1] * ann_limit
Yan's avatar
Yan committed
192
193
194
195
    peaks = []
    for i in argvis:
        if msdata['y'][i] > lim and msdata['y'][i] > max(
                msdata['y'][i-1], msdata['y'][i+1]):
196
            peaks.append(i)
Yan's avatar
Yan committed
197
    s_peaks = sub_peaks(peaks, msdata['x'], msdata['y'],
198
199
                        np.diff(ms_spec.get_xlim()),
                        np.diff(ms_spec.get_ylim()))
Yan's avatar
Yan committed
200

Yan's avatar
Yan committed
201
    # delete objects from the spectra
Yan's avatar
Yan committed
202
    for intensity in msdata['annotation']:
Yan's avatar
Yan committed
203
        intensity.remove()
Yan's avatar
Yan committed
204
    # remove them from tracking
Yan's avatar
Yan committed
205
    msdata['annotation'].clear()
Yan's avatar
Yan committed
206

Yan's avatar
Yan committed
207
    for i in s_peaks:
Yan's avatar
Yan committed
208
209
        msdata['annotation'].append(ms_spec.annotate(
            '{0:.2f}'.format(msdata['x'][i]), xy=(msdata['x'][i], msdata['y'][i]),
Yan's avatar
Yan committed
210
            textcoords='data'))
Yan's avatar
Yan committed
211

Yan's avatar
Yan committed
212

Yan's avatar
Yan committed
213
def pop_plot(plot, plot_data):
Yan's avatar
Yan committed
214
    """Define and populate plot"""
Yan's avatar
Yan committed
215
    plot_data['line'] = plot.plot(plot_data['x'], plot_data['y'])
Yan's avatar
Yan committed
216
    plot.set_title(plot_data['name'], loc="right")
Yan's avatar
Yan committed
217
218
    plot.set_xlabel(plot_data['xlabel'])
    plot.set_ylabel(plot_data['ylabel'])
Yan's avatar
Yan committed
219
    plot.set_ylim(plot.get_ylim()[1] * -0.01, 
Yan's avatar
Yan committed
220
                  plot.get_ylim()[1] * 1.1)
Yan's avatar
Yan committed
221
    plot.ticklabel_format(scilimits=(0, 0), axis='y')
Yan's avatar
Yan committed
222
223
    if "annotation" in plot_data:
        ann_spec(plot, plot_data)
Yan's avatar
Yan committed
224
225
226
227
228
    if "xtics" in plot_data:
        plot.locator_params(nbins=plot_data["xtics"], axis='x')
        plot.minorticks_on()
        plot.tick_params(axis='y', which='minor', left=False)

Yan's avatar
Yan committed
229

Yan's avatar
Yan committed
230
231
232
233
234
235
def populate(mpl_chromatogram, mpl_spectrum, data_set,
             mass_spect, chrom_spect):
    """populate the GUI plots with desired dataset"""
    mass_spect['annotation'].clear()
    mpl_spectrum.clear()
    mpl_chromatogram.clear()
Yan's avatar
Yan committed
236

Yan's avatar
Yan committed
237
238
239
240
    mass_spect['x'] = data_set['masses']
    mass_spect['y'] = np.mean(data_set['matrix'], axis=0)
    pop_plot(mpl_spectrum, mass_spect)
    mpl_spectrum.figure.canvas.draw()
Yan's avatar
Yan committed
241

Yan's avatar
Yan committed
242
243
244
245
246
247
    chrom_spect['x'] = data_set['chrom_dat'][0, :]
    chrom_spect['y'] = data_set['chrom_dat'][1, :]
    chrom_spect['t_start'] = data_set['chrom_dat'][0, 0]
    chrom_spect['t_end'] = data_set['chrom_dat'][0, -1]
    pop_plot(mpl_chromatogram, chrom_spect)
    mpl_chromatogram.figure.canvas.draw()