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 whatset=1 #FIXME: should be decidable
86 x_vect=plot.vectors[1][0]
90 start=x_vect[start_index]
92 while abs(x_vect[i]-x_vect[start_index])*(10**9) < nm:
93 if i==0 or i==maxlen-1: #we reached boundaries of vector!
103 def pickup_contact_point():
104 '''macro to pick up the contact point by clicking'''
105 contact_point=self._measure_N_points(N=1, whatset=1)[0]
106 contact_point_index=contact_point.index
107 self.wlccontact_point=contact_point
108 self.wlccontact_index=contact_point.index
109 self.wlccurrent=self.current.path
110 return contact_point, contact_point_index
112 def find_current_peaks():
114 defplot=self.current.curve.default_plots()[0]
115 flatten=self._find_plotmanip('flatten') #Extract flatten plotmanip
116 defplot=flatten(defplot, self.current, customvalue=1) #Flatten curve before feeding it to has_peaks
117 peak_location,peak_size=self.has_peaks(defplot, self.convfilt_config['mindeviation'])
118 return peak_location, peak_size
120 #default fit etc. variables
122 T=self.config['temperature']
124 slope_span=int(self.config['auto_slope_span'])
126 rebase=False #if true=we select rebase
128 #initialize output data vectors
137 displayed_plot=self._get_displayed_plot(0)
139 #COMMAND LINE PARSING
140 #--Using points instead of nm interval
141 if 'usepoints' in args.split():
142 fit_points=int(self.config['auto_fit_points'])
147 #--Recalculate baseline
148 if 'rebase' in args or (self.basecurrent != self.current.path):
151 #--Custom persistent length / custom temperature
152 for arg in args.split():
153 #look for a persistent length argument.
155 pl_expression=arg.split('=')
156 pl_value=float(pl_expression[1]) #actual value
157 #look for a T argument. FIXME: spaces are not allowed between 'pl' and value
158 if ('t=' in arg[0:2]) or ('T=' in arg[0:2]):
159 t_expression=arg.split('=')
160 T=float(t_expression[1])
161 #--Contact point arguments
162 if 'reclick' in args.split():
163 print 'Click contact point'
164 contact_point, contact_point_index = pickup_contact_point()
165 elif 'noauto' in args.split():
166 if self.wlccontact_index==None or self.wlccurrent != self.current.path:
167 print 'Click contact point'
168 contact_point , contact_point_index = pickup_contact_point()
170 contact_point=self.wlccontact_point
171 contact_point_index=self.wlccontact_index
173 #Automatically find contact point
174 cindex=self.find_contact_point()
175 contact_point=self._clickize(displayed_plot.vectors[1][0], displayed_plot.vectors[1][1], cindex)
176 #--END COMMAND LINE PARSING--
179 peak_location, peak_size = find_current_peaks()
181 if len(peak_location) == 0:
182 print 'No peaks to fit.'
185 fitplot=copy.deepcopy(displayed_plot)
187 #Pick up force baseline
189 clicks=self.config['baseline_clicks']
192 base_index_0=peak_location[-1]+fit_interval_nm(peak_location[-1], displayed_plot, self.config['auto_right_baseline'],False)
193 self.basepoints.append(self._clickize(displayed_plot.vectors[1][0],displayed_plot.vectors[1][1],base_index_0))
194 base_index_1=self.basepoints[0].index+fit_interval_nm(self.basepoints[0].index, displayed_plot, self.config['auto_left_baseline'],False)
195 self.basepoints.append(self._clickize(displayed_plot.vectors[1][0],displayed_plot.vectors[1][1],base_index_1))
197 print 'Select baseline'
199 self.basepoints=self._measure_N_points(N=1, whatset=whatset)
200 base_index_1=self.basepoints[0].index+fit_interval_nm(self.basepoints[0].index, displayed_plot, self.config['auto_left_baseline'], False)
201 self.basepoints.append(self._clickize(displayed_plot.vectors[1][0],displayed_plot.vectors[1][1],base_index_1))
203 self.basepoints=self._measure_N_points(N=2, whatset=whatset)
205 self.basecurrent=self.current.path
207 boundaries=[self.basepoints[0].index, self.basepoints[1].index]
209 to_average=displayed_plot.vectors[1][1][boundaries[0]:boundaries[1]] #y points to average
210 avg=np.mean(to_average)
213 for peak in peak_location:
217 fit_points=fit_interval_nm(peak, displayed_plot, self.config['auto_fit_nm'], True)
218 peak_point=self._clickize(displayed_plot.vectors[1][0],displayed_plot.vectors[1][1],peak)
219 other_fit_point=self._clickize(displayed_plot.vectors[1][0],displayed_plot.vectors[1][1],peak-fit_points)
222 points=[contact_point, peak_point, other_fit_point]
224 if abs(peak_point.index-other_fit_point.index) < 2:
227 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)
231 delta_to_measure=displayed_plot.vectors[1][1][peak-delta_force:peak+delta_force]
232 y=min(delta_to_measure)
233 #save force values (pN)
235 slope=self.linefit_between(peak-slope_span,peak)[0]
238 #check fitted data and, if right, add peak to the measurement
239 #FIXME: code duplication
240 if len(params)==1: #if we did choose 1-value fit
241 p_lengths.append(pl_value)
242 c_lengths.append(params[0]*(1.0e+9))
243 sigma_p_lengths.append(0)
244 sigma_c_lengths.append(fit_errors[0]*(1.0e+9))
245 forces.append(abs(y-avg)*(1.0e+12))
247 #Add WLC fit lines to plot
248 fitplot.add_set(xfit,yfit)
249 if len(fitplot.styles)==0:
253 fitplot.styles.append(None)
254 fitplot.colors.append(None)
256 p_leng=params[1]*(1.0e+9)
257 #check if persistent length makes sense. otherwise, discard peak.
258 if p_leng>self.config['auto_min_p'] and p_leng<self.config['auto_max_p']:
259 p_lengths.append(p_leng)
260 c_lengths.append(params[0]*(1.0e+9))
261 sigma_c_lengths.append(fit_errors[0]*(1.0e+9))
262 sigma_p_lengths.append(fit_errors[1]*(1.0e+9))
263 forces.append(abs(y-avg)*(1.0e+12))
266 #Add WLC fit lines to plot
267 fitplot.add_set(xfit,yfit)
268 if len(fitplot.styles)==0:
272 fitplot.styles.append(None)
273 fitplot.colors.append(None)
278 #add basepoints to fitplot
279 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]])
280 fitplot.styles.append('scatter')
281 fitplot.colors.append(None)
283 #Show wlc fits and peak locations
284 self._send_plot([fitplot])
287 print 'Measurements for all peaks detected:'
288 print 'contour (nm)', c_lengths
289 print 'sigma contour (nm)',sigma_c_lengths
290 print 'p (nm)',p_lengths
291 print 'sigma p (nm)',sigma_p_lengths
292 print 'forces (pN)',forces
293 print 'slopes (N/m)',slopes
295 #Ask the user what peaks to ignore from analysis.
296 print 'Peaks to ignore (0,1...n from contact point,return to take all)'
297 print 'N to discard measurement'
298 exclude_raw=raw_input('Input:')
302 if not exclude_raw=='':
303 exclude=exclude_raw.split(',')
305 exclude=[int(item) for item in exclude]
311 sigma_c_lengths[i]=None
312 sigma_p_lengths[i]=None
314 print 'Bad input, taking all...'
315 #Clean data vectors from ignored peaks
316 #FIXME:code duplication
317 c_lengths=[item for item in c_lengths if item != None]
318 p_lengths=[item for item in p_lengths if item != None]
319 forces=[item for item in forces if item != None]
320 slopes=[item for item in slopes if item != None]
321 sigma_c_lengths=[item for item in sigma_c_lengths if item != None]
322 sigma_p_lengths=[item for item in sigma_p_lengths if item != None]
324 print 'Measurements for chosen peaks:'
325 print 'contour (nm)',c_lengths
326 print 'sigma contour (nm)',sigma_c_lengths
327 print 'p (nm)',p_lengths
328 print 'sigma p (nm)',sigma_p_lengths
329 print 'forces (pN)',forces
330 print 'slopes (N/m)',slopes
333 if self.autofile=='':
334 self.autofile=raw_input('Autopeak filename? (return to ignore) ')
335 if self.autofile=='':
339 if not os.path.exists(self.autofile):
340 f=open(self.autofile,'w+')
341 f.write('Analysis started '+time.asctime()+'\n')
342 f.write('----------------------------------------\n')
343 f.write('; Contour length (nm) ; Persistence length (nm) ; Max.Force (pN) ; Slope (N/m) ; Sigma contour (nm) ; Sigma persistence (nm)\n')
347 f=open(self.autofile,'a+')
349 f.write(self.current.path+'\n')
350 for i in range(len(c_lengths)):
351 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')
354 self.do_note('autopeak')