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