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, median
20 from scipy.signal import medfilt
22 from lib.peakspot import conv_dx
23 import lib.prettyformat
25 class procplotsCommands:
30 def do_convplot(self):
34 Plots the convolution data of the currently displayed force curve retraction.
40 #need to convert the string that contains the list into a list
41 column = self.GetIntFromConfig('procplots', 'convplot', 'column')
42 convolution = eval(self.GetStringFromConfig('procplots', 'convplot', 'convolution'))
43 row = self.GetIntFromConfig('procplots', 'convplot', 'row')
44 whatset_str = self.GetStringFromConfig('procplots', 'convplot', 'whatset')
46 if whatset_str == 'extension':
47 whatset = [lh.EXTENSION]
48 if whatset_str == 'retraction':
49 whatset = [lh.RETRACTION]
50 if whatset_str == 'both':
51 whatset = [lh.EXTENSION, lh.RETRACTION]
53 #TODO: add option to keep previous derivplot
54 plot = self.GetDisplayedPlotCorrected()
57 conv_curve = copy.deepcopy(plot.curves[index])
58 #Calculate convolution
59 conv_curve.y = conv_dx(plot.curves[index].y, convolution)
61 conv_curve.destination.column = column
62 conv_curve.destination.row = row
63 conv_curve.title = 'Convolution'
64 plot.curves.append(conv_curve)
66 #warn if no flattening has been done.
67 if not self.AppliesPlotmanipulator('flatten'):
68 self.AppendToOutput('Flatten manipulator was not applied. Processing was done without flattening.')
69 self.AppendToOutput('Enable the flatten plotmanipulator for better results.')
73 def do_derivplot(self):
75 Plots the discrete differentiation of the currently displayed force curve.
77 column = self.GetIntFromConfig('procplots', 'derivplot', 'column')
78 row = self.GetIntFromConfig('procplots', 'derivplot', 'row')
79 #TODO: what os select good for?
80 select = self.GetBoolFromConfig('procplots', 'derivplot', 'select')
81 whatset_str = self.GetStringFromConfig('procplots', 'derivplot', 'whatset')
83 if whatset_str == 'extension':
84 whatset = [lh.EXTENSION]
85 if whatset_str == 'retraction':
86 whatset = [lh.RETRACTION]
87 if whatset_str == 'both':
88 whatset = [lh.EXTENSION, lh.RETRACTION]
90 #TODO: add option to keep previous derivplot
91 plot = self.GetDisplayedPlotCorrected()
94 deriv_curve = copy.deepcopy(plot.curves[index])
95 deriv_curve.x = deriv_curve.x[:-1]
96 deriv_curve.y = diff(deriv_curve.y).tolist()
98 deriv_curve.destination.column = column
99 deriv_curve.destination.row = row
100 deriv_curve.title = 'Discrete differentiation'
101 deriv_curve.units.y += ' ' + deriv_curve.units.x + '-1'
102 plot.curves.append(deriv_curve)
104 self.UpdatePlot(plot)
108 Replots the current force curve from scratch eliminating any secondary plots.
112 def do_subtplot(self):
115 (procplots.py plugin)
116 Plots the difference between retraction and extension of the currently displayed curve
121 #TODO: add option to keep previous subtplot
122 plot = self.GetDisplayedPlotCorrected()
124 extension = plot.curves[lh.EXTENSION]
125 retraction = plot.curves[lh.RETRACTION]
127 extension, retraction = self.subtract_curves(extension, retraction)
129 self.UpdatePlot(plot)
131 def subtract_curves(self, minuend, subtrahend):
133 calculates: difference = minuend - subtrahend
134 (usually: extension - retraction
137 #we want the same number of points for minuend and subtrahend
138 #TODO: is this not already done when normalizing in the driver?
139 maxpoints_tot = min(len(minuend.x), len(subtrahend.x))
140 minuend.x = minuend.x[0:maxpoints_tot]
141 minuend.y = minuend.y[0:maxpoints_tot]
142 subtrahend.x = subtrahend.x[0:maxpoints_tot]
143 subtrahend.y = subtrahend.y[0:maxpoints_tot]
145 subtrahend.y = [y_subtrahend - y_minuend for y_subtrahend, y_minuend in zip(subtrahend.y, minuend.y)]
146 minuend.y = [0] * len(minuend.x)
148 return minuend, subtrahend
150 #-----PLOT MANIPULATORS
151 def plotmanip_median(self, plot, current, customvalue=False):
153 does the median of the y values of a plot
155 median_filter = self.GetIntFromConfig('procplots', 'median')
156 if median_filter == 0:
159 if float(median_filter) / 2 == int(median_filter) / 2:
162 for curve in plot.curves:
163 curve.y = medfilt(curve.y, median_filter).tolist()
167 def plotmanip_correct(self, plot, current, customvalue=False):
169 does the correction for the deflection for a force spectroscopy curve.
171 - the current plot has a deflection() method that returns a vector of values
172 - the deflection() vector is as long as the X of extension + the X of retraction
173 - plot.vectors[0][0] is the X of extension curve
174 - plot.vectors[1][0] is the X of retraction curve
176 FIXME: both this method and the picoforce driver have to be updated, deflection() must return
177 a more sensible data structure!
179 #use only for force spectroscopy experiments!
180 if current.driver.experiment != 'smfs':
184 customvalue = self.GetBoolFromConfig('procplots', 'correct')
188 defl_ext, defl_ret = current.driver.deflection()
190 plot.curves[lh.EXTENSION].x = [(zpoint - deflpoint) for zpoint,deflpoint in zip(plot.curves[lh.EXTENSION].x, defl_ext)]
191 plot.curves[lh.RETRACTION].x = [(zpoint - deflpoint) for zpoint,deflpoint in zip(plot.curves[lh.RETRACTION].x, defl_ret)]
195 def plotmanip_centerzero(self, plot, current, customvalue=False):
197 Centers the force curve so the median (the free level) corresponds to 0 N
199 #use only for force spectroscopy experiments!
200 if current.driver.experiment != 'smfs':
204 customvalue = self.GetBoolFromConfig('procplots', 'centerzero')
208 levelapp = float(median(plot.curves[lh.EXTENSION].y))
209 levelret = float(median(plot.curves[lh.RETRACTION].y))
211 level = (levelapp + levelret)/2
213 plot.curves[lh.EXTENSION].y = [i-level for i in plot.curves[lh.EXTENSION].y]
214 plot.curves[lh.RETRACTION].y = [i-level for i in plot.curves[lh.RETRACTION].y]
218 #FFT---------------------------
219 def fft_plot(self, curve, boundaries=[0, -1]):
221 calculates the fast Fourier transform for the selected vector in the plot
224 fftlen = len(curve.y[boundaries[0]:boundaries[1]]) / 2 #need just 1/2 of length
225 curve.x = arange(1, fftlen).tolist()
228 curve.y = abs(fft(curve.y[boundaries[0]:boundaries[1]])[1:fftlen]).tolist()
229 except TypeError: #we take care of newer NumPy (1.0.x)
230 curve.y = abs(fft.fft(curve.y[boundaries[0]:boundaries[1]])[1:fftlen]).tolist()
237 (procplots.py plugin)
238 Plots the fast Fourier transform of the selected plot
240 Syntax: fft [top,bottom] [select] [0,1...]
242 By default, fft performs the Fourier transform on all the 0-th data set on the
245 [top, bottom]: which plot is the data set to fft (default: top)
246 [select]: you pick up two points on the plot and fft only the segment between
247 [0,1,...]: which data set on the selected plot you want to fft (default: 0)
250 column = self.GetIntFromConfig('procplots', 'fft', 'column')
251 row = self.GetIntFromConfig('procplots', 'fft', 'row')
252 select = self.GetBoolFromConfig('procplots', 'fft', 'select')
253 whatset_str = self.GetStringFromConfig('procplots', 'fft', 'whatset')
255 if whatset_str == 'extension':
256 whatset = [lh.EXTENSION]
257 if whatset_str == 'retraction':
258 whatset = [lh.RETRACTION]
259 if whatset_str == 'both':
260 whatset = [lh.EXTENSION, lh.RETRACTION]
263 points = self._measure_N_points(N=2, message='Please select a region by clicking on the start and the end point.', whatset=lh.RETRACTION)
264 boundaries = [points[0].index, points[1].index]
269 #TODO: add option to keep previous FFT
270 plot = self.GetDisplayedPlotCorrected()
272 for index in whatset:
273 fft_curve = self.fft_plot(copy.deepcopy(plot.curves[index]), boundaries)
275 fft_curve.decimals.x = 3
276 fft_curve.decimals.y = 0
277 fft_curve.destination.column = column
278 fft_curve.destination.row = row
279 fft_curve.label = plot.curves[index].label
280 fft_curve.legend = True
281 fft_curve.prefix.x = lib.prettyformat.get_prefix(max(fft_curve.x))
282 fft_curve.prefix.y = lib.prettyformat.get_prefix(max(fft_curve.y))
283 fft_curve.title = 'FFT'
284 fft_curve.units.x = 'Hz'
285 fft_curve.units.y = 'power'
286 plot.curves.append(fft_curve)
288 self.UpdatePlot(plot)