1 # Copyright (C) 2008-2010 Alberto Gomez-Casado
3 # Massimo Sandal <devicerandom@gmail.com>
4 # W. Trevor King <wking@drexel.edu>
6 # This file is part of Hooke.
8 # Hooke is free software: you can redistribute it and/or modify it
9 # under the terms of the GNU Lesser General Public License as
10 # published by the Free Software Foundation, either version 3 of the
11 # License, or (at your option) any later version.
13 # Hooke is distributed in the hope that it will be useful, but WITHOUT
14 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
16 # Public License for more details.
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with Hooke. If not, see
20 # <http://www.gnu.org/licenses/>.
22 """Force spectroscopy curves basic fitting plugin.
24 Non-standard Dependencies:
25 procplots.py (plot processing plugin)
28 from ..libhooke import WX_GOOD, ClickedPoint
31 wxversion.select(WX_GOOD)
32 #from wx import PostEvent
33 #from wx.lib.newevent import NewEvent
42 global EVT_MEASURE_WLC
44 #measure_wlc, EVT_MEASURE_WLC = NewEvent()
46 global events_from_fit
47 events_from_fit=Queue.Queue() #GUI ---> CLI COMMUNICATION
50 class fitCommands(object):
54 self.wlccontact_point=None
55 self.wlccontact_index=None
58 '''Calculates the average distance from data to fit, scaled by the standard deviation
59 of the free cantilever area (thermal noise)
64 def wlc_fit(self,clicked_points,xvector,yvector, pl_value, T=293, return_errors=False):
66 Worm-like chain model fitting.
67 The function is the simple polynomial worm-like chain as proposed by C.Bustamante, J.F.Marko, E.D.Siggia
68 and S.Smith (Science. 1994 Sep 9;265(5178):1599-600.)
72 clicked_points[0] = contact point (calculated or hand-clicked)
73 clicked_points[1] and [2] are edges of chunk
76 #STEP 1: Prepare the vectors to apply the fit.
77 if pl_value is not None:
78 pl_value=pl_value/(10**9)
80 #indexes of the selected chunk
81 first_index=min(clicked_points[1].index, clicked_points[2].index)
82 last_index=max(clicked_points[1].index, clicked_points[2].index)
84 #getting the chunk and reverting it
85 xchunk,ychunk=xvector[first_index:last_index],yvector[first_index:last_index]
88 #put contact point at zero and flip around the contact point (the fit wants a positive growth for extension and force)
89 xchunk_corr_up=[-(x-clicked_points[0].graph_coords[0]) for x in xchunk]
90 ychunk_corr_up=[-(y-clicked_points[0].graph_coords[1]) for y in ychunk]
93 xchunk_corr_up=scipy.array(xchunk_corr_up)
94 ychunk_corr_up=scipy.array(ychunk_corr_up)
97 #STEP 2: actually do the fit
99 #Find furthest point of chunk and add it a bit; the fit must converge
101 xchunk_high=max(xchunk_corr_up)
102 xchunk_high+=(xchunk_high/10)
104 #Here are the linearized start parameters for the WLC.
105 #[lambd=1/Lo , pii=1/P]
107 p0=[(1/xchunk_high),(1/(3.5e-10))]
108 p0_plfix=[(1/xchunk_high)]
111 fixme: remove these comments after testing
113 def dist(px,py,linex,liney):
114 distancesx=scipy.array([(px-x)**2 for x in linex])
115 minindex=np.argmin(distancesx)
116 print px, linex[0], linex[-1]
117 return (py-liney[minindex])**2
119 def f_wlc(params,x,T=T):
121 wlc function for ODR fitting
126 y=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd))
129 def f_wlc_plfix(params,x,pl_value=pl_value,T=T):
131 wlc function for ODR fitting
137 y=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd))
141 realdata=scipy.odr.RealData(xchunk_corr_up,ychunk_corr_up)
143 model=scipy.odr.Model(f_wlc_plfix)
144 o = scipy.odr.ODR(realdata, model, p0_plfix)
146 model=scipy.odr.Model(f_wlc)
147 o = scipy.odr.ODR(realdata, model, p0)
149 o.set_job(fit_type=2)
151 fit_out=[(1/i) for i in out.beta]
153 #Calculate fit errors from output standard deviations.
154 #We must propagate the error because we fit the *inverse* parameters!
155 #The error = (error of the inverse)*(value**2)
157 for sd,value in zip(out.sd_beta, fit_out):
158 err_real=sd*(value**2)
159 fit_errors.append(err_real)
161 def wlc_eval(x,params,pl_value,T):
163 Evaluates the WLC function
173 Kb=(1.38065e-23) #boltzmann constant
174 therm=Kb*T #so we have thermal energy
176 return ( (therm*pii/4.0) * (((1-(x*lambd))**-2.0) - 1 + (4.0*x*lambd)) )
179 #STEP 3: plotting the fit
181 #obtain domain to plot the fit - from contact point to last_index plus 20 points
182 thule_index=last_index+10
183 if thule_index > len(xvector): #for rare cases in which we fit something at the END of whole curve.
184 thule_index = len(xvector)
185 #reverse etc. the domain
186 xfit_chunk=xvector[clicked_points[0].index:thule_index]
188 xfit_chunk_corr_up=[-(x-clicked_points[0].graph_coords[0]) for x in xfit_chunk]
189 xfit_chunk_corr_up=scipy.array(xfit_chunk_corr_up)
191 #the fitted curve: reflip, re-uncorrect
192 yfit=wlc_eval(xfit_chunk_corr_up, out.beta, pl_value,T)
193 yfit_down=[-y for y in yfit]
194 yfit_corr_down=[y+clicked_points[0].graph_coords[1] for y in yfit_down]
197 #calculate fit quality
199 yqeval=wlc_eval(xchunk_corr_up,out.beta,pl_value,T)
200 #we need to cut the extra from thuleindex
201 for qindex in np.arange(0,len(yqeval)):
202 qsum+=(yqeval[qindex]-ychunk_corr_up[qindex])**2
203 qstd=np.sqrt(qsum/len(ychunk_corr_up))
207 return fit_out, yfit_corr_down, xfit_chunk, fit_errors, qstd
209 return fit_out, yfit_corr_down, xfit_chunk, None, qstd
211 def fjc_fit(self,clicked_points,xvector,yvector, pl_value, T=293, return_errors=False):
213 Freely-jointed chain function
214 ref: C.Ray and B.B. Akhremitchev; http://www.chem.duke.edu/~boris/research/force_spectroscopy/fit_efjc.pdf
217 clicked_points[0] is the contact point (calculated or hand-clicked)
218 clicked_points[1] and [2] are edges of chunk
221 #STEP 1: Prepare the vectors to apply the fit.
222 if pl_value is not None:
223 pl_value=pl_value/(10**9)
225 #indexes of the selected chunk
226 first_index=min(clicked_points[1].index, clicked_points[2].index)
227 last_index=max(clicked_points[1].index, clicked_points[2].index)
229 #getting the chunk and reverting it
230 xchunk,ychunk=xvector[first_index:last_index],yvector[first_index:last_index]
233 #put contact point at zero and flip around the contact point (the fit wants a positive growth for extension and force)
234 xchunk_corr_up=[-(x-clicked_points[0].graph_coords[0]) for x in xchunk]
235 ychunk_corr_up=[-(y-clicked_points[0].graph_coords[1]) for y in ychunk]
239 xchunk_corr_up=scipy.array(xchunk_corr_up)
240 ychunk_corr_up=scipy.array(ychunk_corr_up)
243 #STEP 2: actually do the fit
245 #Find furthest point of chunk and add it a bit; the fit must converge
247 xchunk_high=max(xchunk_corr_up)
248 xchunk_high+=(xchunk_high/10)
250 #Here are the linearized start parameters for the WLC.
251 #[lambd=1/Lo , pii=1/P]
253 p0=[(1/xchunk_high),(1/(3.5e-10))]
254 p0_plfix=[(1/xchunk_high)]
257 fixme: remove these comments after testing
259 def dist(px,py,linex,liney):
260 distancesx=scipy.array([(px-x)**2 for x in linex])
261 minindex=np.argmin(distancesx)
262 print minindex, px, linex[0], linex[-1]
263 return (py-liney[minindex])**2
269 return (np.exp(2*z)+1)/(np.exp(2*z)-1)
271 def x_fjc(params,f,T=T):
273 fjc function for ODR fitting
279 #x=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd))
280 x=(1/lambd)*(coth(f*(1/pii)/therm) - (therm*pii)/f)
283 def x_fjc_plfix(params,f,pl_value=pl_value,T=T):
285 fjc function for ODR fitting
291 #y=(therm*pii/4.0) * (((1-(x*lambd))**-2) - 1 + (4*x*lambd))
292 x=(1/lambd)*(coth(f*(1/pii)/therm) - (therm*pii)/f)
296 realdata=scipy.odr.RealData(ychunk_corr_up,xchunk_corr_up)
298 model=scipy.odr.Model(x_fjc_plfix)
299 o = scipy.odr.ODR(realdata, model, p0_plfix)
301 model=scipy.odr.Model(x_fjc)
302 o = scipy.odr.ODR(realdata, model, p0)
304 o.set_job(fit_type=2)
306 fit_out=[(1/i) for i in out.beta]
308 #Calculate fit errors from output standard deviations.
309 #We must propagate the error because we fit the *inverse* parameters!
310 #The error = (error of the inverse)*(value**2)
312 for sd,value in zip(out.sd_beta, fit_out):
313 err_real=sd*(value**2)
314 fit_errors.append(err_real)
316 def fjc_eval(y,params,pl_value,T):
318 Evaluates the WLC function
328 Kb=(1.38065e-23) #boltzmann constant
329 therm=Kb*T #so we have thermal energy
330 #return ( (therm*pii/4.0) * (((1-(x*lambd))**-2.0) - 1 + (4.0*x*lambd)) )
331 return (1/lambd)*(coth(y*(1/pii)/therm) - (therm*pii)/y)
335 #STEP 3: plotting the fit
336 #obtain domain to plot the fit - from contact point to last_index plus 20 points
337 thule_index=last_index+10
338 if thule_index > len(xvector): #for rare cases in which we fit something at the END of whole curve.
339 thule_index = len(xvector)
340 #reverse etc. the domain
341 ychunk=yvector[clicked_points[0].index:thule_index]
344 y_evalchunk=np.linspace(min(ychunk),max(ychunk),100)
346 #Empty y-chunk. It happens whenever we set the contact point after a recognized peak,
347 #or other buggy situations. Kludge to live with it now...
348 ychunk=yvector[:thule_index]
349 y_evalchunk=np.linspace(min(ychunk),max(ychunk),100)
351 yfit_down=[-y for y in y_evalchunk]
352 yfit_corr_down=[y+clicked_points[0].graph_coords[1] for y in yfit_down]
353 yfit_corr_down=scipy.array(yfit_corr_down)
355 #the fitted curve: reflip, re-uncorrect
356 xfit=fjc_eval(yfit_corr_down, out.beta, pl_value,T)
359 xfit_chunk_corr_up=[-(x-clicked_points[0].graph_coords[0]) for x in xfit]
361 #xfit_chunk_corr_up=scipy.array(xfit_chunk_corr_up)
362 #deltay=yfit_down[0]-yvector[clicked_points[0].index]
364 #This is a terrible, terrible kludge to find the point where it should normalize (and from where it should plot)
366 for index in scipy.arange(1,len(xfit_chunk_corr_up),1):
367 xxxdists.append((clicked_points[0].graph_coords[0]-xfit_chunk_corr_up[index])**2)
368 normalize_index=xxxdists.index(min(xxxdists))
371 deltay=yfit_down[normalize_index]-clicked_points[0].graph_coords[1]
372 yfit_corr_down=[y-deltay for y in yfit_down]
375 #calculate fit quality
376 #creates dense y vector
377 yqeval=np.linspace(np.min(ychunk_corr_up)/2,np.max(ychunk_corr_up)*2,10*len(ychunk_corr_up))
378 #corresponding fitted x
379 xqeval=fjc_eval(yqeval,out.beta,pl_value,T)
382 for qindex in np.arange(0,len(ychunk_corr_up)):
383 qsum+=dist(xchunk_corr_up[qindex],ychunk_corr_up[qindex],xqeval,yqeval)
384 qstd=np.sqrt(qsum/len(ychunk_corr_up))
388 return fit_out, yfit_corr_down[normalize_index+1:], xfit_chunk_corr_up[normalize_index+1:], fit_errors, qstd
390 return fit_out, yfit_corr_down[normalize_index+1:], xfit_chunk_corr_up[normalize_index+1:], None, qstd
392 def efjc_fit(self,clicked_points,xvector,yvector, pl_value, T=293.0, return_errors=False):
394 Extended Freely-jointed chain function
395 ref: F Oesterhelt, M Rief and H E Gaub, New Journal of Physics 1 (1999) 6.1–6.11
396 Please note that 2-parameter fitting (length and kl) usually does not converge, use fixed kl
399 clicked_points[0] is the contact point (calculated or hand-clicked)
400 clicked_points[1] and [2] are edges of chunk
403 #Fixed parameters from reference
404 Kb=(1.38065e-2) #in pN.nm
406 Lh=0.280 #helical, nm
410 #STEP 1: Prepare the vectors to apply the fit.
412 #indexes of the selected chunk
413 first_index=min(clicked_points[1].index, clicked_points[2].index)
414 last_index=max(clicked_points[1].index, clicked_points[2].index)
416 #getting the chunk and reverting it
417 xchunk,ychunk=xvector[first_index:last_index],yvector[first_index:last_index]
420 #put contact point at zero and flip around the contact point (the fit wants a positive growth for extension and force)
421 xchunk_corr_up=[-(x-clicked_points[0].graph_coords[0]) for x in xchunk]
422 ychunk_corr_up=[-(y-clicked_points[0].graph_coords[1]) for y in ychunk]
426 xchunk_corr_up=scipy.array(xchunk_corr_up)
427 ychunk_corr_up=scipy.array(ychunk_corr_up)
429 xchunk_corr_up_nm=xchunk_corr_up*1e9
430 ychunk_corr_up_pn=ychunk_corr_up*1e12
433 #STEP 2: actually do the fit
435 #Find furthest point of chunk and add it a bit; the fit must converge
437 xchunk_high=max(xchunk_corr_up_nm)
438 xchunk_high+=(xchunk_high/10.0)
440 #Here are the linearized start parameters for the WLC.
442 #max number of monomers (all helical)for a contour length xchunk_high
443 excessNs=xchunk_high/(Lp)
444 p0=[excessNs,(1.0/(0.7))]
445 p0_plfix=[(excessNs)]
447 def dist(px,py,linex,liney):
448 distancesx=scipy.array([(px-x)**2 for x in linex])
449 minindex=np.argmin(distancesx)
450 return (py-liney[minindex])**2
453 dG0=12.4242 #3kt in pN.nm
454 dL=0.078 #planar-helical
459 Lh=0.280 #helical, nm
464 return Lp/(np.exp(dG/therm)+1)+Lh/(np.exp(-dG/therm)+1)
470 return 1.0/np.tanh(z)
472 def x_efjc(params,f,T=T,Ks=Ks):
474 efjc function for ODR fitting
483 x=Ns*Lfactor(f)*(coth(beta)-1.0/beta)+Ns*f/Ks
486 def x_efjc_plfix(params,f,kl_value=pl_value,T=T,Ks=Ks):
488 efjc function for ODR fitting
497 x=Ns*Lfactor(f)*(coth(beta)-1.0/beta)+Ns*f/Ks
501 realdata=scipy.odr.RealData(ychunk_corr_up_pn,xchunk_corr_up_nm)
503 model=scipy.odr.Model(x_efjc_plfix)
504 o = scipy.odr.ODR(realdata, model, p0_plfix)
506 print 'WARNING eFJC fit with free pl sometimes does not converge'
507 model=scipy.odr.Model(x_efjc)
508 o = scipy.odr.ODR(realdata, model, p0)
510 o.set_job(fit_type=2)
517 kfit=1e-9/out.beta[1]
525 #Calculate fit errors from output standard deviations.
527 fit_errors.append(out.sd_beta[0]*Lp*1e-9)
529 fit_errors.append(1e9*out.sd_beta[1]*kfit**2)
533 def efjc_eval(y,params,pl_value,T=T,Lfactor=Lfactor,Ks=Ks):
535 Evaluates the eFJC function
545 Kb=(1.38065e-2) #boltzmann constant
546 therm=Kb*T #so we have thermal energy
549 x= Ns*Lfactor(y)*(coth(beta)-1.0/beta)+Ns*y/Ks
553 #STEP 3: plotting the fit
554 #obtain domain to plot the fit - from contact point to last_index plus 20 points
555 thule_index=last_index+10
556 if thule_index > len(xvector): #for rare cases in which we fit something at the END of whole curve.
557 thule_index = len(xvector)
558 #reverse etc. the domain
559 ychunk=yvector[clicked_points[0].index:thule_index]
562 y_evalchunk=np.linspace(min(ychunk),max(ychunk),100)
564 #Empty y-chunk. It happens whenever we set the contact point after a recognized peak,
565 #or other buggy situations. Kludge to live with it now...
566 ychunk=yvector[:thule_index]
567 y_evalchunk=np.linspace(min(ychunk),max(ychunk),100)
569 yfit_down=[-y for y in y_evalchunk]
570 yfit_corr_down=[y+clicked_points[0].graph_coords[1] for y in yfit_down]
571 yfit_corr_down=scipy.array(yfit_corr_down)
573 #the fitted curve: reflip, re-uncorrect
574 xfit=efjc_eval(1e12*yfit_corr_down, out.beta, pl_value,T)*1e-9
577 xfit_chunk_corr_up=[-(x-clicked_points[0].graph_coords[0]) for x in xfit]
579 #xfit_chunk_corr_up=scipy.array(xfit_chunk_corr_up)
580 #deltay=yfit_down[0]-yvector[clicked_points[0].index]
582 #This is a terrible, terrible kludge to find the point where it should normalize (and from where it should plot)
584 for index in scipy.arange(1,len(xfit_chunk_corr_up),1):
585 xxxdists.append((clicked_points[0].graph_coords[0]-xfit_chunk_corr_up[index])**2)
586 normalize_index=xxxdists.index(min(xxxdists))
589 deltay=yfit_down[normalize_index]-clicked_points[0].graph_coords[1]
590 yfit_corr_down=[y-deltay for y in yfit_down]
592 #calculate fit quality
593 #creates dense y vector
594 yqeval=np.linspace(np.min(ychunk_corr_up_pn)/2,np.max(ychunk_corr_up_pn)*2,10*len(ychunk_corr_up_pn))
595 #corresponding fitted x
596 xqeval=efjc_eval(yqeval,out.beta,pl_value)
599 for qindex in np.arange(0,len(ychunk_corr_up_pn)):
600 qsum+=dist(xchunk_corr_up_nm[qindex],ychunk_corr_up_pn[qindex],xqeval,yqeval)
601 qstd=1e-12*np.sqrt(qsum/len(ychunk_corr_up_pn))
604 return fit_out, yfit_corr_down[normalize_index+1:], xfit_chunk_corr_up[normalize_index+1:], fit_errors, qstd
606 return fit_out, yfit_corr_down[normalize_index+1:], xfit_chunk_corr_up[normalize_index+1:], None, qstd
611 def do_wlc(self,args):
620 def do_fjc(self,args):
629 def do_fit(self,args):
633 Fits an entropic elasticity function to a given chunk of the curve.
635 First you have to click a contact point.
636 Then you have to click the two edges of the data you want to fit.
638 Fit quality compares the distance to the fit with the thermal noise (a good fit should be close to 1)
640 The fit function depends on the fit_function variable. You can set it with the command
641 "set fit_function wlc" or "set fit_function fjc" depending on the function you prefer.
643 For WLC, the function is the simple polynomial worm-like chain as proposed by
644 C.Bustamante, J.F.Marko, E.D.Siggia and S.Smith (Science. 1994
645 Sep 9;265(5178):1599-600.)
648 C.Ray and B.B. Akhremitchev; http://www.chem.duke.edu/~boris/research/force_spectroscopy/fit_efjc.pdf
651 F Oesterhelt, M Rief and H E Gaub, New Journal of Physics 1 (1999) 6.1–6.11 (section 4.2)
652 NOTE: use fixed pl for better results.
655 pl=[value] : Use a fixed persistent length (WLC) or Kuhn length (FJC) for the fit. If pl is not given,
656 the fit will be a 2-variable
657 fit. DO NOT put spaces between 'pl', '=' and the value.
658 The value must be in nanometers.
660 t=[value] : Use a user-defined temperature. The value must be in
661 kelvins; by default it is 293 K.
662 DO NOT put spaces between 't', '=' and the value.
664 noauto : allows for clicking the contact point by
665 hand (otherwise it is automatically estimated) the first time.
666 If subsequent measurements are made, the same contact point
669 reclick : redefines by hand the contact point, if noauto has been used before
670 but the user is unsatisfied of the previously choosen contact point.
672 Syntax: fit [pl=(value)] [t=value] [noauto]
675 T=self.config['temperature']
676 for arg in args.split():
677 #look for a persistent length argument.
679 pl_expression=arg.split('=')
680 pl_value=float(pl_expression[1]) #actual value
681 #look for a T argument. FIXME: spaces are not allowed between 'pl' and value
682 if ('t=' in arg[0:2]) or ('T=' in arg[0:2]):
683 t_expression=arg.split('=')
684 T=float(t_expression[1])
686 #use the currently displayed plot for the fit
687 displayed_plot=self._get_displayed_plot()
689 #handle contact point arguments correctly
690 if 'reclick' in args.split():
691 print 'Click contact point'
692 contact_point=self._measure_N_points(N=1, whatset=1)[0]
693 contact_point_index=contact_point.index
694 self.wlccontact_point=contact_point
695 self.wlccontact_index=contact_point.index
696 self.wlccurrent=self.current.path
697 elif 'noauto' in args.split():
698 if self.wlccontact_index==None or self.wlccurrent != self.current.path:
699 print 'Click contact point'
700 contact_point=self._measure_N_points(N=1, whatset=1)[0]
701 contact_point_index=contact_point.index
702 self.wlccontact_point=contact_point
703 self.wlccontact_index=contact_point.index
704 self.wlccurrent=self.current.path
706 contact_point=self.wlccontact_point
707 contact_point_index=self.wlccontact_index
709 cindex=self.find_contact_point()
710 contact_point=ClickedPoint()
711 contact_point.absolute_coords=displayed_plot.vectors[1][0][cindex], displayed_plot.vectors[1][1][cindex]
712 contact_point.find_graph_coords(displayed_plot.vectors[1][0], displayed_plot.vectors[1][1])
713 contact_point.is_marker=True
715 print 'Click edges of chunk'
716 points=self._measure_N_points(N=2, whatset=1)
717 points=[contact_point]+points
720 if self.config['fit_function']=='wlc':
721 params, yfit, xfit, fit_errors,qstd = self.wlc_fit(points, displayed_plot.vectors[1][0], displayed_plot.vectors[1][1],pl_value,T, return_errors=True )
722 name_of_charlength='Persistent length'
723 elif self.config['fit_function']=='fjc':
724 params, yfit, xfit, fit_errors,qstd = self.fjc_fit(points, displayed_plot.vectors[1][0], displayed_plot.vectors[1][1],pl_value,T, return_errors=True )
725 name_of_charlength='Kuhn length'
726 elif self.config['fit_function']=='efjc':
727 params, yfit, xfit, fit_errors,qstd = self.efjc_fit(points, displayed_plot.vectors[1][0], displayed_plot.vectors[1][1],pl_value,T, return_errors=True )
728 name_of_charlength='Kuhn length (e)'
730 print 'No recognized fit function defined!'
731 print 'Set your fit function to wlc, fjc or efjc.'
735 print 'Fit not possible. Probably wrong interval -did you click two *different* points?'
738 #FIXME: print "Kuhn length" for FJC
739 print 'Fit function:',self.config['fit_function']
740 print 'Contour length: ',params[0]*(1.0e+9),' nm'
741 to_dump='contour '+self.current.path+' '+str(params[0]*(1.0e+9))+' nm'
742 self.outlet.push(to_dump)
743 if len(params)==2: #if we did choose 2-value fit
744 print name_of_charlength+': ',params[1]*(1.0e+9),' nm'
745 to_dump='persistent '+self.current.path+' '+str(params[1]*(1.0e+9))+' nm'
746 self.outlet.push(to_dump)
749 fit_nm=[i*(10**9) for i in fit_errors]
750 print 'Standard deviation (contour length)', fit_nm[0]
752 print 'Standard deviation ('+name_of_charlength+')', fit_nm[1]
754 print 'Fit quality: '+str(qstd/np.std(displayed_plot.vectors[1][1][-20:-1]))
757 #add the clicked points in the final PlotObject
758 clickvector_x, clickvector_y=[], []
760 clickvector_x.append(item.graph_coords[0])
761 clickvector_y.append(item.graph_coords[1])
763 #create a custom PlotObject to gracefully plot the fit along the curves
765 fitplot=copy.deepcopy(displayed_plot)
766 fitplot.add_set(xfit,yfit)
767 fitplot.add_set(clickvector_x,clickvector_y)
769 #FIXME: this colour/styles stuff must be solved at the root!
770 if fitplot.styles==[]:
771 fitplot.styles=[None,None,None,'scatter']
773 fitplot.styles+=[None,'scatter']
775 if fitplot.colors==[]:
776 fitplot.colors=[None,None,None,None]
778 fitplot.colors+=[None,None]
780 self._send_plot([fitplot])