Moving hooke.plugin.procplots to .curve in preparation for merge
[hooke.git] / hooke / plugin / curve.py
1 # Copyright (C) 2008-2010 Alberto Gomez-Casado
2 #                         Massimo Sandal <devicerandom@gmail.com>
3 #                         W. Trevor King <wking@drexel.edu>
4 #
5 # This file is part of Hooke.
6 #
7 # Hooke is free software: you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation, either
10 # version 3 of the License, or (at your option) any later version.
11 #
12 # Hooke is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU Lesser General Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with Hooke.  If not, see
19 # <http://www.gnu.org/licenses/>.
20
21 """Processed plots plugin for force curves.
22 """
23
24 from ..libhooke import WX_GOOD
25 import wxversion
26 wxversion.select(WX_GOOD)
27
28 import wx
29 import numpy as np
30 import scipy as sp
31 import scipy.signal
32 import copy
33
34 from .. import curve as lhc
35
36
37 class procplotsCommands(object):
38
39     def _plug_init(self):
40         pass
41
42     def do_derivplot(self,args):
43         '''
44         DERIVPLOT
45         (procplots.py plugin)
46         Plots the derivate (actually, the discrete differentiation) of the current force curve
47         ---------
48         Syntax: derivplot
49         '''
50         dplot=self.derivplot_curves()
51         plot_graph=self.list_of_events['plot_graph']
52         wx.PostEvent(self.frame,plot_graph(plots=[dplot]))
53
54     def derivplot_curves(self):
55         '''
56         do_derivplot helper function
57
58         create derivate plot curves for force curves.
59         '''
60         dplot=lhc.PlotObject()
61         dplot.vectors=[]
62
63         for vector in self.plots[0].vectors:
64             dplot.vectors.append([])
65             dplot.vectors[-1].append(vector[0][:-1])
66             dplot.vectors[-1].append(np.diff(vector[1]))
67
68         dplot.destination=1
69         dplot.units=self.plots[0].units
70
71         return dplot
72
73     def do_subtplot(self, args):
74         '''
75         SUBTPLOT
76         (procplots.py plugin)
77         Plots the difference between ret and ext current curve
78         -------
79         Syntax: subtplot
80         '''
81         #FIXME: sub_filter and sub_order must be args
82
83         if len(self.plots[0].vectors) != 2:
84             print 'This command only works on a curve with two different plots.'
85             pass
86
87         outplot=self.subtract_curves(sub_order=1)
88
89         plot_graph=self.list_of_events['plot_graph']
90         wx.PostEvent(self.frame,plot_graph(plots=[outplot]))
91
92     def subtract_curves(self, sub_order):
93         '''
94         subtracts the extension from the retraction
95         '''
96         xext=self.plots[0].vectors[0][0]
97         yext=self.plots[0].vectors[0][1]
98         xret=self.plots[0].vectors[1][0]
99         yret=self.plots[0].vectors[1][1]
100
101         #we want the same number of points
102         maxpoints_tot=min(len(xext),len(xret))
103         xext=xext[0:maxpoints_tot]
104         yext=yext[0:maxpoints_tot]
105         xret=xret[0:maxpoints_tot]
106         yret=yret[0:maxpoints_tot]
107
108         if sub_order:
109             ydiff=[yretval-yextval for yretval,yextval in zip(yret,yext)]
110         else: #reverse subtraction (not sure it's useful, but...)
111             ydiff=[yextval-yretval for yextval,yretval in zip(yext,yret)]
112
113         outplot=copy.deepcopy(self.plots[0])
114         outplot.vectors[0][0], outplot.vectors[1][0] = xext,xret #FIXME: if I use xret, it is not correct!
115         outplot.vectors[1][1]=ydiff
116         outplot.vectors[0][1]=[0 for item in outplot.vectors[1][0]]
117
118         return outplot
119
120
121 #-----PLOT MANIPULATORS
122     def plotmanip_median(self, plot, current, customvalue=None):
123         '''
124         does the median of the y values of a plot
125         '''
126         if customvalue:
127             median_filter=customvalue
128         else:
129             median_filter=self.config['medfilt']
130
131         if median_filter==0:
132             return plot
133
134         if float(median_filter)/2 == int(median_filter)/2:
135             median_filter+=1
136
137         nplots=len(plot.vectors)
138         c=0
139         while c<nplots:
140             plot.vectors[c][1]=scipy.signal.medfilt(plot.vectors[c][1],median_filter)
141             c+=1
142
143         return plot
144
145
146     def plotmanip_correct(self, plot, current, customvalue=None):
147         '''
148         does the correction for the deflection for a force spectroscopy curve.
149         Assumes that:
150         - the current plot has a deflection() method that returns a vector of values
151         - the deflection() vector is as long as the X of extension + the X of retraction
152         - plot.vectors[0][0] is the X of extension curve
153         - plot.vectors[1][0] is the X of retraction curve
154
155         FIXME: both this method and the picoforce driver have to be updated, deflection() must return
156         a more senseful data structure!
157         '''
158         #use only for force spectroscopy experiments!
159         if current.curve.experiment != 'smfs':
160             return plot
161
162         if customvalue != None:
163             execute_me=customvalue
164         else:
165             execute_me=self.config['correct']
166         if not execute_me:
167             return plot
168
169         defl_ext,defl_ret=current.curve.deflection()
170         #halflen=len(deflall)/2
171
172         plot.vectors[0][0]=[(zpoint-deflpoint) for zpoint,deflpoint in zip(plot.vectors[0][0],defl_ext)]
173         plot.vectors[1][0]=[(zpoint-deflpoint) for zpoint,deflpoint in zip(plot.vectors[1][0],defl_ret)]
174
175         return plot
176
177
178     def plotmanip_centerzero(self, plot, current, customvalue=None):
179         '''
180         Centers the force curve so the median (the free level) corresponds to 0 N
181         Assumes that:
182         - plot.vectors[0][1] is the Y of extension curve
183         - plot.vectors[1][1] is the Y of retraction curve
184         
185        
186         '''
187         #use only for force spectroscopy experiments!
188         if current.curve.experiment != 'smfs':
189             return plot
190     
191         if customvalue != None:
192             execute_me=customvalue
193         else:
194             execute_me=self.config['centerzero']
195         if not execute_me:
196             return plot
197      
198         
199         
200         #levelapp=float(np.median(plot.vectors[0][1]))
201         levelret=float(np.median(plot.vectors[1][1][-300:-1]))
202
203         level=levelret  
204
205         approach=[i-level for i in plot.vectors[0][1]]
206         retract=[i-level for i in plot.vectors[1][1]]
207         
208         plot.vectors[0][1]=approach     
209         plot.vectors[1][1]=retract      
210         return plot
211     
212     '''
213     def plotmanip_detriggerize(self, plot, current, customvalue=None):
214         #DEPRECATED
215         if self.config['detrigger']==0:
216             return plot
217
218         cutindex=2
219         startvalue=plot.vectors[0][0][0]
220
221         for index in range(len(plot.vectors[0][0])-1,2,-2):
222            if plot.vectors[0][0][index]>startvalue:
223                 cutindex=index
224            else:
225                 break
226
227         plot.vectors[0][0]=plot.vectors[0][0][:cutindex]
228         plot.vectors[0][1]=plot.vectors[0][1][:cutindex]
229
230         return plot
231     '''
232
233
234
235 #FFT---------------------------
236     def fft_plot(self, vector):
237         '''
238         calculates the fast Fourier transform for the selected vector in the plot
239         '''
240         fftplot=lhc.PlotObject()
241         fftplot.vectors=[[]]
242
243         fftlen=len(vector)/2 #need just 1/2 of length
244         fftplot.vectors[-1].append(np.arange(1,fftlen).tolist())
245
246         try:
247             fftplot.vectors[-1].append(abs(np.fft(vector)[1:fftlen]).tolist())
248         except TypeError: #we take care of newer NumPy (1.0.x)
249             fftplot.vectors[-1].append(abs(np.fft.fft(vector)[1:fftlen]).tolist())
250
251
252         fftplot.destination=1
253
254
255         return fftplot
256
257
258     def do_fft(self,args):
259         '''
260         FFT
261         (procplots.py plugin)
262         Plots the fast Fourier transform of the selected plot
263         ---
264         Syntax: fft [top,bottom] [select] [0,1...]
265
266         By default, fft performs the Fourier transform on all the 0-th data set on the
267         top plot.
268
269         [top,bottom]: which plot is the data set to fft (default: top)
270         [select]: you pick up two points on the plot and fft only the segment between
271         [0,1,...]: which data set on the selected plot you want to fft (default: 0)
272         '''
273
274         #args parsing
275         #whatplot = plot to fft
276         #whatset = set to fft in the plot
277         select=('select' in args)
278         if 'top' in args:
279             whatplot=0
280         elif 'bottom' in args:
281             whatplot=1
282         else:
283             whatplot=0
284         whatset=0
285         for arg in args:
286             try:
287                 whatset=int(arg)
288             except ValueError:
289                 pass
290
291         if select:
292             points=self._measure_N_points(N=2, whatset=whatset)
293             boundaries=[points[0].index, points[1].index]
294             boundaries.sort()
295             y_to_fft=self.plots[whatplot].vectors[whatset][1][boundaries[0]:boundaries[1]] #y
296         else:
297             y_to_fft=self.plots[whatplot].vectors[whatset][1] #y
298
299         fftplot=self.fft_plot(y_to_fft)
300         fftplot.units=['frequency', 'power']
301         plot_graph=self.list_of_events['plot_graph']
302         wx.PostEvent(self.frame,plot_graph(plots=[fftplot]))