From: W. Trevor King Date: Tue, 4 May 2010 07:09:59 +0000 (-0400) Subject: Merged with trunk X-Git-Url: http://git.tremily.us/?p=hooke.git;a=commitdiff_plain;h=41ef0130e16c0cf8d2c0f1acc9e06986d62f7607 Merged with trunk --- 41ef0130e16c0cf8d2c0f1acc9e06986d62f7607 diff --cc bin/hooke index 0000000,5a57baa..7bf1b13 mode 000000,100755..100755 --- a/bin/hooke +++ b/bin/hooke @@@ -1,0 -1,5 +1,5 @@@ -#!/usr/bin/python ++#!/usr/bin/env python + + import hooke.hooke + + hooke.hooke.main() diff --cc conf/hooke.conf index 48d83da,c1d8d7b..9236b81 mode 100755,100644..100644 --- a/conf/hooke.conf +++ b/conf/hooke.conf @@@ -1,15 -1,48 +1,50 @@@ - - - - - insert directory - + + + + + ./doc/ + + + + + ++ tccd_coincident="0" ++ centerzero="1" ++/> + --> + @@@ -38,10 -70,6 +73,9 @@@ + + - - ++ - ++ (+100-10) + + peak_location[i]=index_pk + return peak_location,peak_size - - + + def exec_has_peaks(self,item,abs_devs): ''' encapsulates has_peaks for the purpose of correctly treating the curve objects in the convfilt loop, diff --cc hooke/plugin/generalvclamp.py index 2c3f655,45cfa2c..5f6657b --- a/hooke/plugin/generalvclamp.py +++ b/hooke/plugin/generalvclamp.py @@@ -1,6 -1,3 +1,6 @@@ +#!/usr/bin/env python - # -*- coding: utf-8 -*- ++# -*- coding: iso-8859-1 -*- + ''' generalvclamp.py @@@ -115,19 -112,19 +115,19 @@@ class generalvclampCommands(object) boundaries=[self.basepoints[0].index, self.basepoints[1].index] boundaries.sort() to_average=plot.vectors[whatset][1][boundaries[0]:boundaries[1]] #y points to average - + avg=np.mean(to_average) forcebase=abs(y-avg) - print "%.1f pN"%(forcebase*(10**12)) + print str(forcebase*(10**12))+' pN' to_dump='forcebase '+self.current.path+' '+str(forcebase*(10**12))+' pN' self.outlet.push(to_dump) - + def plotmanip_multiplier(self, plot, current): ''' - Multiplies all the Y values of an SMFS curve by a value stored in the 'force_multiplier' + Multiplies all the Y values of an SMFS curve by a value stored in the 'force_multiplier' configuration variable. Useful for calibrations and other stuff. ''' - + #not a smfs curve... if current.curve.experiment != 'smfs': return plot @@@ -135,20 -132,20 +135,20 @@@ #only one set is present... if len(self.plots[0].vectors) != 2: return plot - + #multiplier is 1... if (self.config['force_multiplier']==1): - return plot - + return plot + for i in range(len(plot.vectors[0][1])): - plot.vectors[0][1][i]=plot.vectors[0][1][i]*self.config['force_multiplier'] - - for i in range(len(plot.vectors[1][1])): - plot.vectors[1][1][i]=plot.vectors[1][1][i]*self.config['force_multiplier'] - - return plot + plot.vectors[0][1][i]=plot.vectors[0][1][i]*self.config['force_multiplier'] + for i in range(len(plot.vectors[1][1])): + plot.vectors[1][1][i]=plot.vectors[1][1][i]*self.config['force_multiplier'] + return plot + + def plotmanip_flatten(self, plot, current, customvalue=False): ''' Subtracts a polynomial fit to the non-contact part of the curve, as to flatten it. @@@ -183,19 -180,9 +183,19 @@@ valn=[[] for item in range(max_exponent)] yrn=[0.0 for item in range(max_exponent)] errn=[0.0 for item in range(max_exponent)] - + + #Check if we have a proper numerical value + try: + zzz=int(max_cycles) + except: + #Loudly and annoyingly complain if it's not a number, then fallback to zero + print '''Warning: flatten value is not a number! + Use "set flatten" or edit hooke.conf to set it properly + Using zero.''' + max_cycles=0 + for i in range(int(max_cycles)): - + x_ext=plot.vectors[0][0][contact_index+delta_contact:] y_ext=plot.vectors[0][1][contact_index+delta_contact:] x_ret=plot.vectors[1][0][contact_index+delta_contact:] diff --cc hooke/plugin/jumpstat.py index 07f6e05,0000000..9175b5c mode 100755,000000..100755 --- a/hooke/plugin/jumpstat.py +++ b/hooke/plugin/jumpstat.py @@@ -1,204 -1,0 +1,204 @@@ +# -*- coding: utf-8 -*- - from libhooke import WX_GOOD, ClickedPoint ++from ..libhooke import WX_GOOD, ClickedPoint +import wxversion +wxversion.select(WX_GOOD) +from wx import PostEvent +import numpy as np +import scipy as sp +import copy +import os.path +import time +import sys +import warnings +warnings.simplefilter('ignore',np.RankWarning) + + +class jumpstatCommands(): + + def do_jumpstat(self,args): + ''' + JUMPSTAT + jumpstat.py + Based on the convolution recognition automatically give: + - the delta distance between the peaks, + - the delta-force from the top of the peaks and subsequent relaxation, + - the delta-force from the top of the peaks and the baseline + The command allow also to remove the unwanted peaks that can be due to interference. + When you first issue the command, it will ask for the filename. If you are giving the filename + of an existing file, autopeak will resume it and append measurements to it. If you are giving + a new filename, it will create the file and append to it until you close Hooke. + You can also define a minimun deviation of the peaks. + + Syntax: + jumpstat [deviation] + deviation = number of times the convolution signal is above the noise absolute deviation. + ''' + + + #finding the max and the minimum positions for all the peaks + noflatten=False + #we use if else only to avoid a "bad input" message from find_current_peaks + if (len(args)==0): + max_peaks_location, peak_size=self.find_current_peaks(noflatten) + min_peaks_location, pks2=self.find_current_peaks(noflatten, True, False) + else: + max_peaks_location, peak_size=self.find_current_peaks(noflatten, args) + min_peaks_location, pks2=self.find_current_peaks(noflatten, args, False) + + + #print "max_peaks_location: "+str(len(max_peaks_location)) + #print "min_peaks_location: "+str(len(min_peaks_location)) + + #if no peaks, we have nothing to plot. exit. + if len(max_peaks_location)==0: + print "No peaks on this curve." + return + + if len(max_peaks_location)!=len(min_peaks_location): + print "Something went wrong in peaks recognition, number of minima is different from number of maxima. Exiting." + return + + #otherwise, we plot the peak locations. + xplotted_ret=self.plots[0].vectors[1][0] + yplotted_ret=self.plots[0].vectors[1][1] + xgood=[xplotted_ret[index] for index in max_peaks_location] + ygood=[yplotted_ret[index] for index in max_peaks_location] + + xafter=[xplotted_ret[index] for index in min_peaks_location] + yafter=[yplotted_ret[index] for index in min_peaks_location] + + recplot=self._get_displayed_plot() + recplot2=self._get_displayed_plot() + recplot.vectors.append([xgood,ygood]) + recplot2.vectors.append([xafter,yafter]) + + if recplot.styles==[]: + recplot.styles=[None,None,'scatter'] + recplot.colors=[None,None,None] + else: + recplot.styles+=['scatter'] + recplot.colors+=[None] + + if recplot2.styles==[]: + recplot2.styles=[None,None,None] + recplot2.colors=[None,'1.0',None] + else: + recplot2.styles+=['scatter'] + recplot2.colors+=['0.5'] + + self._send_plot([recplot]) + self._send_plot([recplot2]) + + + #finding the baseline + self.basepoints=self.baseline_points(max_peaks_location, recplot) + boundaries=[self.basepoints[0].index, self.basepoints[1].index] + boundaries.sort() + to_average=recplot.vectors[1][1][boundaries[0]:boundaries[1]] #y points to average + avg=np.mean(to_average) + + + dist=[] + jumpforce=[] + force=[] + + #we calculate the distance vector + for g in range(len(max_peaks_location)-1): + dist.append((10**9)*(xplotted_ret[max_peaks_location[g]]-xplotted_ret[max_peaks_location[g+1]])) + print "Distance values for the peaks in nm:" + print dist + + #the jump-force vector + for g in range(len(max_peaks_location)): + jumpforce.append((10**12) *(yplotted_ret[min_peaks_location[g]] -yplotted_ret[max_peaks_location[g]]) ) + print "Force values for the jumps of the peaks in pN:" + print jumpforce + + #the force from baseline vector + for g in range(len(max_peaks_location)): + force.append((10**12)*(avg-yplotted_ret[max_peaks_location[g]])) + print "Force values for the peaks in pN:" + print force + + + + #Now ask for the peaks that we don't want + print 'Peaks to ignore (0,1...n from contact point,return to take all)' + print 'N to discard measurement' + exclude_raw=raw_input('Input:') + if exclude_raw=='N': + print 'Discarded.' + return + + if not exclude_raw=='': + exclude=exclude_raw.split(',') + #we convert in numbers the input + try: + exclude=[int(item) for item in exclude] + except: + print 'Bad input, taking nothing.' + return + +# we remove the peaks that we don't want from the list, we need a counter beacause if we remove +# a peaks the other peaks in the list are shifted by one at each step + count=0 + for a in exclude: + if (a==0): + max_peaks_location=max_peaks_location[1:] + min_peaks_location=min_peaks_location[1:] + else: + new_a=a-count + max_peaks_location= max_peaks_location[0:new_a]+max_peaks_location[new_a+1:] + min_peaks_location= min_peaks_location[0:new_a]+min_peaks_location[new_a+1:] + peak_size= peak_size[0:new_a]+peak_size[new_a+1:] + count+=1 + + + #print "max_peaks_location: "+str(len(max_peaks_location)) + #print "min_peaks_location: "+str(len(min_peaks_location)) + + + dist=[] + jumpforce=[] + force=[] + #we recalculate the distances and the forces after the removing of the unwanted peaks + for g in range(len(max_peaks_location)-1): + dist.append(xplotted_ret[max_peaks_location[g]]-xplotted_ret[max_peaks_location[g+1]]) + for g in range(len(max_peaks_location)): + jumpforce.append( yplotted_ret[min_peaks_location[g]] - yplotted_ret[max_peaks_location[g]] ) + for g in range(len(max_peaks_location)): + force.append(avg - yplotted_ret[max_peaks_location[g]]) + + + + + + #Save file info + if self.autofile=='': + self.autofile=raw_input('Jumpstat filename? (return to ignore) ') + if self.autofile=='': + print 'Not saved.' + return + + if not os.path.exists(self.autofile): + f=open(self.autofile,'w+') + f.write('Analysis started '+time.asctime()+'\n') + f.write('----------------------------------------\n') + f.write('; Delta Distance length (m); Jump Force pN; Standard Force pN\n') + f.write(self.current.path+'\n') + for k in range(len(dist)): + f.write(";") + f.write(str(dist[k])+";"+str(jumpforce[k])+";"+str(force[k])+"\n" ) + f.write("\n") + f.close() + + else: + f=open(self.autofile,'a+') + f.write(self.current.path+'\n') + for k in range(len(dist)): + f.write(";") + f.write(str(dist[k])+";"+str(jumpforce[k])+";"+str(force[k])+"\n" ) + f.write("\n") + f.close() + - print 'Saving...' ++ print 'Saving...' diff --cc hooke/plugin/multifit.py index 81c4904,0000000..2e620fd mode 100644,000000..100644 --- a/hooke/plugin/multifit.py +++ b/hooke/plugin/multifit.py @@@ -1,385 -1,0 +1,385 @@@ +#!/usr/bin/env python + +''' +multifit.py + +Alberto Gomez-Casado, (c) 2010, University of Twente (The Netherlands) +Licensed under GNU GPL v2 +''' + +#FIXME clean this, probably some dependencies are not needed + - from libhooke import WX_GOOD, ClickedPoint ++from ..libhooke import WX_GOOD, ClickedPoint +import wxversion +wxversion.select(WX_GOOD) +from wx import PostEvent +import numpy as np +import scipy as sp +import copy +import os.path +import time +import tempfile +import warnings +warnings.simplefilter('ignore',np.RankWarning) +import Queue + +global measure_wlc +global EVT_MEASURE_WLC + +global events_from_fit +events_from_fit=Queue.Queue() #GUI ---> CLI COMMUNICATION + + +class multifitCommands: + + def do_multifit(self,args): + ''' + MULTIFIT + (multifit.py) + Presents curves for manual analysis in a comfortable mouse-only fashion. + Obtains contour length, persistance length, rupture force and + slope - loading rate. + WLC is shown in red, eFJC in blue. + ------------- + Syntax: + multifit [pl=value] [kl=value] [t=value] [slopew=value] [basew=value] + [slope2p] [justone] + + pl=[value] and kl=[value]: Use a fixed persistent length (WLC) or Kuhn + length (eFJC) 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. + eFJC fit works better with a fixed kl + 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. + + slopew and basew : width in points for slope fitting (points to the + right of clicked rupture) and base level fitting (points to + the left of clicked top of rupture). + If slopew is not provided, the routine will ask for a 5th + point to fit the slope. + DO NOT put spaces between 'slopew' or 'basew', '=' value. + + slope2p : calculates the slope from the two clicked points, + instead of fitting data between them + + justone : performs the fits over current curve instead of iterating + + See fit command help for more information on the options and fit + procedures. + NOTE: centerzero plot modifier should be activated (set centerzero 1). + ''' + + #NOTE duplicates a lot of code from do_fit in fit.py, a call to it could be used directly + #but it is easier to control the program flow bypassing it + + pl_value=None + kl_value=None + T=self.config['temperature'] + slopew=None + basew=15 + justone=False + twops=False + + #FIXME spaces are not allowed between pl or t and value + 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 + if 'kl=' in arg: + kl_expression=arg.split('=') + kl_value=float(kl_expression[1]) #actual value + #look for a T argument. + if ('t=' in arg) or ('T=' in arg): + t_expression=arg.split('=') + T=float(t_expression[1]) + #look for a basew argument. + if ('basew=' in arg): + basew_expression=arg.split('=') + basew=int(basew_expression[1]) + #look for a slopew argument. + if ('slopew=' in arg): + slopew_expression=arg.split('=') + slopew=int(slopew_expression[1]) + if('justone' in arg): + justone=True + if('slope2p' in arg): + twops=True + + counter=0 + savecounter=0 + curveindex=0 + + if not justone: + print 'What curve no. you would like to start? (enter for ignoring)' + skip=raw_input() + + if skip.isdigit()==False: + skip=0 + else: + skip=int(skip)-1 + print 'Skipping '+str(skip)+ ' curves' + else: + skip=0 + #begin presenting curves for analysis + while curveindex curveindex: + curveindex+=1 + continue + + #give periodically the opportunity to stop the analysis + if counter%20==0 and counter>0: + print '\nYou checked '+str(counter)+' curves. Do you want to continue?' + self.current=curve + self.do_plot(0) + if self.YNclick(): + print 'Going on...' + else: + break + else: + self.current=curve + self.do_plot(0) + else: + curve=self.current + self.do_plot(0) + if not justone: + print '\nCurve '+str(curveindex+1)+' of '+str(len(self.current_list)) + print 'Click contact point or left end (red area)of the curve to skip' + #hightlights an area dedicated to reject current curve + sizeret=len(self.plots[0].vectors[1][0]) + noarea=self.plots[0].vectors[1][0][-sizeret/6:-1] + noareaplot=copy.deepcopy(self._get_displayed_plot()) + #noise dependent slight shift to improve visibility + noareaplot.add_set(noarea,np.ones_like(noarea)*5.0*np.std(self.plots[0].vectors[1][1][-sizeret/6:-1])) + noareaplot.styles+=['scatter'] + noareaplot.colors+=["red"] + self._send_plot([noareaplot]) + contact_point=self._measure_N_points(N=1, whatset=1)[0] + contact_point_index=contact_point.index + noareaplot.remove_set(-1) + #remove set leaves some styles disturbing the next graph, fixed by doing do_plot + self.do_plot(0) + if contact_point_index>5.0/6.0*sizeret: + if justone: + break + curveindex+=1 + continue + + self.wlccontact_point=contact_point + self.wlccontact_index=contact_point.index + self.wlccurrent=self.current.path + + print 'Now click two points for the fitting area (one should be the rupture point)' + wlcpoints=self._measure_N_points(N=2,whatset=1) + print 'And one point of the top of the jump' + toppoint=self._measure_N_points(N=1,whatset=1) + slopepoint=ClickedPoint() + if slopew==None: + print 'Click a point to calculate slope' + slopepoint=self._measure_N_points(N=1,whatset=1) + + fitpoints=[contact_point]+wlcpoints + #use the currently displayed plot for the fit + displayed_plot=self._get_displayed_plot() + + #use both fit functions + try: + wlcparams, wlcyfit, wlcxfit, wlcfit_errors,wlc_qstd = self.wlc_fit(fitpoints, displayed_plot.vectors[1][0], displayed_plot.vectors[1][1],pl_value,T, return_errors=True ) + wlcerror=False + except: + print 'WLC fit not possible' + wlcerror=True + + try: + fjcparams, fjcyfit, fjcxfit, fjcfit_errors,fjc_qstd = self.efjc_fit(fitpoints, displayed_plot.vectors[1][0], displayed_plot.vectors[1][1],kl_value,T, return_errors=True ) + fjcerror=False + except: + print 'eFJC fit not possible' + fjcerror=True + + #Measure rupture force + ruptpoint=ClickedPoint() + if wlcpoints[0].graph_coords[1]= len(curveset): + print 'End of the list' + print 'WARNING: maybe you want to finish!' + break + nextitem=curveset[i] + if not nextitem.identify(self.drivers): + continue + nextplot=self.plotmanip_correct(nextitem.curve.default_plots()[0],nextitem) + nextvect=nextplot.vectors + nextitem.curve.close_all() + + nextx=nextvect[1][0] + nexty=nextvect[1][1] + #center y around 0 + ymedian=np.median(nexty) + pos=0 + for j in range(0,len(nextx)): + nextx[j]=nextx[j]+i*xgap + nexty[j]=nexty[j]+i*ygap-ymedian + multiplot.add_set(nextx,nexty) + multiplot.styles.append('lines') + multiplot.colors.append(None) + + self._send_plot([multiplot]) + + + print 'Which ones you want to keep?' + keep=raw_input() + if keep.isalpha(): + if keep=='b': + print 'Going back ten curves' + c-=10 + if c<0: + print 'We are already at the start' + c=0 + continue + if keep=='q': + break + else: + for i in keep.split(): + if i.isdigit() and int(i)>0 and int(i)<11: #if it is not digit the int() call is never made, so no exception should be happening + keep_item=curveset[int(i)-1].path + if keep_item in keep_list: + print 'This curve ('+keep_item+') was already selected, skipping' + else: + keep_list.append(keep_item) + else: + print 'You entered an invalid value: '+i + + c+=10 + + #FIXME I don't know why the print below gives errors sometimes + try: + print 'Kept '+str(len(keep_list))+' curves from '+str(min(c+i+1,len(self.current_list))) + except: + print 'Display error, never mind, we continue. Below the amount of kept and total curves:' + print str(len(keep_list)) + print str(len(self.current_list)) + + allok=0 #flag to keep from losing all the work in a slight mistake + while allok==0: + if len(keep_list) == 0: + return + save=linp.safeinput('Do you want to save the selected curves?',['y','n']) + if save=='y': + savedir=linp.safeinput('Destination directory?') + savedir=os.path.abspath(savedir) + if not os.path.isdir(savedir): + print 'Destination is not a directory. Try again' + continue + if save=='n': + allok=1 + return + + for item in keep_list: + try: + shutil.copy(item, savedir) + allok=1 + except (OSError, IOError): + print 'Cannot copy file. '+item+' Perhaps you gave me a wrong directory?' + allok=0 + break + + return