4 TUTORIAL DRIVER FOR HOOKE
6 Example driver to teach how to write a driver for data types.
11 Here we define a (fake) file format that is read by this driver. The file format is as following:
45 that is, two plots with two datasets each.
48 import libhookecurve as lhc #We need to import this library to define some essential data types
50 class tutorialdriverDriver(lhc.Driver):
52 This is a *generic* driver, not a specific force spectroscopy driver.
53 See the written documentation to see what a force spectroscopy driver must be defined to take into account Hooke facilities.
55 Our driver is a class with the name convention nameofthedriverDriver, where "nameofthedriver" is the filename.
56 The driver must inherit from the parent class lhc.Driver, so the syntax is
57 class nameofthedriverDriver(lhc.Driver)
59 def __init__(self, filename):
61 THIS METHOD MUST BE DEFINED.
62 The __init__ method MUST call the filename, so that it can open the file.
64 self.filename=filename #self.filename can always be useful, and should be defined
65 self.filedata = open(filename,'r') #We open the file
67 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
68 with each item being a row.
69 Of course if your data files are binary, or follow a different approach, do whatever you need. :)
71 self.data = list(self.filedata)
72 self.filedata.close() #remember to close the file
74 '''These are two strings that can be used by Hooke commands/plugins to understand what they are looking at. They have no other
75 meaning. They have to be somehow defined however - commands often look for those variables.
77 self.filetype should contain the name of the exact filetype defined by the driver (so that filetype-specific commands can know
78 if they're dealing with the correct filetype)
79 self.experiment should contain instead the type of data involved (for example, various drivers can be used for force-clamp experiments,
80 but hooke commands could like to know if we're looking at force clamp data, regardless of their origin, and not other
83 Of course, all other variables you like can be defined in the class.
85 self.filetype = 'tutorial'
86 self.experiment = 'generic'
90 THIS METHOD MUST BE DEFINED.
91 RETURNS: Boolean (True or False)
92 This method must be an heuristic that looks at the file content and decides if the file can be opened by the driver itself.
93 It returns True if the file opened can be interpreted by the current driver, False otherwise.
94 Defining this method allows Hooke to understand what kind of files we're looking at automatically.
96 We have to re-open/re-close the file here.
99 myfile=open(self.filename, 'r')
100 headerline=myfile.readlines()[0] #we take the first line
104 Here, our "magic fingerprint" is the TUTORIAL_FILE header. Of course, depending on the data file, you can have interesting
105 headers, or patterns, etc. that you can use to guess the data format. What matters is successful recognizing, and returning
106 a boolean (True/False).
108 if headerline[:-1]=='TUTORIAL_FILE': #[:-1], otherwise the return character is included in the line
113 def _generate_vectors(self):
115 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
116 no big interest (I just wrote it to present a functional driver).
118 Only thing to remember, it can be nice to call methods that are used only "internally" by the driver (or by plugins) with a
119 "_" prefix, so to have a visual remark. But it's just an advice.
121 vectors={'PLOT1':[[],[],[],[]] , 'PLOT2':[[],[],[],[]]}
122 positions={'X1':0,'Y1':1,'X2':2,'Y2':3}
125 for item in self.data:
128 vectors[whatplot][pos].append(num)
130 if item[:-1]=='PLOT1':
132 elif item[:-1]=='PLOT2':
134 elif item[0]=='X' or item[0]=='Y':
135 pos=positions[item[:-1]]
143 THIS METHOD MUST BE DEFINED.
144 This method is a precaution method that is invoked when cycling to avoid eventually dangling open files.
145 In this method, all file objects defined in the driver must be closed.
147 self.filename.close()
150 def default_plots(self):
152 THIS METHOD MUST BE DEFINED.
153 RETURNS: [ lhc.PlotObject ] or [ lhc.PlotObject, lhc.PlotObject]
155 This is the method that returns the plots to Hooke.
156 It must return a list with *one* or *two* PlotObjects.
158 See the libhookecurve.py source code to see how PlotObjects are defined and work in detail.
160 gen_vectors=self._generate_vectors()
162 #Here we create the main plot PlotObject and initialize its vectors.
163 main_plot=lhc.PlotObject()
165 #The same for the other plot.
166 other_plot=lhc.PlotObject()
167 other_plot.vectors=[]
170 Now we fill the plot vectors with our data.
172 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.
174 The add_set() method takes care of this , just use plot.add_set(x,y).
176 main_plot.add_set(gen_vectors['PLOT1'][0],gen_vectors['PLOT1'][1])
177 main_plot.add_set(gen_vectors['PLOT1'][2],gen_vectors['PLOT1'][3])
179 other_plot.add_set(gen_vectors['PLOT2'][0],gen_vectors['PLOT2'][1])
180 other_plot.add_set(gen_vectors['PLOT2'][2],gen_vectors['PLOT2'][3])
183 normalize_vectors() trims the vectors, so that if two x/y couples are of different lengths, the latest
184 points are trimmed (otherwise we have a python error). Always a good idea to run it, to avoid crashes.
186 main_plot.normalize_vectors()
187 other_plot.normalize_vectors()
191 - units: [string, string], define the measure units of X and Y axes
192 - destination: 0/1 , defines where to plot the plot (0=top, 1=bottom), default=0
193 - title: string , the plot title.
196 Again, see libhookecurve.py comments for details.
198 main_plot.units=['unit of x','unit of y']
199 main_plot.destination=0
200 main_plot.title=self.filename+' main'
202 other_plot.units=['unit of x','unit of y']
203 other_plot.destination=1
204 other_plot.title=self.filename+' other'
206 return [main_plot, other_plot]