(fit.py) Quick kludgy patch for crash of issue 0028
[hooke.git] / hooke / plugin / procplots.py
1 #!/usr/bin/env python
2
3 '''
4 PROCPLOTS
5 Processed plots plugin for force curves.
6
7 Licensed under the GNU GPL version 2
8 '''
9 from libhooke import WX_GOOD
10 import wxversion
11 wxversion.select(WX_GOOD)
12
13 import wx
14 import libhookecurve as lhc
15 import numpy as np
16 import scipy as sp
17 import scipy.signal
18 import copy
19
20 class procplotsCommands:
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]))
251