6 General library of internal objects and utilities for Hooke.
8 Copyright (C) 2006 Massimo Sandal (University of Bologna, Italy).
9 With algorithms contributed by Francesco Musiani (University of Bologna, Italy)
11 This program is released under the GNU General Public License version 2.
16 import libhookecurve as lhc
23 import xml.dom.minidom
28 HOOKE_VERSION=['0.8.3_devel', 'Seinei', '2008-04-16']
33 This module allows for import/export of an XML playlist into/out of a list of HookeCurve objects
38 self.playlist=None #the DOM object representing the playlist data structure
39 self.playpath=None #the path of the playlist XML file
41 self.hidden_attributes=['curve'] #This list contains hidden attributes that we don't want to go into the playlist.
43 def export(self, list_of_hooke_curves, generics):
45 Creates an initial playlist from a list of files.
46 A playlist is an XML document with the following syntaxis:
48 <element path="/my/file/path/"/ attribute="attribute">
53 #create the output playlist, a simple XML document
54 impl=xml.dom.minidom.getDOMImplementation()
55 #create the document DOM object and the root element
56 newdoc=impl.createDocument(None, "playlist",None)
57 top_element=newdoc.documentElement
59 #save generics variables
60 playlist_generics=newdoc.createElement("generics")
61 top_element.appendChild(playlist_generics)
62 for key in generics.keys():
63 newdoc.createAttribute(key)
64 playlist_generics.setAttribute(key,str(generics[key]))
66 #save curves and their attributes
67 for item in list_of_hooke_curves:
68 #playlist_element=newdoc.createElement("curve")
69 playlist_element=newdoc.createElement("element")
70 top_element.appendChild(playlist_element)
71 for key in item.__dict__:
72 if not (key in self.hidden_attributes):
73 newdoc.createAttribute(key)
74 playlist_element.setAttribute(key,str(item.__dict__[key]))
78 def load(self,filename):
83 self.playpath=filename
85 #the following 3 lines are needed to strip newlines. otherwise, since newlines
86 #are XML elements too (why?), the parser would read them (and re-save them, multiplying
89 the_file=myplay.read()
90 the_file_lines=the_file.split('\n')
91 the_file=''.join(the_file_lines)
93 self.playlist=xml.dom.minidom.parseString(the_file)
95 #inner parsing functions
96 def handlePlaylist(playlist):
97 list_of_files=playlist.getElementsByTagName("element")
98 generics=playlist.getElementsByTagName("generics")
99 return handleFiles(list_of_files), handleGenerics(generics)
101 def handleGenerics(generics):
106 for attribute in generics[0].attributes.keys():
107 generics_dict[attribute]=generics[0].getAttribute(attribute)
110 def handleFiles(list_of_files):
112 for myfile in list_of_files:
113 #rebuild a data structure from the xml attributes
114 the_curve=lhc.HookeCurve(myfile.getAttribute('path'))
115 for attribute in myfile.attributes.keys(): #extract attributes for the single curve
116 the_curve.__dict__[attribute]=myfile.getAttribute(attribute)
117 new_playlist.append(the_curve)
119 return new_playlist #this is the true thing returned at the end of this function...(FIXME: clarity)
121 return handlePlaylist(self.playlist)
124 def save(self,output_filename):
126 saves the playlist in a XML file.
129 outfile=file(output_filename,'w')
131 print 'libhooke.py : Cannot save playlist. Wrong path or filename'
134 self.playlist.writexml(outfile,indent='\n')
140 Handling of Hooke configuration file
142 Mostly based on the simple-yet-useful examples of the Python Library Reference
143 about xml.dom.minidom
145 FIXME: starting to look a mess, should require refactoring
150 self.config['plugins']=[]
151 self.config['drivers']=[]
152 self.config['plotmanips']=[]
154 def load_config(self, filename):
155 myconfig=file(filename)
157 #the following 3 lines are needed to strip newlines. otherwise, since newlines
158 #are XML elements too, the parser would read them (and re-save them, multiplying
160 #yes, I'm an XML n00b
161 the_file=myconfig.read()
162 the_file_lines=the_file.split('\n')
163 the_file=''.join(the_file_lines)
165 self.config_tree=xml.dom.minidom.parseString(the_file)
167 def getText(nodelist):
168 #take the text from a nodelist
169 #from Python Library Reference 13.7.2
171 for node in nodelist:
172 if node.nodeType == node.TEXT_NODE:
176 def handleConfig(config):
177 display_elements=config.getElementsByTagName("display")
178 plugins_elements=config.getElementsByTagName("plugins")
179 drivers_elements=config.getElementsByTagName("drivers")
180 workdir_elements=config.getElementsByTagName("workdir")
181 defaultlist_elements=config.getElementsByTagName("defaultlist")
182 plotmanip_elements=config.getElementsByTagName("plotmanips")
183 handleDisplay(display_elements)
184 handlePlugins(plugins_elements)
185 handleDrivers(drivers_elements)
186 handleWorkdir(workdir_elements)
187 handleDefaultlist(defaultlist_elements)
188 handlePlotmanip(plotmanip_elements)
190 def handleDisplay(display_elements):
191 for element in display_elements:
192 for attribute in element.attributes.keys():
193 self.config[attribute]=element.getAttribute(attribute)
195 def handlePlugins(plugins):
196 for plugin in plugins[0].childNodes:
198 self.config['plugins'].append(str(plugin.tagName))
199 except: #if we allow fancy formatting of xml, there is a text node, so tagName fails for it...
201 #FIXME: code duplication
202 def handleDrivers(drivers):
203 for driver in drivers[0].childNodes:
205 self.config['drivers'].append(str(driver.tagName))
206 except: #if we allow fancy formatting of xml, there is a text node, so tagName fails for it...
209 def handlePlotmanip(plotmanips):
210 for plotmanip in plotmanips[0].childNodes:
212 self.config['plotmanips'].append(str(plotmanip.tagName))
213 except: #if we allow fancy formatting of xml, there is a text node, so tagName fails for it...
216 def handleWorkdir(workdir):
218 default working directory
220 wdir=getText(workdir[0].childNodes)
221 self.config['workdir']=wdir.strip()
223 def handleDefaultlist(defaultlist):
227 dflist=getText(defaultlist[0].childNodes)
228 self.config['defaultlist']=dflist.strip()
230 handleConfig(self.config_tree)
231 #making items in the dictionary more machine-readable
232 for item in self.config.keys():
234 self.config[item]=float(self.config[item])
235 except TypeError: #we are dealing with a list, probably. keep it this way.
237 self.config[item]=eval(self.config[item])
238 except: #not a list, not a tuple, probably a string?
240 except ValueError: #if we can't get it to a number, it must be None or a string
241 if string.lower(self.config[item])=='none':
242 self.config[item]=None
249 def save_config(self, config_filename):
250 print 'Not Implemented.'
256 this class defines what a clicked point on the curve plot is
260 self.is_marker=None #boolean ; decides if it is a marker
261 self.is_line_edge=None #boolean ; decides if it is the edge of a line (unused)
262 self.absolute_coords=(None,None) #(float,float) ; the absolute coordinates of the clicked point on the graph
263 self.graph_coords=(None,None) #(float,float) ; the coordinates of the plot that are nearest in X to the clicked point
264 self.index=None #integer ; the index of the clicked point with respect to the vector selected
265 self.dest=None #0 or 1 ; 0=top plot 1=bottom plot
268 def find_graph_coords_old(self, xvector, yvector):
270 Given a clicked point on the plot, finds the nearest point in the dataset (in X) that
271 corresponds to the clicked point.
272 OLD & DEPRECATED - to be removed
275 #FIXME: a general algorithm using min() is needed!
276 print '---DEPRECATED FIND_GRAPH_COORDS_OLD---'
278 best_dist=10**9 #should be more than enough given the scale
280 for index in scipy.arange(1,len(xvector),1):
281 dist=((self.absolute_coords[0]-xvector[index])**2)+(100*((self.absolute_coords[1]-yvector[index])))**2
282 #TODO, generalize? y coordinate is multiplied by 100 due to scale differences in the plot
287 self.index=best_index
288 self.graph_coords=(xvector[best_index],yvector[best_index])
291 def find_graph_coords(self,xvector,yvector):
293 Given a clicked point on the plot, finds the nearest point in the dataset that
294 corresponds to the clicked point.
297 for index in scipy.arange(1,len(xvector),1):
298 dists.append(((self.absolute_coords[0]-xvector[index])**2)+((self.absolute_coords[1]-yvector[index])**2))
300 self.index=dists.index(min(dists))
301 self.graph_coords=(xvector[self.index],yvector[self.index])
302 #-----------------------------------------
303 #CSV-HELPING FUNCTIONS
305 def transposed2(lists, defval=0):
307 transposes a list of lists, i.e. from [[a,b,c],[x,y,z]] to [[a,x],[b,y],[c,z]] without losing
309 (by Zoran Isailovski on the Python Cookbook online)
311 if not lists: return []
312 return map(lambda *row: [elem or defval for elem in row], *lists)
314 def csv_write_dictionary(f, data, sorting='COLUMNS'):
316 Writes a CSV file from a dictionary, with keys as first column or row
317 Keys are in "random" order.
319 Keys should be strings
320 Values should be lists or other iterables
324 t_values=transposed2(values)
327 if sorting=='COLUMNS':
328 writer.writerow(keys)
329 for item in t_values:
330 writer.writerow(item)
333 print 'Not implemented!' #FIXME: implement it.
336 #-----------------------------------------
340 debug stuff from latest rewrite of hooke_playlist.py
341 should be removed sooner or later (or substituted with new debug code!)
344 print confo.load_config('hooke.conf')
346 if __name__ == '__main__':