6 Force spectroscopy curves basic fitting plugin.
9 procplots.py (plot processing plugin)
12 with modifications by Dr. Rolf Schmidt (Concordia University, Canada)
14 This program is released under the GNU General Public License version 2.
17 import lib.libhooke as lh
19 wxversion.select(lh.WX_GOOD)
27 class fitCommands(object):
29 Do not use any of the following commands directly:
33 These commands are not implemented properly yet. However, the properties you set for these commands are used for the autopeak command.
38 self.wlccontact_point=None
39 self.wlccontact_index=None
41 def wlc_fit(self, clicked_points, xvector, yvector, pl_value, T=293, return_errors=False):
43 Worm-like chain model fitting.
44 The function is the simple polynomial worm-like chain as proposed by C.Bustamante, J.F.Marko, E.D.Siggia
45 and S.Smith (Science. 1994 Sep 9;265(5178):1599-600.)
49 clicked_points[0] = contact point (calculated or hand-clicked)
50 clicked_points[1] and [2] are edges of chunk
53 #STEP 1: Prepare the vectors to apply the fit.
55 if pl_value is not None:
56 pl_value=pl_value/(10**9)
58 #indexes of the selected chunk
59 first_index=min(clicked_points[1].index, clicked_points[2].index)
60 last_index=max(clicked_points[1].index, clicked_points[2].index)
62 #getting the chunk and reverting it
63 xchunk,ychunk=xvector[first_index:last_index],yvector[first_index:last_index]
66 #put contact point at zero and flip around the contact point (the fit wants a positive growth for extension and force)
67 xchunk_corr_up=[-(x-clicked_points[0].graph_coords[0]) for x in xchunk]
68 ychunk_corr_up=[-(y-clicked_points[0].graph_coords[1]) for y in ychunk]
71 xchunk_corr_up=scipy.array(xchunk_corr_up)
72 ychunk_corr_up=scipy.array(ychunk_corr_up)
74 #STEP 2: actually do the fit
76 #Find furthest point of chunk and add it a bit; the fit must converge
78 xchunk_high=max(xchunk_corr_up)
79 xchunk_high+=(xchunk_high/10)
81 #Here are the linearized start parameters for the WLC.
82 #[lambd=1/Lo , pii=1/P]
84 p0=[(1/xchunk_high),(1/(3.5e-10))]
85 p0_plfix=[(1/xchunk_high)]
88 fixme: remove these comments after testing
91 def f_wlc(params,x,T=T):
93 wlc function for ODR fitting
98 y=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd))
101 def f_wlc_plfix(params,x,pl_value=pl_value,T=T):
103 wlc function for ODR fitting
109 y=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd))
113 realdata=scipy.odr.RealData(xchunk_corr_up,ychunk_corr_up)
116 model=scipy.odr.Model(f_wlc_plfix)
117 o = scipy.odr.ODR(realdata, model, p0_plfix)
119 model=scipy.odr.Model(f_wlc)
120 o = scipy.odr.ODR(realdata, model, p0)
122 o.set_job(fit_type=2)
124 fit_out=[(1/i) for i in out.beta]
126 #Calculate fit errors from output standard deviations.
127 #We must propagate the error because we fit the *inverse* parameters!
128 #The error = (error of the inverse)*(value**2)
130 for sd,value in zip(out.sd_beta, fit_out):
131 err_real=sd*(value**2)
132 fit_errors.append(err_real)
134 def wlc_eval(x, params, pl_value, T):
136 Evaluates the WLC function
146 Kb=(1.38065e-23) #Boltzmann constant
147 therm=Kb*T #so we have thermal energy
149 return ((therm*pii / 4.0) * (((1 - (x*lambd))**-2.0) - 1 + (4.0*x*lambd)) )
151 #STEP 3: plotting the fit
153 #obtain domain to plot the fit - from contact point to last_index plus 20 points
154 thule_index=last_index + 1
155 if thule_index > len(xvector): #for rare cases in which we fit something at the END of whole curve.
156 thule_index = len(xvector)
157 #reverse etc. the domain
158 xfit_chunk=xvector[clicked_points[0].index:thule_index]
160 xfit_chunk_corr_up=[-(x-clicked_points[0].graph_coords[0]) for x in xfit_chunk]
161 xfit_chunk_corr_up=scipy.array(xfit_chunk_corr_up)
163 #the fitted curve: reflip, re-uncorrect
164 #x_max = xfit_chunk_corr_up[-1]
165 #x_min = xfit_chunk_corr_up[0]
167 #increment = (x_max - x_min) / (points_in_fit - 1)
168 #x_help = [x_min + x * increment for x in range(points_in_fit)]
169 #xfit_chunk = [x_min + x * increment for x in range(points_in_fit)]
170 #xfit_chunk.reverse()
171 #x_help = scipy.array(x_help)
173 #yfit = wlc_eval(x_help, out.beta, pl_value, T)
175 yfit=wlc_eval(xfit_chunk_corr_up, out.beta, pl_value,T)
176 yfit_down=[-y for y in yfit]
177 yfit_corr_down=[y+clicked_points[0].graph_coords[1] for y in yfit_down]
179 plot = self.GetActivePlot()
182 return fit_out, yfit_corr_down, xfit_chunk, fit_errors
184 return fit_out, yfit_corr_down, xfit_chunk, None
186 def fjc_fit(self, clicked_points, xvector, yvector, pl_value, T=293, return_errors=False):
188 Freely-jointed chain function
189 ref: C.Ray and B.B. Akhremitchev; http://www.chem.duke.edu/~boris/research/force_spectroscopy/fit_efjc.pdf
193 clicked_points[0] = contact point (calculated or hand-clicked)
194 clicked_points[1] and [2] are edges of chunk
197 #STEP 1: Prepare the vectors to apply the fit.
198 if pl_value is not None:
199 pl_value=pl_value/(10**9)
201 #indexes of the selected chunk
202 first_index=min(clicked_points[1].index, clicked_points[2].index)
203 last_index=max(clicked_points[1].index, clicked_points[2].index)
205 #getting the chunk and reverting it
206 xchunk,ychunk=xvector[first_index:last_index],yvector[first_index:last_index]
209 #put contact point at zero and flip around the contact point (the fit wants a positive growth for extension and force)
210 xchunk_corr_up=[-(x-clicked_points[0].graph_coords[0]) for x in xchunk]
211 ychunk_corr_up=[-(y-clicked_points[0].graph_coords[1]) for y in ychunk]
214 xchunk_corr_up=scipy.array(xchunk_corr_up)
215 ychunk_corr_up=scipy.array(ychunk_corr_up)
218 #STEP 2: actually do the fit
220 #Find furthest point of chunk and add it a bit; the fit must converge
222 xchunk_high=max(xchunk_corr_up)
223 xchunk_high+=(xchunk_high/10)
225 #Here are the linearized start parameters for the WLC.
226 #[lambd=1/Lo , pii=1/P]
228 p0=[(1/xchunk_high),(1/(3.5e-10))]
229 p0_plfix=[(1/xchunk_high)]
232 fixme: remove these comments after testing
234 def x_fjc(params,f,T=T):
236 fjc function for ODR fitting
242 #x=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd))
243 x=(1/lambd)*(lh.coth(f*(1/pii)/therm) - (therm*pii)/f)
246 def x_fjc_plfix(params,f,pl_value=pl_value,T=T):
248 fjc function for ODR fitting
254 #y=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd))
255 x=(1/lambd)*(lh.coth(f*(1/pii)/therm) - (therm*pii)/f)
259 realdata=scipy.odr.RealData(ychunk_corr_up,xchunk_corr_up)
261 model=scipy.odr.Model(x_fjc_plfix)
262 o = scipy.odr.ODR(realdata, model, p0_plfix)
264 model=scipy.odr.Model(x_fjc)
265 o = scipy.odr.ODR(realdata, model, p0)
267 o.set_job(fit_type=2)
269 fit_out=[(1/i) for i in out.beta]
271 #Calculate fit errors from output standard deviations.
272 #We must propagate the error because we fit the *inverse* parameters!
273 #The error = (error of the inverse)*(value**2)
275 for sd,value in zip(out.sd_beta, fit_out):
276 err_real=sd*(value**2)
277 fit_errors.append(err_real)
279 def fjc_eval(y, params, pl_value, T):
281 Evaluates the FJC function
291 Kb = (1.38065e-23) #Boltzmann constant
292 therm = Kb * T #so we have thermal energy
293 #return ( (therm*pii/4.0) * (((1-(x*lambd))**-2.0) - 1 + (4.0*x*lambd)) )
294 return (1 / lambd) * (lh.coth(y * (1 / pii) / therm) - (therm * pii) / y)
297 #STEP 3: plotting the fit
299 #obtain domain to plot the fit - from contact point to last_index plus 20 points
300 thule_index=last_index+10
301 if thule_index > len(xvector): #for rare cases in which we fit something at the END of whole curve.
302 thule_index = len(xvector)
303 #reverse etc. the domain
304 ychunk=yvector[clicked_points[0].index:thule_index]
307 y_evalchunk=np.linspace(min(ychunk),max(ychunk),100)
309 #Empty y-chunk. It happens whenever we set the contact point after a recognized peak,
310 #or other buggy situations. Kludge to live with it now...
311 ychunk=yvector[:thule_index]
312 y_evalchunk=np.linspace(min(ychunk),max(ychunk),100)
314 yfit_down=[-y for y in y_evalchunk]
315 yfit_corr_down=[y+clicked_points[0].graph_coords[1] for y in yfit_down]
316 yfit_corr_down=scipy.array(yfit_corr_down)
318 #the fitted curve: reflip, re-uncorrect
319 xfit=fjc_eval(yfit_corr_down, out.beta, pl_value,T)
322 xfit_chunk_corr_up=[-(x-clicked_points[0].graph_coords[0]) for x in xfit]
324 #xfit_chunk_corr_up=scipy.array(xfit_chunk_corr_up)
325 #deltay=yfit_down[0]-yvector[clicked_points[0].index]
327 #This is a terrible, terrible kludge to find the point where it should normalize (and from where it should plot)
329 for index in scipy.arange(1,len(xfit_chunk_corr_up),1):
330 xxxdists.append((clicked_points[0].graph_coords[0]-xfit_chunk_corr_up[index])**2)
331 normalize_index=xxxdists.index(min(xxxdists))
334 deltay=yfit_down[normalize_index]-clicked_points[0].graph_coords[1]
335 yfit_corr_down=[y-deltay for y in yfit_down]
338 #return fit_out, yfit_corr_down, xfit_chunk_corr_up, fit_errors
339 return fit_out, yfit_corr_down[normalize_index+1:], xfit_chunk_corr_up[normalize_index+1:], fit_errors
341 #return fit_out, yfit_corr_down, xfit_chunk_corr_up, None
342 return fit_out, yfit_corr_down[normalize_index+1:], xfit_chunk_corr_up[normalize_index+1:], None
344 def fjcPEG_fit(self, clicked_points, xvector, yvector, pl_value, T=293, return_errors=False):
346 Freely-jointed chain function for PEG-containing molecules
347 ref: C.Ray and B.B. Akhremitchev; http://www.chem.duke.edu/~boris/research/force_spectroscopy/fit_efjc.pdf
351 clicked_points[0] = contact point (calculated or hand-clicked)
352 clicked_points[1] and [2] are edges of chunk
355 #STEP 1: Prepare the vectors to apply the fit.
356 if pl_value is not None:
357 pl_value=pl_value/(10**9)
359 #indexes of the selected chunk
360 first_index=min(clicked_points[1].index, clicked_points[2].index)
361 last_index=max(clicked_points[1].index, clicked_points[2].index)
363 #getting the chunk and reverting it
364 xchunk,ychunk=xvector[first_index:last_index],yvector[first_index:last_index]
367 #put contact point at zero and flip around the contact point (the fit wants a positive growth for extension and force)
368 xchunk_corr_up=[-(x-clicked_points[0].graph_coords[0]) for x in xchunk]
369 ychunk_corr_up=[-(y-clicked_points[0].graph_coords[1]) for y in ychunk]
372 xchunk_corr_up=scipy.array(xchunk_corr_up)
373 ychunk_corr_up=scipy.array(ychunk_corr_up)
375 #STEP 2: actually do the fit
377 #Find furthest point of chunk and add it a bit; the fit must converge
379 xchunk_high=max(xchunk_corr_up)
380 xchunk_high+=(xchunk_high/10)
382 #Here are the linearized start parameters for the WLC.
383 #[lambd=1/Lo , pii=1/P]
385 L_helical = self.GetFloatFromConfig('fit', 'fjcPEG', 'L_helical') #in nm
386 L_planar = self.GetFloatFromConfig('fit', 'fjcPEG', 'L_planar') #in nm
387 delta_G = self.GetFloatFromConfig('fit', 'fjcPEG', 'delta_G') #in Kb*T
389 p0=[(1/xchunk_high),(1/(3.5e-10))]
390 p0_plfix=[(1/xchunk_high)]
393 fixme: remove these comments after testing
395 def x_fjcPEG(params,f,T=T):
397 fjcPEG function for ODR fitting
403 #x=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd))
405 x=(1/lambd)*(1 / (exp(delta_G) + 1) + (L_helical/L_planar) * (1 / (exp(-delta_G) + 1))) * (lh.coth(f*(1/pii)/therm) - (therm*pii)/f)
408 def x_fjcPEG_plfix(params,f,pl_value=pl_value,T=T):
410 fjcPEG function for ODR fitting
416 #y=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd))
417 x=(1/lambd)*(1 / (exp(delta_G) + 1) + (L_helical/L_planar) * (1 / (exp(-delta_G) + 1))) * (lh.coth(f*(1/pii)/therm) - (therm*pii)/f)
421 realdata=scipy.odr.RealData(ychunk_corr_up,xchunk_corr_up)
423 model=scipy.odr.Model(x_fjcPEG_plfix)
424 o = scipy.odr.ODR(realdata, model, p0_plfix)
426 model=scipy.odr.Model(x_fjcPEG)
427 o = scipy.odr.ODR(realdata, model, p0)
429 o.set_job(fit_type=2)
431 fit_out=[(1/i) for i in out.beta]
433 #Calculate fit errors from output standard deviations.
434 #We must propagate the error because we fit the *inverse* parameters!
435 #The error = (error of the inverse)*(value**2)
437 for sd,value in zip(out.sd_beta, fit_out):
438 err_real=sd*(value**2)
439 fit_errors.append(err_real)
441 def fjcPEG_eval(y, params, pl_value, T):
443 Evaluates the fjcPEG function
453 Kb = (1.38065e-23) #Boltzmann constant
454 therm = Kb * T #so we have thermal energy
455 #return ( (therm*pii/4.0) * (((1-(x*lambd))**-2.0) - 1 + (4.0*x*lambd)) )
456 return (1/lambd)*(1 / (exp(delta_G) + 1) + (L_helical/L_planar) * (1 / (exp(-delta_G) + 1))) * (lh.coth(y*(1/pii)/therm) - (therm*pii)/y)
458 #STEP 3: plotting the fit
460 #obtain domain to plot the fit - from contact point to last_index plus 20 points
461 thule_index=last_index+10
462 if thule_index > len(xvector): #for rare cases in which we fit something at the END of whole curve.
463 thule_index = len(xvector)
464 #reverse etc. the domain
465 ychunk=yvector[clicked_points[0].index:thule_index]
468 y_evalchunk=np.linspace(min(ychunk),max(ychunk),100)
470 #Empty y-chunk. It happens whenever we set the contact point after a recognized peak,
471 #or other buggy situations. Kludge to live with it now...
472 ychunk=yvector[:thule_index]
473 y_evalchunk=np.linspace(min(ychunk),max(ychunk),100)
475 yfit_down=[-y for y in y_evalchunk]
476 yfit_corr_down=[y+clicked_points[0].graph_coords[1] for y in yfit_down]
477 yfit_corr_down=scipy.array(yfit_corr_down)
479 #the fitted curve: reflip, re-uncorrect
480 xfit=fjcPEG_eval(yfit_corr_down, out.beta, pl_value,T)
483 xfit_chunk_corr_up=[-(x-clicked_points[0].graph_coords[0]) for x in xfit]
485 #xfit_chunk_corr_up=scipy.array(xfit_chunk_corr_up)
486 #deltay=yfit_down[0]-yvector[clicked_points[0].index]
488 #This is a terrible, terrible kludge to find the point where it should normalize (and from where it should plot)
490 for index in scipy.arange(1,len(xfit_chunk_corr_up),1):
491 xxxdists.append((clicked_points[0].graph_coords[0]-xfit_chunk_corr_up[index])**2)
492 normalize_index=xxxdists.index(min(xxxdists))
495 deltay=yfit_down[normalize_index]-clicked_points[0].graph_coords[1]
496 yfit_corr_down=[y-deltay for y in yfit_down]
499 #return fit_out, yfit_corr_down, xfit_chunk_corr_up, fit_errors
500 return fit_out, yfit_corr_down[normalize_index+1:], xfit_chunk_corr_up[normalize_index+1:], fit_errors
502 #return fit_out, yfit_corr_down, xfit_chunk_corr_up, None
503 return fit_out, yfit_corr_down[normalize_index+1:], xfit_chunk_corr_up[normalize_index+1:], None
505 def do_wlc(self,args):
514 def do_fjc(self,args):
523 def do_fjcPEG(self,args):
528 default values for PEG
529 ----------------------
534 See the fit command for more information
542 Fits an entropic elasticity function to a given chunk of the curve.
544 First you have to click a contact point.
545 Then you have to click the two edges of the data you want to fit.
547 The fit function depends on the fit_function variable. You can set it with the command
548 "set fit_function wlc" or "set fit_function fjc" depending on the function you prefer.
550 For WLC, the function is the simple polynomial worm-like chain as proposed by
551 C.Bustamante, J.F.Marko, E.D.Siggia and S.Smith (Science. 1994
552 Sep 9;265(5178):1599-600.)
555 C.Ray and B.B. Akhremitchev; http://www.chem.duke.edu/~boris/research/force_spectroscopy/fit_efjc.pdf
558 pl=[value] : Use a fixed persistent length (WLC) or Kuhn length (FJC) for the fit. If pl is not given,
559 the fit will be a 2-variable
560 fit. DO NOT put spaces between 'pl', '=' and the value.
561 The value must be in nanometers.
563 t=[value] : Use a user-defined temperature. The value must be in
564 kelvins; by default it is 293 K.
565 DO NOT put spaces between 't', '=' and the value.
567 noauto : allows for clicking the contact point by
568 hand (otherwise it is automatically estimated) the first time.
569 If subsequent measurements are made, the same contact point
572 reclick : redefines by hand the contact point, if noauto has been used before
573 but the user is unsatisfied of the previously choosen contact point.
575 Syntax: fit [pl=(value)] [t=value] [noauto]
578 T = self.config['fit'].as_float['temperature']
579 for arg in args.split():
580 #look for a persistent length argument.
582 pl_expression=arg.split('=')
583 pl_value=float(pl_expression[1]) #actual value
584 #look for a T argument. FIXME: spaces are not allowed between 'pl' and value
585 if ('t=' in arg[0:2]) or ('T=' in arg[0:2]):
586 t_expression=arg.split('=')
587 T=float(t_expression[1])
589 #use the currently displayed plot for the fit
590 displayed_plot=self._get_displayed_plot()
592 #handle contact point arguments correctly
593 if 'reclick' in args.split():
594 print 'Click contact point'
595 contact_point=self._measure_N_points(N=1, whatset=lh.RETRACTION)[0]
596 contact_point_index=contact_point.index
597 self.wlccontact_point=contact_point
598 self.wlccontact_index=contact_point.index
599 self.wlccurrent=self.current.path
600 elif 'noauto' in args.split():
601 if self.wlccontact_index is None or self.wlccurrent != self.current.path:
602 print 'Click contact point'
603 contact_point=self._measure_N_points(N=1, whatset=lh.RETRACTION)[0]
604 contact_point_index=contact_point.index
605 self.wlccontact_point=contact_point
606 self.wlccontact_index=contact_point.index
607 self.wlccurrent=self.current.path
609 contact_point=self.wlccontact_point
610 contact_point_index=self.wlccontact_index
612 cindex=self.find_contact_point()
613 contact_point=lh.ClickedPoint()
614 contact_point.absolute_coords=displayed_plot.vectors[1][0][cindex], displayed_plot.vectors[1][1][cindex]
615 contact_point.find_graph_coords(displayed_plot.vectors[1][0], displayed_plot.vectors[1][1])
616 contact_point.is_marker=True
618 print 'Click edges of chunk'
619 points=self._measure_N_points(N=2, whatset=lh.RETRACTION)
620 points=[contact_point]+points
622 if self.config['fit_function']=='wlc':
623 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 )
624 name_of_charlength='Persistent length'
625 elif self.config['fit_function']=='fjc':
626 params, yfit, xfit, fit_errors = self.fjc_fit(points, displayed_plot.vectors[1][0], displayed_plot.vectors[1][1],pl_value,T, return_errors=True )
627 name_of_charlength='Kuhn length'
628 elif self.config['fit_function']=='fjcPEG':
629 params, yfit, xfit, fit_errors = self.fjcPEG_fit(points, displayed_plot.vectors[1][0], displayed_plot.vectors[1][1],pl_value,T, return_errors=True )
630 name_of_charlength='Kuhn length'
632 print 'No recognized fit function defined!'
633 print 'Set your fit function to wlc or fjc.'
637 print 'Fit not possible. Probably wrong interval -did you click two *different* points?'
640 #FIXME: print "Kuhn length" for FJC
641 print 'Fit function:',self.config['fit_function']
642 print 'Contour length: ',params[0]*(1.0e+9),' nm'
643 to_dump='contour '+self.current.path+' '+str(params[0]*(1.0e+9))+' nm'
644 self.outlet.push(to_dump)
645 if len(params)==2: #if we did choose 2-value fit
646 print name_of_charlength+': ',params[1]*(1.0e+9),' nm'
647 to_dump='persistent '+self.current.path+' '+str(params[1]*(1.0e+9))+' nm'
648 self.outlet.push(to_dump)
651 fit_nm=[i*(10**9) for i in fit_errors]
652 print 'Standard deviation (contour length)', fit_nm[0]
654 print 'Standard deviation ('+name_of_charlength+')', fit_nm[1]
656 #add the clicked points in the final PlotObject
657 clickvector_x, clickvector_y=[], []
659 clickvector_x.append(item.graph_coords[0])
660 clickvector_y.append(item.graph_coords[1])
662 #create a custom PlotObject to gracefully plot the fit along the curves
664 fitplot=copy.deepcopy(displayed_plot)
665 fitplot.add_set(xfit,yfit)
666 fitplot.add_set(clickvector_x,clickvector_y)
668 #FIXME: this colour/styles stuff must be solved at the root!
669 if fitplot.styles==[]:
670 fitplot.styles=[None,None,None,'scatter']
672 fitplot.styles+=[None,'scatter']
674 if fitplot.colors==[]:
675 fitplot.colors=[None,None,None,None]
677 fitplot.colors+=[None,None]
679 self._send_plot([fitplot])
681 #TODO: remove 'plot' as parameter
682 def find_contact_point(self, plot=None):
684 Finds the contact point on the curve.
686 The current algorithm (thanks to Francesco Musiani, francesco.musiani@unibo.it and Massimo Sandal) is:
687 - take care of the PicoForce trigger bug - exclude retraction portions with too high standard deviation
688 - fit the second half of the retraction curve to a line
689 - if the fit is not almost horizontal, take a smaller chunk and repeat
690 - otherwise, we have something horizontal
691 - so take the average of horizontal points and use it as a baseline
693 Then, start from the rise of the retraction curve and look at the first point below the
696 FIXME: should be moved, probably to generalvclamp.py
699 #TODO: pickup current curve?
703 extension = copy.deepcopy(plot.curves[lh.EXTENSION])
704 retraction = copy.deepcopy(plot.curves[lh.RETRACTION])
707 extension, retraction = self.subtract_curves(extension, retraction)
710 #taking care of the picoforce trigger bug: we exclude portions of the curve that have too much
711 #standard deviation. yes, a lot of magic is here.
713 monlength=len(xret)-int(len(xret)/20)
716 monchunk=scipy.array(ydiff[monlength:finalength])
717 #TODO: there is a difference between scipy.stats.std and numpy.std: why?
718 #if abs(scipy.stats.std(monchunk)) < 2e-10:
719 if abs(np.std(monchunk)) < 2e-10:
721 else: #move away from the monster
722 monlength-=int(len(xret)/50)
723 finalength-=int(len(xret)/50)
724 #take half of the thing
725 endlength=int(len(xret)/2)
728 xchunk=yext[endlength:monlength]
729 ychunk=yext[endlength:monlength]
730 regr=scipy.stats.linregress(xchunk,ychunk)[0:2]
731 #we stop if we found an almost-horizontal fit or if we're going too short...
732 #FIXME: 0.1 and 6 here are "magic numbers" (although reasonable)
733 if (abs(regr[1]) > 0.1) and ( endlength < len(xret)-int(len(xret)/6) ) :
737 #ymean=scipy.mean(ychunk) #baseline
738 ymean = np.mean(ychunk) #baseline
740 #TODO: check if this works rather than the thing below
741 #for index, point in enumerate(yret):
746 #find the first point below the calculated baseline
754 #The algorithm didn't find anything below the baseline! It should NEVER happen
760 def find_contact_point2(self, debug=False):
762 TO BE DEVELOPED IN THE FUTURE
763 Finds the contact point on the curve.
765 FIXME: should be moved, probably to generalvclamp.py
768 #raw_plot=self.current.curve.default_plots()[0]
769 raw_plot=self.plots[0]
770 '''xext=self.plots[0].vectors[0][0]
771 yext=self.plots[0].vectors[0][1]
772 xret2=self.plots[0].vectors[1][0]
773 yret=self.plots[0].vectors[1][1]
775 xext=raw_plot.vectors[0][0]
776 yext=raw_plot.vectors[0][1]
777 xret2=raw_plot.vectors[1][0]
778 yret=raw_plot.vectors[1][1]
780 first_point=[xext[0], yext[0]]
781 last_point=[xext[-1], yext[-1]]
783 #regr=scipy.polyfit(first_point, last_point,1)[0:2]
784 diffx=abs(first_point[0]-last_point[0])
785 diffy=abs(first_point[1]-last_point[1])
787 #using polyfit results in numerical errors. good old algebra.
789 b=first_point[1]-(a*first_point[0])
790 baseline=scipy.polyval((a,b), xext)
792 ysub=[item-basitem for item,basitem in zip(yext,baseline)]
794 contact=ysub.index(min(ysub))
796 return xext,ysub,contact
798 #now, exploit a ClickedPoint instance to calculate index...
799 dummy=lh.ClickedPoint()
800 dummy.absolute_coords=(x_intercept,y_intercept)
801 dummy.find_graph_coords(xret2,yret)
804 return dummy.index, regr, regr_contact
810 #def x_do_contact(self,args):
812 #DEBUG COMMAND to be activated in the future
814 #xext,ysub,contact=self.find_contact_point2(debug=True)
816 #contact_plot=self.plots[0]
817 #contact_plot.add_set(xext,ysub)
818 #contact_plot.add_set([xext[contact]],[self.plots[0].vectors[0][1][contact]])
819 ##contact_plot.add_set([first_point[0]],[first_point[1]])
820 ##contact_plot.add_set([last_point[0]],[last_point[1]])
821 #contact_plot.styles=[None,None,None,'scatter']
822 #self._send_plot([contact_plot])
825 #index,regr,regr_contact=self.find_contact_point2(debug=True)
828 #raw_plot=self.current.curve.default_plots()[0]
829 #xret=raw_plot.vectors[0][0]
830 ##nc_line=[(item*regr[0])+regr[1] for item in x_nc]
831 #nc_line=scipy.polyval(regr,xret)
832 #c_line=scipy.polyval(regr_contact,xret)
835 #contact_plot=self.current.curve.default_plots()[0]
836 #contact_plot.add_set(xret, nc_line)
837 #contact_plot.add_set(xret, c_line)
838 #contact_plot.styles=[None,None,None,None]
839 ##contact_plot.styles.append(None)
840 #contact_plot.destination=1
841 #self._send_plot([contact_plot])