3 """This plugin contains example commands to teach how to write an
4 Hooke plugin, including description of main Hooke internals.
9 from .. import curve as lhc
12 SYNTAX OF DATA TYPE DECLARATION:
14 [ type ] = list containing objects of type
15 {typekey:typearg} = dictionary with keys of type typekey and args of type typearg
16 ( type ) = tuple containing objects of type
20 class tutorialCommands(object):
22 Here we define the class containing all the Hooke commands we want to define
25 Notice the class name!!
26 The syntax is filenameCommands. That is, if your plugin is pluggy.py, your class
27 name is pluggyCommands.
29 Otherwise, the class will be ignored by Hooke.
34 This is the plugin initialization.
35 When Hooke starts and the plugin is loaded, this function is executed.
36 If there is something you need to do when Hooke starts, code it in this function.
38 print 'I am the Tutorial plugin initialization!'
40 #Here we initialize a local configuration variable; see plotmanip_absvalue() for explanation.
41 self.config['tutorial_absvalue']=0
44 def do_nothing(self,args):
46 This is a boring but working example of an actual Hooke command.
47 A Hooke command is a function of the xxxxCommands class, which is ALWAYS defined
50 def do_nameofcommand(self,args)
52 *do_ is needed to make Hooke understand this function is a command
53 *nameofcommand is how the command will be called in the Hooke command line.
55 *args is ALWAYS needed (otherwise Hooke will crash executing the command). We will see
58 Note that if you now start Hooke with this plugin activated and you type in the Hooke command
59 line "help nothing" you will see this very text as output. So the help of a command is a
60 string comment below the function definition, like this one.
62 Commands usually return None.
64 print 'I am a Hooke command. I do nothing.'
66 def do_printargs(self,args):
68 This command prints the args you give to it.
69 args is always a string, that contains everything you write after the command.
70 So if you issue "mycommand blah blah 12345" args is "blah blah 12345".
72 Again, args is needed in the definition even if your command does not use it.
74 print 'You gave me those args: '+args
76 def help_tutorial(self):
78 This is a help function.
79 If you want a help function for something that is not a command, you can write a help
80 function like this. Calling "help tutorial" will execute this function.
82 print 'You called help_tutorial()'
84 def do_environment(self,args):
86 This plugin contains a panoramic of the Hooke command line environment variables,
87 and prints their current value.
91 TYPE: [ curve.HookeCurve ], len=variable
92 contains the actual playlist of Hooke curve objects.
93 Each HookeCurve object represents a reference to a data file.
94 We will see later in detail how do they work.
96 print 'current_list length:',len(self.current_list)
97 print 'current_list 0th:',self.current_list[0]
101 contains the index of
102 the current curve in the playlist
104 print 'pointer: ',self.pointer
107 TYPE: curve.HookeCurve
108 contains the current curve displayed.
109 We will see later how it works.
111 print 'current:',self.current
114 TYPE: [ curve.PlotObject ], len=1,2
115 contains the current default plots.
116 Each PlotObject contains all info needed to display
117 the plot: apart from the data vectors, the title, destination
119 Usually self.plots[0] is the default topmost plot, self.plots[1] is the
120 accessory bottom plot.
122 print 'plots:',self.plots
125 TYPE: { string:anything }
126 contains the current Hooke configuration variables, in form of a dictionary.
128 print 'config:',self.config
132 Contains the ordered plot manipulation functions.
133 These functions are called to modify the default plot by default before it is plotted.
134 self.plots contains the plot passed through the plot manipulators.
135 We will see it better later.
136 *YOU SHOULD NEVER MODIFY THAT*
138 print 'plotmanip: ',self.plotmanip
142 Contains the plot reading drivers.
143 *YOU SHOULD NEVER MODIFY THAT*
145 print 'drivers: ',self.drivers
149 Contains the wx Frame of the GUI.
150 ***NEVER, EVER TOUCH THAT.***
152 print 'frame: ',self.frame
154 '''self.list_of_events
155 TYPE: { string:wx.Event }
156 Contains the wx.Events to communicate with the GUI.
157 Usually not necessary to use it, unless you want
158 to create a GUI plugin.
160 print 'list of events:',self.list_of_events
162 '''self.events_from_gui
164 Contains the Queue where data from the GUI is put.
165 Usually not necessary to use it, unless you want
166 to create a GUI plugin.
168 print 'events from gui:',self.events_from_gui
170 '''self.playlist_saved
171 TYPE: Int (0/1) ; Boolean
172 Flag that tells if the playlist has been saved or not.
174 print 'playlist saved:',self.playlist_saved
176 '''self.playlist_name
178 Name of current playlist
180 print 'playlist name:',self.playlist_name
183 TYPE: Int (0/1) ; Boolean
184 Flag that tells if the playlist has been saved or not.
186 print 'notes saved:',self.notes_saved
189 def do_myfirstplot(self,args):
191 In this function, we see how to create a PlotObject and send it to the screen.
192 ***Read the code of PlotObject in curve.py before!***.
195 #We generate some interesting data to plot for this example.
196 xdata1=np.arange(-5,5,0.1)
197 xdata2=np.arange(-5,5,0.1)
198 ydata1=[item**2 for item in xdata1]
199 ydata2=[item**3 for item in xdata2]
202 #The PlotObject class lives in the curve library.
203 myplot=lhc.PlotObject()
205 The *data* of the plot live in the .vectors list.
207 plot.vectors is a multidimensional array:
210 plot.vectors[2]=sett3
213 2 curves in a x,y plot are:
214 [[[x1],[y1]],[[x2],[y2]]]
217 [[[1,2,3,4],[10,20,30,40]],[[3,6,9,12],[30,60,90,120]]]
218 x1 = self.vectors[0][0]
219 y1 = self.vectors[0][1]
220 x2 = self.vectors[1][0]
221 y2 = self.vectors[1][1]
223 #Pour 0-th dataset into myplot:
224 myplot.add_set(xdata1,ydata1)
226 #Pour 1-st dataset into myplot:
227 myplot.add_set(xdata2,ydata2)
229 #Add units to x and y axes
230 #units=[string, string]
231 myplot.units=['x axis','y axis']
233 #Where do we want the plot? 0=top, 1=bottom
236 '''Send it to the GUI.
237 Note that you *have* to encapsulate it into a list, so you
238 have to send [myplot], not simply myplot.
240 You can also send more two plots at once
241 self.send_plot([plot1,plot2])
243 self._send_plot([myplot])
246 def do_myfirstscatter(self,args):
248 How to draw a scatter plot.
250 #We generate some interesting data to plot for this example.
251 xdata1=np.arange(-5,5,1)
252 xdata2=np.arange(-5,5,1)
253 ydata1=[item**2 for item in xdata1]
254 ydata2=[item**3 for item in xdata2]
256 myplot=lhc.PlotObject()
257 myplot.add_set(xdata1,ydata1)
258 myplot.add_set(xdata2,ydata2)
261 #Add units to x and y axes
262 myplot.units=['x axis','y axis']
264 #Where do we want the plot? 0=top, 1=bottom
267 '''None=standard line plot
268 'scatter'=scatter plot
269 By default, the styles attribute is an empty list. If you
270 want to define a scatter plot, you must define all other
271 plots as None or 'scatter', depending on what you want.
273 Here we define the second set to be plotted as scatter,
274 and the first to be plotted as line.
276 Here we define also the colors to be the default Matplotlib colors
278 myplot.styles=[None,'scatter']
279 myplot.colors=[None,None]
280 self._send_plot([myplot])
283 def do_clickaround(self,args):
285 Here we click two points on the curve and take some parameters from the points
290 points = self._measure_N_points(N=Int, whatset=Int)
291 *N = number of points to measure(1...n)
292 *whatset = data set to measure (0,1...n)
293 *points = a list of ClickedPoint objects, one for each point requested
295 points=self._measure_N_points(N=2,whatset=1)
296 print 'You clicked the following points.'
299 These are the absolute coordinates of the
303 print 'Absolute coordinates:'
304 print points[0].absolute_coords
305 print points[1].absolute_coords
309 These are the coordinates of the points
310 clicked, remapped on the graph.
311 Hooke looks at the graph point which X
312 coordinate is next to the X coordinate of
313 the point measured, and uses that point
314 as the actual clicked point.
317 print 'Coordinates on the graph:'
318 print points[0].graph_coords
319 print points[1].graph_coords
323 These are the indexes of the clicked points
324 on the dataset vector.
326 print 'Index of points on the graph:'
327 print points[0].index
328 print points[1].index
331 def help_thedifferentplots(self):
333 The *three* different default plots you should be familiar with
336 Each plot contains of course the respective data in their
337 vectors attribute, so here you learn also which data access for
341 1. THE RAW, CURRENT PLOTS
345 Contains the current curve.HookeCurve container object.
346 A HookeCurve object defines only two default attributes:
348 * self.current.path = string
349 The path of the current displayed curve
351 * self.current.curve = curve.Driver
352 The curve object. This is not only generated by the driver,
353 this IS a driver instance in itself.
354 This means that in self.current.curve you can access the
355 specific driver APIs, if you know them.
357 And defines only one method:
358 * self.current.identify()
359 Fills in the self.current.curve object.
360 See in the cycling tutorial.
363 The REAL curve data actually lives in:
365 * self.current.curve.default_plots() = [ libhooke.PlotObject ]
366 Contains the raw PlotObject-s, as "spitted out" by the driver, without any
368 This is as close to the raw data as Hooke gets.
370 One or two plots can be spit out; they are always enclosed in a list.
373 Methods of self.current.curve are:
376 * self.current.curve.is_me()
377 (Used by identify() only.)
379 * self.current.curve.close_all()
380 Closes all driver open files; see the cycling tutorial.
384 2. THE PROCESSED, DEFAULT PLOT
386 The plot that is spitted out by the driver is *not* the usual default plot
387 that is displayed by calling "plot" at the Hooke prompt.
389 This is because the raw, driver-generated plot is usually *processed* by so called
390 *plot processing* functions. We will see in the tutorial how to define
393 For example, in force spectroscopy force curves, raw data are automatically corrected
394 for deflection. Other data can be, say, filtered by default.
396 The default plots are accessible in
397 self.plots = [ libhooke.PlotObject ]
399 self.plots[0] is usually the topmost plot
400 self.plots[1] is usually the bottom plot (if present)
404 3. THE PLOT DISPLAYED RIGHT NOW.
406 Sometimes the plots you are displaying *right now* is different from the previous
407 two. You may have a fit trace, you may have issued some command that spits out
408 a custom plot and you want to rework that, whatever.
410 You can obtain in any moment the plot currently displayed by Hooke by issuing
412 PlotObject = self._get_displayed_plot(dest)
419 def do_cycling(self,args):
421 Here we cycle through our playlist and print some info on the curves we find.
422 Cycling through the playlist needs a bit of care to avoid memory leaks and dangling
425 Look at the source code for more information.
428 def things_when_cycling(item):
430 We encapsulate here everything has to open the actual curve file.
431 By doing it all here, we avoid to do acrobacies when deleting objects etc.
432 in the main loop: we do the dirty stuff here.
438 This method looks for the correct driver in self.drivers to use;
439 and puts the curve content in the .curve attribute.
440 Basically, until identify() is called, the HookeCurve object
441 is just an empty shell. When identify() is called (usually by
442 the Hooke plot routine), the HookeCurve object is "filled" with
446 item.identify(self.drivers)
449 After the identify(), item.curve contains the curve, and item.curve.default_plots() behaves exactly like
450 self.current.curve.default_plots() -but for the given item.
452 itplot=item.curve.default_plots()
454 print 'length of X1 vector:',len(itplot[0].vectors[0][0]) #just to show something
457 The following three lines are a magic spell you HAVE to do
458 before closing the function.
459 (Otherwise you will be plagued by unpredicatable, system-dependent bugs.)
461 item.curve.close_all() #Avoid open files dangling
462 del item.curve #Avoid memory leaks
463 del item #Just be paranoid. Don't ask.
469 for item in self.current_list:
470 print 'Looking at curve ',c,'of',len(self.current_list)
471 things_when_cycling(item)
478 def plotmanip_absvalue(self, plot, current, customvalue=None):
480 This function defines a PLOT MANIPULATOR.
481 A plot manipulator is a function that takes a plot in input, does something to the plot
482 and returns the modified plot in output.
483 The function, once plugged, gets automatically called everytime self.plots is updated
485 For example, in force spectroscopy force curves, raw data are automatically corrected
486 for deflection. Other data can be, say, filtered by default.
488 To create and activate a plot manipulator you have to:
489 * Write a function (like this) which name starts with "plotmanip_" (just like commands
491 * The function must support four arguments:
494 current : (usually not used, deprecated)
495 customvalue=None : a variable containing custom value(s) you need for your plot manipulators.
496 * The function must return a plot object.
497 * Add an entry in hooke.conf: if your function is "plotmanip_something" you will have
498 to add <something/> in the plotmanips section: example
507 Important: Plot manipulators are *in pipe*: each plot manipulator output becomes the input of the next one.
508 The order in hooke.conf *is the order* in which plot manipulators are connected, so in the example above
510 self.current.curve.default_plots() --> detriggerize --> correct --> median --> something --> self.plots
514 Here we see what is in a configuration variable to enable/disable the plot manipulator as user will using
515 the Hooke "set" command.
516 Typing "set tutorial_absvalue 0" disables the plot manipulator; typing "set tutorial_absvalue 1" will enable it.
518 if not self.config['tutorial_absvalue']:
521 #We do something to the plot, for demonstration's sake
522 #If we needed variables, we would have used customvalue.
523 plot.vectors[0][1]=[abs(i) for i in plot.vectors[0][1]]
524 plot.vectors[1][1]=[abs(i) for i in plot.vectors[1][1]]
526 #Return the plot object.
531 #how to add lines to an existing plot!!