3 from libhooke import WX_GOOD, ClickedPoint
5 wxversion.select(WX_GOOD)
6 from wx import PostEvent
14 warnings.simplefilter('ignore',np.RankWarning)
17 class autopeakCommands:
19 def do_autopeak(self,args):
23 Automatically performs a number of analyses on the peaks of the given curve.
24 Currently it automatically:
25 - fits peaks with WLC function
26 - measures peak maximum forces with a baseline
27 - measures slope in proximity of peak maximum
28 Requires flatten plotmanipulator , fit.py plugin , flatfilts.py plugin with convfilt
31 autopeak [rebase] [pl=value] [t=value] [noauto] [reclick]
33 rebase : Re-asks baseline interval
35 pl=[value] : Use a fixed persistent length for the fit. If pl is not given,
36 the fit will be a 2-variable
37 fit. DO NOT put spaces between 'pl', '=' and the value.
38 The value must be in meters.
39 Scientific notation like 0.35e-9 is fine.
41 t=[value] : Use a user-defined temperature. The value must be in
42 kelvins; by default it is 293 K.
43 DO NOT put spaces between 't', '=' and the value.
45 noauto : allows for clicking the contact point by
46 hand (otherwise it is automatically estimated) the first time.
47 If subsequent measurements are made, the same contact point
48 clicked the first time is used
50 reclick : redefines by hand the contact point, if noauto has been used before
51 but the user is unsatisfied of the previously choosen contact point.
53 usepoints : fit interval by number of points instead than by nanometers
55 When you first issue the command, it will ask for the filename. If you are giving the filename
56 of an existing file, autopeak will resume it and append measurements to it. If you are giving
57 a new filename, it will create the file and append to it until you close Hooke.
60 Useful variables (to set with SET command):
62 temperature= temperature of the system for wlc fit (in K)
64 auto_slope_span = number of points on which measure the slope, for slope
66 auto_fit_nm = number of nm to fit before the peak maximum, for WLC (if usepoints false)
67 auto_fit_points = number of points to fit before the peak maximum, for WLC (if usepoints true)
69 baseline_clicks = 0: automatic baseline
70 1: decide baseline with a single click and length defined in auto_left_baseline
71 2: let user click points of baseline
72 auto_left_baseline = length in nm to use as baseline from the right point (if baseline_clicks=0 , 1)
73 auto_right_baseline = distance in nm of peak-most baseline point from last peak (if baseline_clicks = 0)
77 #FIXME: to move outside function
78 def fit_interval_nm(start_index,plot,nm,backwards):
80 Calculates the number of points to fit, given a fit interval in nm
81 start_index: index of point
83 backwards: if true, finds a point backwards.
85 x_vect=plot.vectors[1][0]
89 start=x_vect[start_index]
91 while abs(x_vect[i]-x_vect[start_index])*(10**9) < nm:
92 if i==0 or i==maxlen-1: #we reached boundaries of vector!
102 def pickup_contact_point():
103 '''macro to pick up the contact point by clicking'''
104 contact_point=self._measure_N_points(N=1, whatset=1)[0]
105 contact_point_index=contact_point.index
106 self.wlccontact_point=contact_point
107 self.wlccontact_index=contact_point.index
108 self.wlccurrent=self.current.path
109 return contact_point, contact_point_index
111 def find_current_peaks():
113 defplot=self.current.curve.default_plots()[0]
114 flatten=self._find_plotmanip('flatten') #Extract flatten plotmanip
115 defplot=flatten(defplot, self.current, customvalue=1) #Flatten curve before feeding it to has_peaks
116 peak_location,peak_size=self.has_peaks(defplot, self.convfilt_config['mindeviation'])
117 return peak_location, peak_size
119 #default fit etc. variables
121 T=self.config['temperature']
123 slope_span=int(self.config['auto_slope_span'])
125 rebase=False #if true=we select rebase
127 #initialize output data vectors
136 displayed_plot=self._get_displayed_plot(0)
138 #COMMAND LINE PARSING
139 #--Using points instead of nm interval
140 if 'usepoints' in args.split():
141 fit_points=int(self.config['auto_fit_points'])
146 #--Recalculate baseline
147 if 'rebase' in args or (self.basecurrent != self.current.path):
150 #--Custom persistent length / custom temperature
151 for arg in args.split():
152 #look for a persistent length argument.
154 pl_expression=arg.split('=')
155 pl_value=float(pl_expression[1]) #actual value
156 #look for a T argument. FIXME: spaces are not allowed between 'pl' and value
157 if ('t=' in arg[0:2]) or ('T=' in arg[0:2]):
158 t_expression=arg.split('=')
159 T=float(t_expression[1])
160 #--Contact point arguments
161 if 'reclick' in args.split():
162 print 'Click contact point'
163 contact_point, contact_point_index = pickup_contact_point()
164 elif 'noauto' in args.split():
165 if self.wlccontact_index==None or self.wlccurrent != self.current.path:
166 print 'Click contact point'
167 contact_point , contact_point_index = pickup_contact_point()
169 contact_point=self.wlccontact_point
170 contact_point_index=self.wlccontact_index
172 #Automatically find contact point
173 cindex=self.find_contact_point()
174 contact_point=self._clickize(displayed_plot.vectors[1][0], displayed_plot.vectors[1][1], cindex)
175 #--END COMMAND LINE PARSING--
178 peak_location, peak_size = find_current_peaks()
180 fitplot=copy.deepcopy(displayed_plot)
182 #Pick up force baseline
184 clicks=self.config['baseline_clicks']
187 base_index_0=peak_location[-1]+fit_interval_nm(peak_location[-1], displayed_plot, self.config['auto_right_baseline'],False)
188 self.basepoints.append(self._clickize(displayed_plot.vectors[1][0],displayed_plot.vectors[1][1],base_index_0))
189 base_index_1=self.basepoints[0].index+fit_interval_nm(self.basepoints[0].index, displayed_plot, self.config['auto_left_baseline'],False)
190 self.basepoints.append(self._clickize(displayed_plot.vectors[1][0],displayed_plot.vectors[1][1],base_index_1))
192 print 'Select baseline'
194 self.basepoints=self._measure_N_points(N=1, whatset=whatset)
195 base_index_1=self.basepoints[0].index+fit_interval_nm(self.basepoints[0].index, displayed_plot, self.config['auto_left_baseline'], False)
196 self.basepoints.append(self._clickize(displayed_plot.vectors[1][0],displayed_plot.vectors[1][1],base_index_1))
198 self.basepoints=self._measure_N_points(N=2, whatset=whatset)
200 self.basecurrent=self.current.path
202 boundaries=[self.basepoints[0].index, self.basepoints[1].index]
204 to_average=displayed_plot.vectors[1][1][boundaries[0]:boundaries[1]] #y points to average
205 avg=np.mean(to_average)
208 for peak in peak_location:
212 fit_points=fit_interval_nm(peak, displayed_plot, self.config['auto_fit_nm'], True)
213 peak_point=self._clickize(displayed_plot.vectors[1][0],displayed_plot.vectors[1][1],peak)
214 other_fit_point=self._clickize(displayed_plot.vectors[1][0],displayed_plot.vectors[1][1],peak-fit_points)
217 points=[contact_point, peak_point, other_fit_point]
219 if abs(peak_point.index-other_fit_point.index) < 2:
222 params, yfit, xfit, fit_errors = self.wlc_fit(points, displayed_plot.vectors[1][0], displayed_plot.vectors[1][1], pl_value, T, return_errors=True)
226 delta_to_measure=displayed_plot.vectors[1][1][peak-delta_force:peak+delta_force]
227 y=min(delta_to_measure)
228 #save force values (pN)
230 slope=self.linefit_between(peak-slope_span,peak)[0]
233 #check fitted data and, if right, add peak to the measurement
234 #FIXME: code duplication
235 if len(params)==1: #if we did choose 1-value fit
236 p_lengths.append(pl_value)
237 c_lengths.append(params[0]*(1.0e+9))
238 sigma_p_lengths.append(0)
239 sigma_c_lengths.append(fit_errors[0]*(1.0e+9))
240 forces.append(abs(y-avg)*(1.0e+12))
242 #Add WLC fit lines to plot
243 fitplot.add_set(xfit,yfit)
244 if len(fitplot.styles)==0:
247 fitplot.styles.append(None)
249 p_leng=params[1]*(1.0e+9)
250 #check if persistent length makes sense. otherwise, discard peak.
251 if p_leng>self.config['auto_min_p'] and p_leng<self.config['auto_max_p']:
252 p_lengths.append(p_leng)
253 c_lengths.append(params[0]*(1.0e+9))
254 sigma_c_lengths.append(fit_errors[0]*(1.0e+9))
255 sigma_p_lengths.append(fit_errors[1]*(1.0e+9))
256 forces.append(abs(y-avg)*(1.0e+12))
259 #Add WLC fit lines to plot
260 fitplot.add_set(xfit,yfit)
261 if len(fitplot.styles)==0:
264 fitplot.styles.append(None)
269 #add basepoints to fitplot
270 fitplot.add_set([self.basepoints[0].graph_coords[0],self.basepoints[1].graph_coords[0]],[self.basepoints[0].graph_coords[1],self.basepoints[1].graph_coords[1]])
271 fitplot.styles.append('scatter')
274 #Show wlc fits and peak locations
275 self._send_plot([fitplot])
279 #Ask the user what peaks to ignore from analysis.
280 print 'Peaks to ignore (0,1...n from contact point,return to take all)'
281 print 'N to discard measurement'
282 exclude_raw=raw_input('Input:')
286 if not exclude_raw=='':
287 exclude=exclude_raw.split(',')
289 exclude=[int(item) for item in exclude]
295 sigma_c_lengths[i]=None
296 sigma_p_lengths[i]=None
298 print 'Bad input, taking all...'
299 #Clean data vectors from ignored peaks
300 #FIXME:code duplication
301 c_lengths=[item for item in c_lengths if item != None]
302 p_lengths=[item for item in p_lengths if item != None]
303 forces=[item for item in forces if item != None]
304 slopes=[item for item in slopes if item != None]
305 sigma_c_lengths=[item for item in sigma_c_lengths if item != None]
306 sigma_p_lengths=[item for item in sigma_p_lengths if item != None]
308 print 'contour (nm)',c_lengths
309 print 'sigma contour (nm)',sigma_c_lengths
310 print 'p (nm)',p_lengths
311 print 'sigma p (nm)',sigma_p_lengths
312 print 'forces (pN)',forces
313 print 'slopes (N/m)',slopes
316 if self.autofile=='':
317 self.autofile=raw_input('Autopeak filename? (return to ignore) ')
318 if self.autofile=='':
322 if not os.path.exists(self.autofile):
323 f=open(self.autofile,'w+')
324 f.write('Analysis started '+time.asctime()+'\n')
325 f.write('----------------------------------------\n')
326 f.write('; Contour length (nm) ; Persistence length (nm) ; Max.Force (pN) ; Slope (N/m) ; Sigma contour (nm) ; Sigma persistence (nm)\n')
330 f=open(self.autofile,'a+')
332 f.write(self.current.path+'\n')
333 for i in range(len(c_lengths)):
334 f.write(' ; '+str(c_lengths[i])+' ; '+str(p_lengths[i])+' ; '+str(forces[i])+' ; '+str(slopes[i])+' ; '+str(sigma_c_lengths[i])+' ; '+str(sigma_p_lengths[i])+'\n')
337 self.do_note('autopeak')