All classes should at least subclass 'object' to avoid being old-style classes.
[hooke.git] / hooke / plugin / procplots.py
1 '''
2 PROCPLOTS
3 Processed plots plugin for force curves.
4
5 Licensed under the GNU GPL version 2
6 '''
7 from libhooke import WX_GOOD
8 import wxversion
9 wxversion.select(WX_GOOD)
10
11 import wx
12 import libhookecurve as lhc
13 import numpy as np
14 import scipy as sp
15 import scipy.signal
16 import copy
17
18 class procplotsCommands(object):
19
20     def _plug_init(self):
21         pass
22
23     def do_derivplot(self,args):
24         '''
25         DERIVPLOT
26         (procplots.py plugin)
27         Plots the derivate (actually, the discrete differentiation) of the current force curve
28         ---------
29         Syntax: derivplot
30         '''
31         dplot=self.derivplot_curves()
32         plot_graph=self.list_of_events['plot_graph']
33         wx.PostEvent(self.frame,plot_graph(plots=[dplot]))
34
35     def derivplot_curves(self):
36         '''
37         do_derivplot helper function
38
39         create derivate plot curves for force curves.
40         '''
41         dplot=lhc.PlotObject()
42         dplot.vectors=[]
43
44         for vector in self.plots[0].vectors:
45             dplot.vectors.append([])
46             dplot.vectors[-1].append(vector[0][:-1])
47             dplot.vectors[-1].append(np.diff(vector[1]))
48
49         dplot.destination=1
50         dplot.units=self.plots[0].units
51
52         return dplot
53
54     def do_subtplot(self,args):
55         '''
56         SUBTPLOT
57         (procplots.py plugin)
58         Plots the difference between ret and ext current curve
59         -------
60         Syntax: subtplot
61         '''
62         #FIXME: sub_filter and sub_order must be args
63
64         if len(self.plots[0].vectors) != 2:
65             print 'This command only works on a curve with two different plots.'
66             pass
67
68         outplot=self.subtract_curves(sub_order=1)
69
70         plot_graph=self.list_of_events['plot_graph']
71         wx.PostEvent(self.frame,plot_graph(plots=[outplot]))
72
73     def subtract_curves(self, sub_order):
74         '''
75         subtracts the extension from the retraction
76         '''
77         xext=self.plots[0].vectors[0][0]
78         yext=self.plots[0].vectors[0][1]
79         xret=self.plots[0].vectors[1][0]
80         yret=self.plots[0].vectors[1][1]
81
82         #we want the same number of points
83         maxpoints_tot=min(len(xext),len(xret))
84         xext=xext[0:maxpoints_tot]
85         yext=yext[0:maxpoints_tot]
86         xret=xret[0:maxpoints_tot]
87         yret=yret[0:maxpoints_tot]
88
89         if sub_order:
90             ydiff=[yretval-yextval for yretval,yextval in zip(yret,yext)]
91         else: #reverse subtraction (not sure it's useful, but...)
92             ydiff=[yextval-yretval for yextval,yretval in zip(yext,yret)]
93
94         outplot=copy.deepcopy(self.plots[0])
95         outplot.vectors[0][0], outplot.vectors[1][0] = xext,xret #FIXME: if I use xret, it is not correct!
96         outplot.vectors[1][1]=ydiff
97         outplot.vectors[0][1]=[0 for item in outplot.vectors[1][0]]
98
99         return outplot
100
101
102 #-----PLOT MANIPULATORS
103     def plotmanip_median(self, plot, current, customvalue=None):
104         '''
105         does the median of the y values of a plot
106         '''
107         if customvalue:
108             median_filter=customvalue
109         else:
110             median_filter=self.config['medfilt']
111
112         if median_filter==0:
113             return plot
114
115         if float(median_filter)/2 == int(median_filter)/2:
116             median_filter+=1
117
118         nplots=len(plot.vectors)
119         c=0
120         while c<nplots:
121             plot.vectors[c][1]=scipy.signal.medfilt(plot.vectors[c][1],median_filter)
122             c+=1
123
124         return plot
125
126
127     def plotmanip_correct(self, plot, current, customvalue=None):
128         '''
129         does the correction for the deflection for a force spectroscopy curve.
130         Assumes that:
131         - the current plot has a deflection() method that returns a vector of values
132         - the deflection() vector is as long as the X of extension + the X of retraction
133         - plot.vectors[0][0] is the X of extension curve
134         - plot.vectors[1][0] is the X of retraction curve
135
136         FIXME: both this method and the picoforce driver have to be updated, deflection() must return
137         a more senseful data structure!
138         '''
139         #use only for force spectroscopy experiments!
140         if current.curve.experiment != 'smfs':
141             return plot
142
143         if customvalue != None:
144             execute_me=customvalue
145         else:
146             execute_me=self.config['correct']
147         if not execute_me:
148             return plot
149
150         defl_ext,defl_ret=current.curve.deflection()
151         #halflen=len(deflall)/2
152
153         plot.vectors[0][0]=[(zpoint-deflpoint) for zpoint,deflpoint in zip(plot.vectors[0][0],defl_ext)]
154         plot.vectors[1][0]=[(zpoint-deflpoint) for zpoint,deflpoint in zip(plot.vectors[1][0],defl_ret)]
155
156         return plot
157
158     '''
159     def plotmanip_detriggerize(self, plot, current, customvalue=None):
160         #DEPRECATED
161         if self.config['detrigger']==0:
162             return plot
163
164         cutindex=2
165         startvalue=plot.vectors[0][0][0]
166
167         for index in range(len(plot.vectors[0][0])-1,2,-2):
168            if plot.vectors[0][0][index]>startvalue:
169                 cutindex=index
170            else:
171                 break
172
173         plot.vectors[0][0]=plot.vectors[0][0][:cutindex]
174         plot.vectors[0][1]=plot.vectors[0][1][:cutindex]
175
176         return plot
177     '''
178
179
180
181 #FFT---------------------------
182     def fft_plot(self, vector):
183         '''
184         calculates the fast Fourier transform for the selected vector in the plot
185         '''
186         fftplot=lhc.PlotObject()
187         fftplot.vectors=[[]]
188
189         fftlen=len(vector)/2 #need just 1/2 of length
190         fftplot.vectors[-1].append(np.arange(1,fftlen).tolist())
191
192         try:
193             fftplot.vectors[-1].append(abs(np.fft(vector)[1:fftlen]).tolist())
194         except TypeError: #we take care of newer NumPy (1.0.x)
195             fftplot.vectors[-1].append(abs(np.fft.fft(vector)[1:fftlen]).tolist())
196
197
198         fftplot.destination=1
199
200
201         return fftplot
202
203
204     def do_fft(self,args):
205         '''
206         FFT
207         (procplots.py plugin)
208         Plots the fast Fourier transform of the selected plot
209         ---
210         Syntax: fft [top,bottom] [select] [0,1...]
211
212         By default, fft performs the Fourier transform on all the 0-th data set on the
213         top plot.
214
215         [top,bottom]: which plot is the data set to fft (default: top)
216         [select]: you pick up two points on the plot and fft only the segment between
217         [0,1,...]: which data set on the selected plot you want to fft (default: 0)
218         '''
219
220         #args parsing
221         #whatplot = plot to fft
222         #whatset = set to fft in the plot
223         select=('select' in args)
224         if 'top' in args:
225             whatplot=0
226         elif 'bottom' in args:
227             whatplot=1
228         else:
229             whatplot=0
230         whatset=0
231         for arg in args:
232             try:
233                 whatset=int(arg)
234             except ValueError:
235                 pass
236
237         if select:
238             points=self._measure_N_points(N=2, whatset=whatset)
239             boundaries=[points[0].index, points[1].index]
240             boundaries.sort()
241             y_to_fft=self.plots[whatplot].vectors[whatset][1][boundaries[0]:boundaries[1]] #y
242         else:
243             y_to_fft=self.plots[whatplot].vectors[whatset][1] #y
244
245         fftplot=self.fft_plot(y_to_fft)
246         fftplot.units=['frequency', 'power']
247         plot_graph=self.list_of_events['plot_graph']
248         wx.PostEvent(self.frame,plot_graph(plots=[fftplot]))