6 TUTORIAL DRIVER FOR HOOKE
8 Example driver to teach how to write a driver for data types.
13 Here we define a (fake) file format that is read by this driver. The file format is as following:
47 that is, two plots with two datasets each.
50 import libhookecurve as lhc #We need to import this library to define some essential data types
52 class tutorialdriverDriver(lhc.Driver):
54 This is a *generic* driver, not a specific force spectroscopy driver.
55 See the written documentation to see what a force spectroscopy driver must be defined to take into account Hooke facilities.
57 Our driver is a class with the name convention nameofthedriverDriver, where "nameofthedriver" is the filename.
58 The driver must inherit from the parent class lhc.Driver, so the syntax is
59 class nameofthedriverDriver(lhc.Driver)
61 def __init__(self, filename):
63 THIS METHOD MUST BE DEFINED.
64 The __init__ method MUST call the filename, so that it can open the file.
66 self.filename=filename #self.filename can always be useful, and should be defined
67 self.filedata = open(filename,'r') #We open the file
69 In this case, we have a data format that is just a list of ASCII values, so we can just divide that in rows, and generate a list
70 with each item being a row.
71 Of course if your data files are binary, or follow a different approach, do whatever you need. :)
73 self.data = list(self.filedata)
74 self.filedata.close() #remember to close the file
76 '''These are two strings that can be used by Hooke commands/plugins to understand what they are looking at. They have no other
77 meaning. They have to be somehow defined however - commands often look for those variables.
79 self.filetype should contain the name of the exact filetype defined by the driver (so that filetype-specific commands can know
80 if they're dealing with the correct filetype)
81 self.experiment should contain instead the type of data involved (for example, various drivers can be used for force-clamp experiments,
82 but hooke commands could like to know if we're looking at force clamp data, regardless of their origin, and not other
85 Of course, all other variables you like can be defined in the class.
87 self.filetype = 'tutorial'
88 self.experiment = 'generic'
92 THIS METHOD MUST BE DEFINED.
93 RETURNS: Boolean (True or False)
94 This method must be an heuristic that looks at the file content and decides if the file can be opened by the driver itself.
95 It returns True if the file opened can be interpreted by the current driver, False otherwise.
96 Defining this method allows Hooke to understand what kind of files we're looking at automatically.
98 We have to re-open/re-close the file here.
101 myfile=open(self.filename, 'r')
102 headerline=myfile.readlines()[0] #we take the first line
106 Here, our "magic fingerprint" is the TUTORIAL_FILE header. Of course, depending on the data file, you can have interesting
107 headers, or patterns, etc. that you can use to guess the data format. What matters is successful recognizing, and returning
108 a boolean (True/False).
110 if headerline[:-1]=='TUTORIAL_FILE': #[:-1], otherwise the return character is included in the line
115 def _generate_vectors(self):
117 Here we parse the data and generate the raw vectors. This method has only to do with the peculiar file format here, so it's of
118 no big interest (I just wrote it to present a functional driver).
120 Only thing to remember, it can be nice to call methods that are used only "internally" by the driver (or by plugins) with a
121 "_" prefix, so to have a visual remark. But it's just an advice.
123 vectors={'PLOT1':[[],[],[],[]] , 'PLOT2':[[],[],[],[]]}
124 positions={'X1':0,'Y1':1,'X2':2,'Y2':3}
127 for item in self.data:
130 vectors[whatplot][pos].append(num)
132 if item[:-1]=='PLOT1':
134 elif item[:-1]=='PLOT2':
136 elif item[0]=='X' or item[0]=='Y':
137 pos=positions[item[:-1]]
145 THIS METHOD MUST BE DEFINED.
146 This method is a precaution method that is invoked when cycling to avoid eventually dangling open files.
147 In this method, all file objects defined in the driver must be closed.
149 self.filename.close()
152 def default_plots(self):
154 THIS METHOD MUST BE DEFINED.
155 RETURNS: [ lhc.PlotObject ] or [ lhc.PlotObject, lhc.PlotObject]
157 This is the method that returns the plots to Hooke.
158 It must return a list with *one* or *two* PlotObjects.
160 See the libhookecurve.py source code to see how PlotObjects are defined and work in detail.
162 gen_vectors=self._generate_vectors()
164 #Here we create the main plot PlotObject and initialize its vectors.
165 main_plot=lhc.PlotObject()
167 #The same for the other plot.
168 other_plot=lhc.PlotObject()
169 other_plot.vectors=[]
172 Now we fill the plot vectors with our data.
174 The "correct" shape of the vector is [ [[x1,x2,x3...],[y1,y2,y3...]] , [[x1,x2,x3...],[y1,y2,y3...]] ], so we have to put stuff in this way into it.
176 The add_set() method takes care of this , just use plot.add_set(x,y).
178 main_plot.add_set(gen_vectors['PLOT1'][0],gen_vectors['PLOT1'][1])
179 main_plot.add_set(gen_vectors['PLOT1'][2],gen_vectors['PLOT1'][3])
181 other_plot.add_set(gen_vectors['PLOT2'][0],gen_vectors['PLOT2'][1])
182 other_plot.add_set(gen_vectors['PLOT2'][2],gen_vectors['PLOT2'][3])
185 normalize_vectors() trims the vectors, so that if two x/y couples are of different lengths, the latest
186 points are trimmed (otherwise we have a python error). Always a good idea to run it, to avoid crashes.
188 main_plot.normalize_vectors()
189 other_plot.normalize_vectors()
193 - units: [string, string], define the measure units of X and Y axes
194 - destination: 0/1 , defines where to plot the plot (0=top, 1=bottom), default=0
195 - title: string , the plot title.
198 Again, see libhookecurve.py comments for details.
200 main_plot.units=['unit of x','unit of y']
201 main_plot.destination=0
202 main_plot.title=self.filename+' main'
204 other_plot.units=['unit of x','unit of y']
205 other_plot.destination=1
206 other_plot.title=self.filename+' other'
208 return [main_plot, other_plot]