4 TUTORIAL PLUGIN FOR HOOKE
6 This plugin contains example commands to teach how to write an Hooke plugin, including description of main Hooke
11 import libhookecurve as lhc
16 SYNTAX OF DATA TYPE DECLARATION:
18 [ type ] = list containing objects of type
19 {typekey:typearg} = dictionary with keys of type typekey and args of type typearg
20 ( type ) = tuple containing objects of type
24 class tutorialCommands:
26 Here we define the class containing all the Hooke commands we want to define
29 Notice the class name!!
30 The syntax is filenameCommands. That is, if your plugin is pluggy.py, your class
31 name is pluggyCommands.
33 Otherwise, the class will be ignored by Hooke.
38 This is the plugin initialization.
39 When Hooke starts and the plugin is loaded, this function is executed.
40 If there is something you need to do when Hooke starts, code it in this function.
42 print 'I am the Tutorial plugin initialization!'
44 #Here we initialize a local configuration variable; see plotmanip_absvalue() for explanation.
45 self.config['tutorial_absvalue']=0
48 def do_nothing(self,args):
50 This is a boring but working example of an actual Hooke command.
51 A Hooke command is a function of the xxxxCommands class, which is ALWAYS defined
54 def do_nameofcommand(self,args)
56 *do_ is needed to make Hooke understand this function is a command
57 *nameofcommand is how the command will be called in the Hooke command line.
59 *args is ALWAYS needed (otherwise Hooke will crash executing the command). We will see
62 Note that if you now start Hooke with this plugin activated and you type in the Hooke command
63 line "help nothing" you will see this very text as output. So the help of a command is a
64 string comment below the function definition, like this one.
66 Commands usually return None.
68 print 'I am a Hooke command. I do nothing.'
70 def do_printargs(self,args):
72 This command prints the args you give to it.
73 args is always a string, that contains everything you write after the command.
74 So if you issue "mycommand blah blah 12345" args is "blah blah 12345".
76 Again, args is needed in the definition even if your command does not use it.
78 print 'You gave me those args: '+args
80 def help_tutorial(self):
82 This is a help function.
83 If you want a help function for something that is not a command, you can write a help
84 function like this. Calling "help tutorial" will execute this function.
86 print 'You called help_tutorial()'
88 def do_environment(self,args):
90 This plugin contains a panoramic of the Hooke command line environment variables,
91 and prints their current value.
95 TYPE: [ libhookecurve.HookeCurve ], len=variable
96 contains the actual playlist of Hooke curve objects.
97 Each HookeCurve object represents a reference to a data file.
98 We will see later in detail how do they work.
100 print 'current_list length:',len(self.current_list)
101 print 'current_list 0th:',self.current_list[0]
105 contains the index of
106 the current curve in the playlist
108 print 'pointer: ',self.pointer
111 TYPE: libhookecurve.HookeCurve
112 contains the current curve displayed.
113 We will see later how it works.
115 print 'current:',self.current
118 TYPE: [ libhookecurve.PlotObject ], len=1,2
119 contains the current default plots.
120 Each PlotObject contains all info needed to display
121 the plot: apart from the data vectors, the title, destination
123 Usually self.plots[0] is the default topmost plot, self.plots[1] is the
124 accessory bottom plot.
126 print 'plots:',self.plots
129 TYPE: { string:anything }
130 contains the current Hooke configuration variables, in form of a dictionary.
132 print 'config:',self.config
136 Contains the ordered plot manipulation functions.
137 These functions are called to modify the default plot by default before it is plotted.
138 self.plots contains the plot passed through the plot manipulators.
139 We will see it better later.
140 *YOU SHOULD NEVER MODIFY THAT*
142 print 'plotmanip: ',self.plotmanip
146 Contains the plot reading drivers.
147 *YOU SHOULD NEVER MODIFY THAT*
149 print 'drivers: ',self.drivers
153 Contains the wx Frame of the GUI.
154 ***NEVER, EVER TOUCH THAT.***
156 print 'frame: ',self.frame
158 '''self.list_of_events
159 TYPE: { string:wx.Event }
160 Contains the wx.Events to communicate with the GUI.
161 Usually not necessary to use it, unless you want
162 to create a GUI plugin.
164 print 'list of events:',self.list_of_events
166 '''self.events_from_gui
168 Contains the Queue where data from the GUI is put.
169 Usually not necessary to use it, unless you want
170 to create a GUI plugin.
172 print 'events from gui:',self.events_from_gui
174 '''self.playlist_saved
175 TYPE: Int (0/1) ; Boolean
176 Flag that tells if the playlist has been saved or not.
178 print 'playlist saved:',self.playlist_saved
180 '''self.playlist_name
182 Name of current playlist
184 print 'playlist name:',self.playlist_name
187 TYPE: Int (0/1) ; Boolean
188 Flag that tells if the playlist has been saved or not.
190 print 'notes saved:',self.notes_saved
193 def do_myfirstplot(self,args):
195 In this function, we see how to create a PlotObject and send it to the screen.
196 ***Read the code of PlotObject in libhookecurve.py before!***.
199 #We generate some interesting data to plot for this example.
200 xdata1=np.arange(-5,5,0.1)
201 xdata2=np.arange(-5,5,0.1)
202 ydata1=[item**2 for item in xdata1]
203 ydata2=[item**3 for item in xdata2]
206 #The PlotObject class lives in the libhookecurve library.
207 myplot=lhc.PlotObject()
208 myplot.vectors=[[],[]] #Decide we will have two data sets in this plot
210 The *data* of the plot live in the .vectors list.
212 plot.vectors is a multidimensional array:
215 plot.vectors[2]=sett3
218 2 curves in a x,y plot are:
219 [[[x1],[y1]],[[x2],[y2]]]
222 [[[1,2,3,4],[10,20,30,40]],[[3,6,9,12],[30,60,90,120]]]
223 x1 = self.vectors[0][0]
224 y1 = self.vectors[0][1]
225 x2 = self.vectors[1][0]
226 y2 = self.vectors[1][1]
228 #Pour 0-th dataset into myplot:
229 myplot.vectors[0].append(xdata1) #...x
230 myplot.vectors[0].append(ydata1) #...then y
232 #Pour 1-st dataset into myplot:
233 myplot.vectors[1].append(xdata2) #...x
234 myplot.vectors[1].append(ydata2) #...then y
236 #Add units to x and y axes
237 #units=[string, string]
238 myplot.units=['x axis','y axis']
240 #Where do we want the plot? 0=top, 1=bottom
243 '''Send it to the GUI.
244 Note that you *have* to encapsulate it into a list, so you
245 have to send [myplot], not simply myplot.
247 You can also send more two plots at once
248 self.send_plot([plot1,plot2])
250 self._send_plot([myplot])
253 def do_myfirstscatter(self,args):
255 How to draw a scatter plot.
257 #We generate some interesting data to plot for this example.
258 xdata1=np.arange(-5,5,1)
259 xdata2=np.arange(-5,5,1)
260 ydata1=[item**2 for item in xdata1]
261 ydata2=[item**3 for item in xdata2]
263 myplot=lhc.PlotObject()
264 myplot.vectors=[[],[]]
265 #Pour 0-th dataset into myplot:
266 myplot.vectors[0].append(xdata1) #...x
267 myplot.vectors[0].append(ydata1) #...then y
269 #Pour 1-st dataset into myplot:
270 myplot.vectors[1].append(xdata2) #...x
271 myplot.vectors[1].append(ydata2) #...then y
273 #Add units to x and y axes
274 myplot.units=['x axis','y axis']
276 #Where do we want the plot? 0=top, 1=bottom
279 '''None=standard line plot
280 'scatter'=scatter plot
281 By default, the styles attribute is an empty list. If you
282 want to define a scatter plot, you must define all other
283 plots as None or 'scatter', depending on what you want.
285 Here we define the second set to be plotted as scatter,
286 and the first to be plotted as line.
288 myplot.styles=[None,'scatter']
290 self._send_plot([myplot])
293 def do_clickaround(self,args):
295 Here we click two points on the curve and take some parameters from the points
300 points = self._measure_N_points(N=Int, whatset=Int)
301 *N = number of points to measure(1...n)
302 *whatset = data set to measure (0,1...n)
303 *points = a list of ClickedPoint objects, one for each point requested
305 points=self._measure_N_points(N=2,whatset=1)
306 print 'You clicked the following points.'
309 These are the absolute coordinates of the
313 print 'Absolute coordinates:'
314 print points[0].absolute_coords
315 print points[1].absolute_coords
319 These are the coordinates of the points
320 clicked, remapped on the graph.
321 Hooke looks at the graph point which X
322 coordinate is next to the X coordinate of
323 the point measured, and uses that point
324 as the actual clicked point.
327 print 'Coordinates on the graph:'
328 print points[0].graph_coords
329 print points[1].graph_coords
333 These are the indexes of the clicked points
334 on the dataset vector.
336 print 'Index of points on the graph:'
337 print points[0].index
338 print points[1].index
341 def help_thedifferentplots(self):
343 The *three* different default plots you should be familiar with
346 Each plot contains of course the respective data in their
347 vectors attribute, so here you learn also which data access for
351 1. THE RAW, CURRENT PLOTS
355 Contains the current libhookecurve.HookeCurve container object.
356 A HookeCurve object defines only two default attributes:
358 * self.current.path = string
359 The path of the current displayed curve
361 * self.current.curve = libhookecurve.Driver
362 The curve object. This is not only generated by the driver,
363 this IS a driver instance in itself.
364 This means that in self.current.curve you can access the
365 specific driver APIs, if you know them.
367 And defines only one method:
368 * self.current.identify()
369 Fills in the self.current.curve object.
370 See in the cycling tutorial.
373 The REAL curve data actually lives in:
375 * self.current.curve.default_plots() = [ libhooke.PlotObject ]
376 Contains the raw PlotObject-s, as "spitted out" by the driver, without any
378 This is as close to the raw data as Hooke gets.
380 One or two plots can be spit out; they are always enclosed in a list.
383 Methods of self.current.curve are:
386 * self.current.curve.is_me()
387 (Used by identify() only.)
389 * self.current.curve.close_all()
390 Closes all driver open files; see the cycling tutorial.
394 2. THE PROCESSED, DEFAULT PLOT
396 The plot that is spitted out by the driver is *not* the usual default plot
397 that is displayed by calling "plot" at the Hooke prompt.
399 This is because the raw, driver-generated plot is usually *processed* by so called
400 *plot processing* functions. We will see in the tutorial how to define
403 For example, in force spectroscopy force curves, raw data are automatically corrected
404 for deflection. Other data can be, say, filtered by default.
406 The default plots are accessible in
407 self.plots = [ libhooke.PlotObject ]
409 self.plots[0] is usually the topmost plot
410 self.plots[1] is usually the bottom plot (if present)
414 3. THE PLOT DISPLAYED RIGHT NOW.
416 Sometimes the plots you are displaying *right now* is different from the previous
417 two. You may have a fit trace, you may have issued some command that spits out
418 a custom plot and you want to rework that, whatever.
420 You can obtain in any moment the plot currently displayed by Hooke by issuing
422 PlotObject = self._get_displayed_plot(dest)
429 def do_cycling(self,args):
431 Here we cycle through our playlist and print some info on the curves we find.
432 Cycling through the playlist needs a bit of care to avoid memory leaks and dangling
435 Look at the source code for more information.
438 def things_when_cycling(item):
440 We encapsulate here everything has to open the actual curve file.
441 By doing it all here, we avoid to do acrobacies when deleting objects etc.
442 in the main loop: we do the dirty stuff here.
448 This method looks for the correct driver in self.drivers to use;
449 and puts the curve content in the .curve attribute.
450 Basically, until identify() is called, the HookeCurve object
451 is just an empty shell. When identify() is called (usually by
452 the Hooke plot routine), the HookeCurve object is "filled" with
456 item.identify(self.drivers)
459 After the identify(), item.curve contains the curve, and item.curve.default_plots() behaves exactly like
460 self.current.curve.default_plots() -but for the given item.
462 itplot=item.curve.default_plots()
464 print 'length of X1 vector:',len(itplot[0].vectors[0][0]) #just to show something
467 The following three lines are a magic spell you HAVE to do
468 before closing the function.
469 (Otherwise you will be plagued by unpredicatable, system-dependent bugs.)
471 item.curve.close_all() #Avoid open files dangling
472 del item.curve #Avoid memory leaks
473 del item #Just be paranoid. Don't ask.
479 for item in self.current_list:
480 print 'Looking at curve ',c,'of',len(self.current_list)
481 things_when_cycling(item)
488 def plotmanip_absvalue(self, plot, current, customvalue=None):
490 This function defines a PLOT MANIPULATOR.
491 A plot manipulator is a function that takes a plot in input, does something to the plot
492 and returns the modified plot in output.
493 The function, once plugged, gets automatically called everytime self.plots is updated
495 For example, in force spectroscopy force curves, raw data are automatically corrected
496 for deflection. Other data can be, say, filtered by default.
498 To create and activate a plot manipulator you have to:
499 * Write a function (like this) which name starts with "plotmanip_" (just like commands
501 * The function must support four arguments:
504 current : (usually not used, deprecated)
505 customvalue=None : a variable containing custom value(s) you need for your plot manipulators.
506 * The function must return a plot object.
507 * Add an entry in hooke.conf: if your function is "plotmanip_something" you will have
508 to add <something/> in the plotmanips section: example
517 Important: Plot manipulators are *in pipe*: each plot manipulator output becomes the input of the next one.
518 The order in hooke.conf *is the order* in which plot manipulators are connected, so in the example above
520 self.current.curve.default_plots() --> detriggerize --> correct --> median --> something --> self.plots
524 Here we see what is in a configuration variable to enable/disable the plot manipulator as user will using
525 the Hooke "set" command.
526 Typing "set tutorial_absvalue 0" disables the plot manipulator; typing "set tutorial_absvalue 1" will enable it.
528 if not self.config['tutorial_absvalue']:
531 #We do something to the plot, for demonstration's sake
532 #If we needed variables, we would have used customvalue.
533 plot.vectors[0][1]=[abs(i) for i in plot.vectors[0][1]]
534 plot.vectors[1][1]=[abs(i) for i in plot.vectors[1][1]]
536 #Return the plot object.
541 #how to add lines to an existing plot!!