2 TUTORIAL PLUGIN FOR HOOKE
4 This plugin contains example commands to teach how to write an Hooke plugin, including description of main Hooke
11 from .. import curve as lhc
14 SYNTAX OF DATA TYPE DECLARATION:
16 [ type ] = list containing objects of type
17 {typekey:typearg} = dictionary with keys of type typekey and args of type typearg
18 ( type ) = tuple containing objects of type
22 class tutorialCommands(object):
24 Here we define the class containing all the Hooke commands we want to define
27 Notice the class name!!
28 The syntax is filenameCommands. That is, if your plugin is pluggy.py, your class
29 name is pluggyCommands.
31 Otherwise, the class will be ignored by Hooke.
36 This is the plugin initialization.
37 When Hooke starts and the plugin is loaded, this function is executed.
38 If there is something you need to do when Hooke starts, code it in this function.
40 print 'I am the Tutorial plugin initialization!'
42 #Here we initialize a local configuration variable; see plotmanip_absvalue() for explanation.
43 self.config['tutorial_absvalue']=0
46 def do_nothing(self,args):
48 This is a boring but working example of an actual Hooke command.
49 A Hooke command is a function of the xxxxCommands class, which is ALWAYS defined
52 def do_nameofcommand(self,args)
54 *do_ is needed to make Hooke understand this function is a command
55 *nameofcommand is how the command will be called in the Hooke command line.
57 *args is ALWAYS needed (otherwise Hooke will crash executing the command). We will see
60 Note that if you now start Hooke with this plugin activated and you type in the Hooke command
61 line "help nothing" you will see this very text as output. So the help of a command is a
62 string comment below the function definition, like this one.
64 Commands usually return None.
66 print 'I am a Hooke command. I do nothing.'
68 def do_printargs(self,args):
70 This command prints the args you give to it.
71 args is always a string, that contains everything you write after the command.
72 So if you issue "mycommand blah blah 12345" args is "blah blah 12345".
74 Again, args is needed in the definition even if your command does not use it.
76 print 'You gave me those args: '+args
78 def help_tutorial(self):
80 This is a help function.
81 If you want a help function for something that is not a command, you can write a help
82 function like this. Calling "help tutorial" will execute this function.
84 print 'You called help_tutorial()'
86 def do_environment(self,args):
88 This plugin contains a panoramic of the Hooke command line environment variables,
89 and prints their current value.
93 TYPE: [ curve.HookeCurve ], len=variable
94 contains the actual playlist of Hooke curve objects.
95 Each HookeCurve object represents a reference to a data file.
96 We will see later in detail how do they work.
98 print 'current_list length:',len(self.current_list)
99 print 'current_list 0th:',self.current_list[0]
103 contains the index of
104 the current curve in the playlist
106 print 'pointer: ',self.pointer
109 TYPE: curve.HookeCurve
110 contains the current curve displayed.
111 We will see later how it works.
113 print 'current:',self.current
116 TYPE: [ curve.PlotObject ], len=1,2
117 contains the current default plots.
118 Each PlotObject contains all info needed to display
119 the plot: apart from the data vectors, the title, destination
121 Usually self.plots[0] is the default topmost plot, self.plots[1] is the
122 accessory bottom plot.
124 print 'plots:',self.plots
127 TYPE: { string:anything }
128 contains the current Hooke configuration variables, in form of a dictionary.
130 print 'config:',self.config
134 Contains the ordered plot manipulation functions.
135 These functions are called to modify the default plot by default before it is plotted.
136 self.plots contains the plot passed through the plot manipulators.
137 We will see it better later.
138 *YOU SHOULD NEVER MODIFY THAT*
140 print 'plotmanip: ',self.plotmanip
144 Contains the plot reading drivers.
145 *YOU SHOULD NEVER MODIFY THAT*
147 print 'drivers: ',self.drivers
151 Contains the wx Frame of the GUI.
152 ***NEVER, EVER TOUCH THAT.***
154 print 'frame: ',self.frame
156 '''self.list_of_events
157 TYPE: { string:wx.Event }
158 Contains the wx.Events to communicate with the GUI.
159 Usually not necessary to use it, unless you want
160 to create a GUI plugin.
162 print 'list of events:',self.list_of_events
164 '''self.events_from_gui
166 Contains the Queue where data from the GUI is put.
167 Usually not necessary to use it, unless you want
168 to create a GUI plugin.
170 print 'events from gui:',self.events_from_gui
172 '''self.playlist_saved
173 TYPE: Int (0/1) ; Boolean
174 Flag that tells if the playlist has been saved or not.
176 print 'playlist saved:',self.playlist_saved
178 '''self.playlist_name
180 Name of current playlist
182 print 'playlist name:',self.playlist_name
185 TYPE: Int (0/1) ; Boolean
186 Flag that tells if the playlist has been saved or not.
188 print 'notes saved:',self.notes_saved
191 def do_myfirstplot(self,args):
193 In this function, we see how to create a PlotObject and send it to the screen.
194 ***Read the code of PlotObject in curve.py before!***.
197 #We generate some interesting data to plot for this example.
198 xdata1=np.arange(-5,5,0.1)
199 xdata2=np.arange(-5,5,0.1)
200 ydata1=[item**2 for item in xdata1]
201 ydata2=[item**3 for item in xdata2]
204 #The PlotObject class lives in the curve library.
205 myplot=lhc.PlotObject()
207 The *data* of the plot live in the .vectors list.
209 plot.vectors is a multidimensional array:
212 plot.vectors[2]=sett3
215 2 curves in a x,y plot are:
216 [[[x1],[y1]],[[x2],[y2]]]
219 [[[1,2,3,4],[10,20,30,40]],[[3,6,9,12],[30,60,90,120]]]
220 x1 = self.vectors[0][0]
221 y1 = self.vectors[0][1]
222 x2 = self.vectors[1][0]
223 y2 = self.vectors[1][1]
225 #Pour 0-th dataset into myplot:
226 myplot.add_set(xdata1,ydata1)
228 #Pour 1-st dataset into myplot:
229 myplot.add_set(xdata2,ydata2)
231 #Add units to x and y axes
232 #units=[string, string]
233 myplot.units=['x axis','y axis']
235 #Where do we want the plot? 0=top, 1=bottom
238 '''Send it to the GUI.
239 Note that you *have* to encapsulate it into a list, so you
240 have to send [myplot], not simply myplot.
242 You can also send more two plots at once
243 self.send_plot([plot1,plot2])
245 self._send_plot([myplot])
248 def do_myfirstscatter(self,args):
250 How to draw a scatter plot.
252 #We generate some interesting data to plot for this example.
253 xdata1=np.arange(-5,5,1)
254 xdata2=np.arange(-5,5,1)
255 ydata1=[item**2 for item in xdata1]
256 ydata2=[item**3 for item in xdata2]
258 myplot=lhc.PlotObject()
259 myplot.add_set(xdata1,ydata1)
260 myplot.add_set(xdata2,ydata2)
263 #Add units to x and y axes
264 myplot.units=['x axis','y axis']
266 #Where do we want the plot? 0=top, 1=bottom
269 '''None=standard line plot
270 'scatter'=scatter plot
271 By default, the styles attribute is an empty list. If you
272 want to define a scatter plot, you must define all other
273 plots as None or 'scatter', depending on what you want.
275 Here we define the second set to be plotted as scatter,
276 and the first to be plotted as line.
278 Here we define also the colors to be the default Matplotlib colors
280 myplot.styles=[None,'scatter']
281 myplot.colors=[None,None]
282 self._send_plot([myplot])
285 def do_clickaround(self,args):
287 Here we click two points on the curve and take some parameters from the points
292 points = self._measure_N_points(N=Int, whatset=Int)
293 *N = number of points to measure(1...n)
294 *whatset = data set to measure (0,1...n)
295 *points = a list of ClickedPoint objects, one for each point requested
297 points=self._measure_N_points(N=2,whatset=1)
298 print 'You clicked the following points.'
301 These are the absolute coordinates of the
305 print 'Absolute coordinates:'
306 print points[0].absolute_coords
307 print points[1].absolute_coords
311 These are the coordinates of the points
312 clicked, remapped on the graph.
313 Hooke looks at the graph point which X
314 coordinate is next to the X coordinate of
315 the point measured, and uses that point
316 as the actual clicked point.
319 print 'Coordinates on the graph:'
320 print points[0].graph_coords
321 print points[1].graph_coords
325 These are the indexes of the clicked points
326 on the dataset vector.
328 print 'Index of points on the graph:'
329 print points[0].index
330 print points[1].index
333 def help_thedifferentplots(self):
335 The *three* different default plots you should be familiar with
338 Each plot contains of course the respective data in their
339 vectors attribute, so here you learn also which data access for
343 1. THE RAW, CURRENT PLOTS
347 Contains the current curve.HookeCurve container object.
348 A HookeCurve object defines only two default attributes:
350 * self.current.path = string
351 The path of the current displayed curve
353 * self.current.curve = curve.Driver
354 The curve object. This is not only generated by the driver,
355 this IS a driver instance in itself.
356 This means that in self.current.curve you can access the
357 specific driver APIs, if you know them.
359 And defines only one method:
360 * self.current.identify()
361 Fills in the self.current.curve object.
362 See in the cycling tutorial.
365 The REAL curve data actually lives in:
367 * self.current.curve.default_plots() = [ libhooke.PlotObject ]
368 Contains the raw PlotObject-s, as "spitted out" by the driver, without any
370 This is as close to the raw data as Hooke gets.
372 One or two plots can be spit out; they are always enclosed in a list.
375 Methods of self.current.curve are:
378 * self.current.curve.is_me()
379 (Used by identify() only.)
381 * self.current.curve.close_all()
382 Closes all driver open files; see the cycling tutorial.
386 2. THE PROCESSED, DEFAULT PLOT
388 The plot that is spitted out by the driver is *not* the usual default plot
389 that is displayed by calling "plot" at the Hooke prompt.
391 This is because the raw, driver-generated plot is usually *processed* by so called
392 *plot processing* functions. We will see in the tutorial how to define
395 For example, in force spectroscopy force curves, raw data are automatically corrected
396 for deflection. Other data can be, say, filtered by default.
398 The default plots are accessible in
399 self.plots = [ libhooke.PlotObject ]
401 self.plots[0] is usually the topmost plot
402 self.plots[1] is usually the bottom plot (if present)
406 3. THE PLOT DISPLAYED RIGHT NOW.
408 Sometimes the plots you are displaying *right now* is different from the previous
409 two. You may have a fit trace, you may have issued some command that spits out
410 a custom plot and you want to rework that, whatever.
412 You can obtain in any moment the plot currently displayed by Hooke by issuing
414 PlotObject = self._get_displayed_plot(dest)
421 def do_cycling(self,args):
423 Here we cycle through our playlist and print some info on the curves we find.
424 Cycling through the playlist needs a bit of care to avoid memory leaks and dangling
427 Look at the source code for more information.
430 def things_when_cycling(item):
432 We encapsulate here everything has to open the actual curve file.
433 By doing it all here, we avoid to do acrobacies when deleting objects etc.
434 in the main loop: we do the dirty stuff here.
440 This method looks for the correct driver in self.drivers to use;
441 and puts the curve content in the .curve attribute.
442 Basically, until identify() is called, the HookeCurve object
443 is just an empty shell. When identify() is called (usually by
444 the Hooke plot routine), the HookeCurve object is "filled" with
448 item.identify(self.drivers)
451 After the identify(), item.curve contains the curve, and item.curve.default_plots() behaves exactly like
452 self.current.curve.default_plots() -but for the given item.
454 itplot=item.curve.default_plots()
456 print 'length of X1 vector:',len(itplot[0].vectors[0][0]) #just to show something
459 The following three lines are a magic spell you HAVE to do
460 before closing the function.
461 (Otherwise you will be plagued by unpredicatable, system-dependent bugs.)
463 item.curve.close_all() #Avoid open files dangling
464 del item.curve #Avoid memory leaks
465 del item #Just be paranoid. Don't ask.
471 for item in self.current_list:
472 print 'Looking at curve ',c,'of',len(self.current_list)
473 things_when_cycling(item)
480 def plotmanip_absvalue(self, plot, current, customvalue=None):
482 This function defines a PLOT MANIPULATOR.
483 A plot manipulator is a function that takes a plot in input, does something to the plot
484 and returns the modified plot in output.
485 The function, once plugged, gets automatically called everytime self.plots is updated
487 For example, in force spectroscopy force curves, raw data are automatically corrected
488 for deflection. Other data can be, say, filtered by default.
490 To create and activate a plot manipulator you have to:
491 * Write a function (like this) which name starts with "plotmanip_" (just like commands
493 * The function must support four arguments:
496 current : (usually not used, deprecated)
497 customvalue=None : a variable containing custom value(s) you need for your plot manipulators.
498 * The function must return a plot object.
499 * Add an entry in hooke.conf: if your function is "plotmanip_something" you will have
500 to add <something/> in the plotmanips section: example
509 Important: Plot manipulators are *in pipe*: each plot manipulator output becomes the input of the next one.
510 The order in hooke.conf *is the order* in which plot manipulators are connected, so in the example above
512 self.current.curve.default_plots() --> detriggerize --> correct --> median --> something --> self.plots
516 Here we see what is in a configuration variable to enable/disable the plot manipulator as user will using
517 the Hooke "set" command.
518 Typing "set tutorial_absvalue 0" disables the plot manipulator; typing "set tutorial_absvalue 1" will enable it.
520 if not self.config['tutorial_absvalue']:
523 #We do something to the plot, for demonstration's sake
524 #If we needed variables, we would have used customvalue.
525 plot.vectors[0][1]=[abs(i) for i in plot.vectors[0][1]]
526 plot.vectors[1][1]=[abs(i) for i in plot.vectors[1][1]]
528 #Return the plot object.
533 #how to add lines to an existing plot!!