def find_contact_point2(self, debug=False): """ TO BE DEVELOPED IN THE FUTURE Finds the contact point on the curve. FIXME: should be moved, probably to generalvclamp.py """ # raw_plot=self.current.curve.default_plots()[0] raw_plot = self.plots[0] """xext=self.plots[0].vectors[0][0] yext=self.plots[0].vectors[0][1] xret2=self.plots[0].vectors[1][0] yret=self.plots[0].vectors[1][1] """ xext = raw_plot.vectors[0][0] yext = raw_plot.vectors[0][1] xret2 = raw_plot.vectors[1][0] yret = raw_plot.vectors[1][1] first_point = [xext[0], yext[0]] last_point = [xext[-1], yext[-1]] # regr=scipy.polyfit(first_point, last_point,1)[0:2] diffx = abs(first_point[0] - last_point[0]) diffy = abs(first_point[1] - last_point[1]) # using polyfit results in numerical errors. good old algebra. a = diffy / diffx b = first_point[1] - (a * first_point[0]) baseline = scipy.polyval((a, b), xext) ysub = [item - basitem for item, basitem in zip(yext, baseline)] contact = ysub.index(min(ysub)) return xext, ysub, contact # now, exploit a ClickedPoint instance to calculate index... dummy = ClickedPoint() dummy.absolute_coords = (x_intercept, y_intercept) dummy.find_graph_coords(xret2, yret) if debug: return dummy.index, regr, regr_contact else: return dummy.index
def do_fit(self, args): """ FIT (fit.py plugin) Fits an entropic elasticity function to a given chunk of the curve. First you have to click a contact point. Then you have to click the two edges of the data you want to fit. Fit quality compares the distance to the fit with the thermal noise (a good fit should be close to 1) The fit function depends on the fit_function variable. You can set it with the command "set fit_function wlc" or "set fit_function fjc" depending on the function you prefer. For WLC, the function is the simple polynomial worm-like chain as proposed by C.Bustamante, J.F.Marko, E.D.Siggia and S.Smith (Science. 1994 Sep 9;265(5178):1599-600.) For FJC, ref: C.Ray and B.B. Akhremitchev; http://www.chem.duke.edu/~boris/research/force_spectroscopy/fit_efjc.pdf For eFJC, ref: F Oesterhelt, M Rief and H E Gaub, New Journal of Physics 1 (1999) 6.1–6.11 (section 4.2) NOTE: use fixed pl for better results. Arguments: pl=[value] : Use a fixed persistent length (WLC) or Kuhn length (FJC) for the fit. If pl is not given, the fit will be a 2-variable fit. DO NOT put spaces between 'pl', '=' and the value. The value must be in nanometers. t=[value] : Use a user-defined temperature. The value must be in kelvins; by default it is 293 K. DO NOT put spaces between 't', '=' and the value. noauto : allows for clicking the contact point by hand (otherwise it is automatically estimated) the first time. If subsequent measurements are made, the same contact point clicked is used reclick : redefines by hand the contact point, if noauto has been used before but the user is unsatisfied of the previously choosen contact point. --------- Syntax: fit [pl=(value)] [t=value] [noauto] """ pl_value = None T = self.config["temperature"] for arg in args.split(): # look for a persistent length argument. if "pl=" in arg: pl_expression = arg.split("=") pl_value = float(pl_expression[1]) # actual value # look for a T argument. FIXME: spaces are not allowed between 'pl' and value if ("t=" in arg[0:2]) or ("T=" in arg[0:2]): t_expression = arg.split("=") T = float(t_expression[1]) # use the currently displayed plot for the fit displayed_plot = self._get_displayed_plot() # handle contact point arguments correctly if "reclick" in args.split(): print "Click contact point" contact_point = self._measure_N_points(N=1, whatset=1)[0] contact_point_index = contact_point.index self.wlccontact_point = contact_point self.wlccontact_index = contact_point.index self.wlccurrent = self.current.path elif "noauto" in args.split(): if self.wlccontact_index == None or self.wlccurrent != self.current.path: print "Click contact point" contact_point = self._measure_N_points(N=1, whatset=1)[0] contact_point_index = contact_point.index self.wlccontact_point = contact_point self.wlccontact_index = contact_point.index self.wlccurrent = self.current.path else: contact_point = self.wlccontact_point contact_point_index = self.wlccontact_index else: cindex = self.find_contact_point() contact_point = ClickedPoint() contact_point.absolute_coords = displayed_plot.vectors[1][0][cindex], displayed_plot.vectors[1][1][cindex] contact_point.find_graph_coords(displayed_plot.vectors[1][0], displayed_plot.vectors[1][1]) contact_point.is_marker = True print "Click edges of chunk" points = self._measure_N_points(N=2, whatset=1) points = [contact_point] + points try: if self.config["fit_function"] == "wlc": 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 ) name_of_charlength = "Persistent length" elif self.config["fit_function"] == "fjc": 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 ) name_of_charlength = "Kuhn length" elif self.config["fit_function"] == "efjc": 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 ) name_of_charlength = "Kuhn length (e)" else: print "No recognized fit function defined!" print "Set your fit function to wlc, fjc or efjc." return except: print "Fit not possible. Probably wrong interval -did you click two *different* points?" return # FIXME: print "Kuhn length" for FJC print "Fit function:", self.config["fit_function"] print "Contour length: %.2f nm" % (params[0] * (1.0e9)) to_dump = "contour " + self.current.path + " %.2f nm" % (params[0] * (1.0e9)) self.outlet.push(to_dump) if len(params) == 2: # if we did choose 2-value fit print name_of_charlength + ": %.2f nm" % (params[1] * (1.0e9)) to_dump = "persistent " + self.current.path + " %.2f nm" % (params[1] * (1.0e9)) self.outlet.push(to_dump) if fit_errors: fit_nm = [i * (10 ** 9) for i in fit_errors] print "Standard deviation (contour length) %.2f" % fit_nm[0] if len(fit_nm) > 1: print "Standard deviation (" + name_of_charlength + ") %.2f" % fit_nm[1] print "Fit quality: %.3f " % (qstd / np.std(displayed_plot.vectors[1][1][-20:-1])) # add the clicked points in the final PlotObject clickvector_x, clickvector_y = [], [] for item in points: clickvector_x.append(item.graph_coords[0]) clickvector_y.append(item.graph_coords[1]) # create a custom PlotObject to gracefully plot the fit along the curves fitplot = copy.deepcopy(displayed_plot) fitplot.add_set(xfit, yfit) fitplot.add_set(clickvector_x, clickvector_y) # FIXME: this colour/styles stuff must be solved at the root! if fitplot.styles == []: fitplot.styles = [None, None, None, "scatter"] else: fitplot.styles += [None, "scatter"] if fitplot.colors == []: fitplot.colors = [None, None, None, None] else: fitplot.colors += [None, None] self._send_plot([fitplot])