6 Process plots plugin for force curves.
9 with modifications by Dr. Rolf Schmidt (Concordia University, Canada)
11 This program is released under the GNU General Public License version 2.
14 import lib.libhooke as lh
16 wxversion.select(lh.WX_GOOD)
19 from numpy import arange, diff, fft
20 from scipy.signal import medfilt
22 from lib.peakspot import conv_dx
24 class procplotsCommands:
29 def do_convplot(self):
33 Plots the convolution data of the currently displayed force curve retraction.
39 #need to convert the string that contains the list into a list
40 column = self.GetIntFromConfig('procplots', 'convplot', 'column')
41 convolution = eval(self.GetStringFromConfig('procplots', 'convplot', 'convolution'))
42 row = self.GetIntFromConfig('procplots', 'convplot', 'row')
43 whatset_str = self.GetStringFromConfig('procplots', 'convplot', 'whatset')
45 if whatset_str == 'extension':
46 whatset = [lh.EXTENSION]
47 if whatset_str == 'retraction':
48 whatset = [lh.RETRACTION]
49 if whatset_str == 'both':
50 whatset = [lh.EXTENSION, lh.RETRACTION]
52 #TODO: add option to keep previous derivplot
53 plot = self.GetDisplayedPlotCorrected()
56 conv_curve = copy.deepcopy(plot.curves[index])
57 #Calculate convolution
58 conv_curve.y = conv_dx(plot.curves[index].y, convolution)
60 conv_curve.destination.column = column
61 conv_curve.destination.row = row
62 conv_curve.title = 'Convolution'
63 plot.curves.append(conv_curve)
65 #warn if no flattening has been done.
66 if not self.AppliesPlotmanipulator('flatten'):
67 self.AppendToOutput('Flatten manipulator was not applied. Processing was done without flattening.')
68 self.AppendToOutput('Enable the flatten plotmanipulator for better results.')
73 def do_derivplot(self):
77 Plots the discrete differentiation of the currently displayed force curve retraction
81 column = self.GetIntFromConfig('procplots', 'derivplot', 'column')
82 row = self.GetIntFromConfig('procplots', 'derivplot', 'row')
83 select = self.GetBoolFromConfig('procplots', 'derivplot', 'select')
84 whatset_str = self.GetStringFromConfig('procplots', 'derivplot', 'whatset')
86 if whatset_str == 'extension':
87 whatset = [lh.EXTENSION]
88 if whatset_str == 'retraction':
89 whatset = [lh.RETRACTION]
90 if whatset_str == 'both':
91 whatset = [lh.EXTENSION, lh.RETRACTION]
93 #TODO: add option to keep previous derivplot
94 plot = self.GetDisplayedPlotCorrected()
97 deriv_curve = copy.deepcopy(plot.curves[index])
98 deriv_curve.x = deriv_curve.x[:-1]
99 deriv_curve.y = diff(deriv_curve.y).tolist()
101 deriv_curve.destination.column = column
102 deriv_curve.destination.row = row
103 deriv_curve.title = 'Discrete differentiation'
104 deriv_curve.units.y += ' ' + deriv_curve.units.x + '-1'
105 plot.curves.append(deriv_curve)
107 self.UpdatePlot(plot)
109 def do_subtplot(self):
112 (procplots.py plugin)
113 Plots the difference between retraction and extension of the currently displayed curve
117 #TODO: what is sub_filter supposed to do?
119 #TODO: add option to keep previous subtplot
120 plot = self.GetDisplayedPlotCorrected()
122 extension = plot.curves[lh.EXTENSION]
123 retraction = plot.curves[lh.RETRACTION]
125 extension, retraction = self.subtract_curves(extension, retraction)
127 self.UpdatePlot(plot)
129 def subtract_curves(self, minuend, subtrahend):
131 calculates: difference = minuend - subtrahend
132 (usually: extension - retraction
135 #we want the same number of points for minuend and subtrahend
136 #TODO: is this not already done when normalizing in the driver?
137 maxpoints_tot = min(len(minuend.x), len(subtrahend.x))
138 minuend.x = minuend.x[0:maxpoints_tot]
139 minuend.y = minuend.y[0:maxpoints_tot]
140 subtrahend.x = subtrahend.x[0:maxpoints_tot]
141 subtrahend.y = subtrahend.y[0:maxpoints_tot]
143 subtrahend.y = [y_subtrahend - y_minuend for y_subtrahend, y_minuend in zip(subtrahend.y, minuend.y)]
144 minuend.y = [0] * len(minuend.x)
146 return minuend, subtrahend
148 #-----PLOT MANIPULATORS
149 def plotmanip_median(self, plot, current, customvalue=False):
151 does the median of the y values of a plot
153 median_filter = self.GetIntFromConfig('procplots', 'median')
154 if median_filter == 0:
157 if float(median_filter) / 2 == int(median_filter) / 2:
160 for curve in plot.curves:
161 curve.y = medfilt(curve.y, median_filter).tolist()
165 def plotmanip_correct(self, plot, current, customvalue=False):
167 does the correction for the deflection for a force spectroscopy curve.
169 - the current plot has a deflection() method that returns a vector of values
170 - the deflection() vector is as long as the X of extension + the X of retraction
171 - plot.vectors[0][0] is the X of extension curve
172 - plot.vectors[1][0] is the X of retraction curve
174 FIXME: both this method and the picoforce driver have to be updated, deflection() must return
175 a more sensible data structure!
177 #use only for force spectroscopy experiments!
178 if current.driver.experiment != 'smfs':
182 customvalue = self.GetBoolFromConfig('procplots', 'correct')
186 defl_ext, defl_ret = current.driver.deflection()
188 plot.curves[lh.EXTENSION].x = [(zpoint - deflpoint) for zpoint,deflpoint in zip(plot.curves[lh.EXTENSION].x, defl_ext)]
189 plot.curves[lh.RETRACTION].x = [(zpoint - deflpoint) for zpoint,deflpoint in zip(plot.curves[lh.RETRACTION].x, defl_ret)]
193 #FFT---------------------------
194 def fft_plot(self, curve, boundaries=[0, -1]):
196 calculates the fast Fourier transform for the selected vector in the plot
199 fftlen = len(curve.y[boundaries[0]:boundaries[1]]) / 2 #need just 1/2 of length
200 curve.x = arange(1, fftlen).tolist()
203 curve.y = abs(fft(curve.y[boundaries[0]:boundaries[1]])[1:fftlen]).tolist()
204 except TypeError: #we take care of newer NumPy (1.0.x)
205 curve.y = abs(fft.fft(curve.y[boundaries[0]:boundaries[1]])[1:fftlen]).tolist()
212 (procplots.py plugin)
213 Plots the fast Fourier transform of the selected plot
215 Syntax: fft [top,bottom] [select] [0,1...]
217 By default, fft performs the Fourier transform on all the 0-th data set on the
220 [top, bottom]: which plot is the data set to fft (default: top)
221 [select]: you pick up two points on the plot and fft only the segment between
222 [0,1,...]: which data set on the selected plot you want to fft (default: 0)
225 column = self.GetIntFromConfig('procplots', 'fft', 'column')
226 row = self.GetIntFromConfig('procplots', 'fft', 'row')
227 select = self.GetBoolFromConfig('procplots', 'fft', 'select')
228 whatset_str = self.GetStringFromConfig('procplots', 'fft', 'whatset')
230 if whatset_str == 'extension':
231 whatset = [lh.EXTENSION]
232 if whatset_str == 'retraction':
233 whatset = [lh.RETRACTION]
234 if whatset_str == 'both':
235 whatset = [lh.EXTENSION, lh.RETRACTION]
238 points = self._measure_N_points(N=2, message='Please select a region by clicking on the start and the end point.', whatset=1)
239 boundaries = [points[0].index, points[1].index]
244 #TODO: add option to keep previous FFT
245 plot = self.GetDisplayedPlotCorrected()
247 for index in whatset:
248 fft_curve = self.fft_plot(copy.deepcopy(plot.curves[index]), boundaries)
250 fft_curve.destination.column = column
251 fft_curve.destination.row = row
252 fft_curve.title = 'FFT'
253 fft_curve.units.x = 'frequency'
254 fft_curve.units.y = 'power'
255 plot.curves.append(fft_curve)
257 self.UpdatePlot(plot)