Ran update_copyright.py, updating all the copyright blurbs and adding AUTHORS.
[hooke.git] / hooke / plugin / curvetools.py
1 # Copyright (C) 2010 Fabrizio Benedetti
2 #                    W. Trevor King <wking@drexel.edu>
3 #
4 # This file is part of Hooke.
5 #
6 # Hooke is free software: you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation, either
9 # version 3 of the License, or (at your option) any later version.
10 #
11 # Hooke is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU Lesser General Public License for more details.
15 #
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with Hooke.  If not, see
18 # <http://www.gnu.org/licenses/>.
19
20 from ..libhooke import WX_GOOD, ClickedPoint
21
22 import wxversion
23 wxversion.select(WX_GOOD)
24 from wx import PostEvent
25 import numpy as np
26 import scipy as sp
27 import copy
28 import os.path
29 import time
30
31
32 class curvetoolsCommands:
33
34       def fit_interval_nm(self,start_index,plot,nm,backwards):
35           '''
36           Calculates the number of points to fit, given a fit interval in nm
37           start_index: index of point
38           plot: plot to use
39           backwards: if true, finds a point backwards.
40           '''
41           whatset=1 #FIXME: should be decidable
42           x_vect=plot.vectors[1][0]
43           
44           c=0
45           i=start_index
46           start=x_vect[start_index]
47           maxlen=len(x_vect)
48           while abs(x_vect[i]-x_vect[start_index])*(10**9) < nm:
49               if i==0 or i==maxlen-1: #we reached boundaries of vector!
50                   return c
51               
52               if backwards:
53                   i-=1
54               else:
55                   i+=1
56               c+=1
57           return c
58
59
60
61       def find_current_peaks(self,noflatten, a=True, maxpeak=True):
62             #Find peaks.
63             if a==True:
64                   a=self.convfilt_config['mindeviation']
65             try:
66                   abs_devs=float(a)
67             except:
68                   print "Bad input, using default."
69                   abs_devs=self.convfilt_config['mindeviation']
70
71             defplot=self.current.curve.default_plots()[0]
72             if not noflatten:
73                 flatten=self._find_plotmanip('flatten') #Extract flatten plotmanip
74                 defplot=flatten(defplot, self.current, customvalue=1) #Flatten curve before feeding it to has_peaks
75             pk_location,peak_size=self.has_peaks(defplot, abs_devs, maxpeak)
76             return pk_location, peak_size
77
78
79       def pickup_contact_point(self,N=1,whatset=1):
80             '''macro to pick up the contact point by clicking'''
81             contact_point=self._measure_N_points(N=1, whatset=1)[0]
82             contact_point_index=contact_point.index
83             self.wlccontact_point=contact_point
84             self.wlccontact_index=contact_point.index
85             self.wlccurrent=self.current.path
86             return contact_point, contact_point_index
87
88
89
90       def baseline_points(self,peak_location, displayed_plot):
91             clicks=self.config['baseline_clicks']
92             if clicks==0:
93                 self.basepoints=[]
94                 base_index_0=peak_location[-1]+self.fit_interval_nm(peak_location[-1], displayed_plot, self.config['auto_right_baseline'],False)
95                 self.basepoints.append(self._clickize(displayed_plot.vectors[1][0],displayed_plot.vectors[1][1],base_index_0))
96                 base_index_1=self.basepoints[0].index+self.fit_interval_nm(self.basepoints[0].index, displayed_plot, self.config['auto_left_baseline'],False)
97                 self.basepoints.append(self._clickize(displayed_plot.vectors[1][0],displayed_plot.vectors[1][1],base_index_1))
98             elif clicks>0:
99                 print 'Select baseline'
100                 if clicks==1:
101                     self.basepoints=self._measure_N_points(N=1, whatset=1)
102                     base_index_1=self.basepoints[0].index+self.fit_interval_nm(self.basepoints[0].index, displayed_plot, self.config['auto_left_baseline'], False)
103                     self.basepoints.append(self._clickize(displayed_plot.vectors[1][0],displayed_plot.vectors[1][1],base_index_1))
104                 else:
105                     self.basepoints=self._measure_N_points(N=2, whatset=1)
106             
107             self.basecurrent=self.current.path
108             return self.basepoints
109
110
111
112 class InfoCommand (Command):
113     """Execute a system command and report the output.
114     """
115     def __init__(self):
116         super(SystemCommand, self).__init__(
117             name='system',
118             arguments=[
119                 Argument(
120     name='command', type='string', optional=False, count=-1,
121     help="""
122 Command line to execute.
123 """.strip())
124 ],
125             help=self.__doc__)
126
127     def _run(self, hooke, inqueue, outqueue, params):
128         os.system(params['command'])
129
130     def do_info(self,args):
131         '''
132         INFO
133         ----
134         Returns informations about the current curve.
135         '''
136         print 'Path: ',self.current.path
137         print 'Experiment: ',self.current.curve.experiment
138         print 'Filetype: ',self.current.curve.filetype
139         for plot in self.current.curve.default_plots():
140             for set in plot.vectors:
141                 lengths=[len(item) for item in set]
142                 print 'Data set size: ',lengths
143
144
145     def help_current(self):
146         print '''
147 CURRENT
148 Prints the current curve path.
149 ------
150 Syntax: current
151         '''
152     def do_current(self,args):
153         print self.current.path
154
155
156     def help_txt(self):
157         print '''
158 TXT
159 Saves the current curve as a text file
160 Columns are, in order:
161 X1 , Y1 , X2 , Y2 , X3 , Y3 ...
162
163 -------------
164 Syntax: txt [filename] {plot to export}
165         '''
166     def do_txt(self,args):
167
168         def transposed2(lists, defval=0):
169             '''
170             transposes a list of lists, i.e. from [[a,b,c],[x,y,z]] to [[a,x],[b,y],[c,z]] without losing
171             elements
172             (by Zoran Isailovski on the Python Cookbook online)
173             '''
174             if not lists: return []
175             return map(lambda *row: [elem or defval for elem in row], *lists)
176
177         whichplot=0
178         args=args.split()
179         if len(args)==0:
180             filename=linp.safeinput('Filename?',[self.current.path+'.txt'])
181         else:
182             filename=linp.checkalphainput(args[0],self.current.path+'.txt',[])
183             try:
184                 whichplot=int(args[1])
185             except:
186                 pass
187
188         try:
189             outofplot=self.plots[whichplot].vectors
190         except:
191             print "Plot index out of range."
192             return 0
193
194         columns=[]     
195         for dataset in self.plots[whichplot].vectors:
196             for i in range(0,len(dataset)):
197                 columns.append([])
198                 for value in dataset[i]:
199                     columns[-1].append(str(value))
200
201         rows=transposed2(columns, 'nan')
202         rows=[' , '.join(item) for item in rows]
203         text='\n'.join(rows)
204
205         txtfile=open(filename,'w+')
206         #Save units of measure in header
207         txtfile.write('X:'+self.plots[whichplot].units[0]+'\n')
208         txtfile.write('Y:'+self.plots[whichplot].units[1]+'\n')
209         txtfile.write(text)
210         txtfile.close()