5 General library of internal objects and utilities for Hooke.
7 Copyright (C) 2006 Massimo Sandal (University of Bologna, Italy).
8 With algorithms contributed by Francesco Musiani (University of Bologna, Italy)
10 This program is released under the GNU General Public License version 2.
13 import libhookecurve as lhc
20 import xml.dom.minidom
25 HOOKE_VERSION=['0.8.3_devel', 'Seinei', '2008-04-16']
30 This module allows for import/export of an XML playlist into/out of a list of HookeCurve objects
35 self.playlist=None #the DOM object representing the playlist data structure
36 self.playpath=None #the path of the playlist XML file
38 self.hidden_attributes=['curve'] #This list contains hidden attributes that we don't want to go into the playlist.
40 def export(self, list_of_hooke_curves, generics):
42 Creates an initial playlist from a list of files.
43 A playlist is an XML document with the following syntaxis:
45 <element path="/my/file/path/"/ attribute="attribute">
50 #create the output playlist, a simple XML document
51 impl=xml.dom.minidom.getDOMImplementation()
52 #create the document DOM object and the root element
53 newdoc=impl.createDocument(None, "playlist",None)
54 top_element=newdoc.documentElement
56 #save generics variables
57 playlist_generics=newdoc.createElement("generics")
58 top_element.appendChild(playlist_generics)
59 for key in generics.keys():
60 newdoc.createAttribute(key)
61 playlist_generics.setAttribute(key,str(generics[key]))
63 #save curves and their attributes
64 for item in list_of_hooke_curves:
65 #playlist_element=newdoc.createElement("curve")
66 playlist_element=newdoc.createElement("element")
67 top_element.appendChild(playlist_element)
68 for key in item.__dict__:
69 if not (key in self.hidden_attributes):
70 newdoc.createAttribute(key)
71 playlist_element.setAttribute(key,str(item.__dict__[key]))
75 def load(self,filename):
80 self.playpath=filename
82 #the following 3 lines are needed to strip newlines. otherwise, since newlines
83 #are XML elements too (why?), the parser would read them (and re-save them, multiplying
86 the_file=myplay.read()
87 the_file_lines=the_file.split('\n')
88 the_file=''.join(the_file_lines)
90 self.playlist=xml.dom.minidom.parseString(the_file)
92 #inner parsing functions
93 def handlePlaylist(playlist):
94 list_of_files=playlist.getElementsByTagName("element")
95 generics=playlist.getElementsByTagName("generics")
96 return handleFiles(list_of_files), handleGenerics(generics)
98 def handleGenerics(generics):
103 for attribute in generics[0].attributes.keys():
104 generics_dict[attribute]=generics[0].getAttribute(attribute)
107 def handleFiles(list_of_files):
109 for myfile in list_of_files:
110 #rebuild a data structure from the xml attributes
111 the_curve=lhc.HookeCurve(myfile.getAttribute('path'))
112 for attribute in myfile.attributes.keys(): #extract attributes for the single curve
113 the_curve.__dict__[attribute]=myfile.getAttribute(attribute)
114 new_playlist.append(the_curve)
116 return new_playlist #this is the true thing returned at the end of this function...(FIXME: clarity)
118 return handlePlaylist(self.playlist)
121 def save(self,output_filename):
123 saves the playlist in a XML file.
126 outfile=file(output_filename,'w')
128 print 'libhooke.py : Cannot save playlist. Wrong path or filename'
131 self.playlist.writexml(outfile,indent='\n')
137 Handling of Hooke configuration file
139 Mostly based on the simple-yet-useful examples of the Python Library Reference
140 about xml.dom.minidom
142 FIXME: starting to look a mess, should require refactoring
147 self.config['plugins']=[]
148 self.config['drivers']=[]
149 self.config['plotmanips']=[]
151 def load_config(self, filename):
152 myconfig=file(filename)
154 #the following 3 lines are needed to strip newlines. otherwise, since newlines
155 #are XML elements too, the parser would read them (and re-save them, multiplying
157 #yes, I'm an XML n00b
158 the_file=myconfig.read()
159 the_file_lines=the_file.split('\n')
160 the_file=''.join(the_file_lines)
162 self.config_tree=xml.dom.minidom.parseString(the_file)
164 def getText(nodelist):
165 #take the text from a nodelist
166 #from Python Library Reference 13.7.2
168 for node in nodelist:
169 if node.nodeType == node.TEXT_NODE:
173 def handleConfig(config):
174 display_elements=config.getElementsByTagName("display")
175 plugins_elements=config.getElementsByTagName("plugins")
176 drivers_elements=config.getElementsByTagName("drivers")
177 workdir_elements=config.getElementsByTagName("workdir")
178 defaultlist_elements=config.getElementsByTagName("defaultlist")
179 plotmanip_elements=config.getElementsByTagName("plotmanips")
180 handleDisplay(display_elements)
181 handlePlugins(plugins_elements)
182 handleDrivers(drivers_elements)
183 handleWorkdir(workdir_elements)
184 handleDefaultlist(defaultlist_elements)
185 handlePlotmanip(plotmanip_elements)
187 def handleDisplay(display_elements):
188 for element in display_elements:
189 for attribute in element.attributes.keys():
190 self.config[attribute]=element.getAttribute(attribute)
192 def handlePlugins(plugins):
193 for plugin in plugins[0].childNodes:
195 self.config['plugins'].append(str(plugin.tagName))
196 except: #if we allow fancy formatting of xml, there is a text node, so tagName fails for it...
198 #FIXME: code duplication
199 def handleDrivers(drivers):
200 for driver in drivers[0].childNodes:
202 self.config['drivers'].append(str(driver.tagName))
203 except: #if we allow fancy formatting of xml, there is a text node, so tagName fails for it...
206 def handlePlotmanip(plotmanips):
207 for plotmanip in plotmanips[0].childNodes:
209 self.config['plotmanips'].append(str(plotmanip.tagName))
210 except: #if we allow fancy formatting of xml, there is a text node, so tagName fails for it...
213 def handleWorkdir(workdir):
215 default working directory
217 wdir=getText(workdir[0].childNodes)
218 self.config['workdir']=wdir.strip()
220 def handleDefaultlist(defaultlist):
224 dflist=getText(defaultlist[0].childNodes)
225 self.config['defaultlist']=dflist.strip()
227 handleConfig(self.config_tree)
228 #making items in the dictionary more machine-readable
229 for item in self.config.keys():
231 self.config[item]=float(self.config[item])
232 except TypeError: #we are dealing with a list, probably. keep it this way.
234 self.config[item]=eval(self.config[item])
235 except: #not a list, not a tuple, probably a string?
237 except ValueError: #if we can't get it to a number, it must be None or a string
238 if string.lower(self.config[item])=='none':
239 self.config[item]=None
246 def save_config(self, config_filename):
247 print 'Not Implemented.'
253 this class defines what a clicked point on the curve plot is
257 self.is_marker=None #boolean ; decides if it is a marker
258 self.is_line_edge=None #boolean ; decides if it is the edge of a line (unused)
259 self.absolute_coords=(None,None) #(float,float) ; the absolute coordinates of the clicked point on the graph
260 self.graph_coords=(None,None) #(float,float) ; the coordinates of the plot that are nearest in X to the clicked point
261 self.index=None #integer ; the index of the clicked point with respect to the vector selected
262 self.dest=None #0 or 1 ; 0=top plot 1=bottom plot
265 def find_graph_coords_old(self, xvector, yvector):
267 Given a clicked point on the plot, finds the nearest point in the dataset (in X) that
268 corresponds to the clicked point.
269 OLD & DEPRECATED - to be removed
272 #FIXME: a general algorithm using min() is needed!
273 print '---DEPRECATED FIND_GRAPH_COORDS_OLD---'
275 best_dist=10**9 #should be more than enough given the scale
277 for index in scipy.arange(1,len(xvector),1):
278 dist=((self.absolute_coords[0]-xvector[index])**2)+(100*((self.absolute_coords[1]-yvector[index])))**2
279 #TODO, generalize? y coordinate is multiplied by 100 due to scale differences in the plot
284 self.index=best_index
285 self.graph_coords=(xvector[best_index],yvector[best_index])
288 def find_graph_coords(self,xvector,yvector):
290 Given a clicked point on the plot, finds the nearest point in the dataset that
291 corresponds to the clicked point.
294 for index in scipy.arange(1,len(xvector),1):
295 dists.append(((self.absolute_coords[0]-xvector[index])**2)+((self.absolute_coords[1]-yvector[index])**2))
297 self.index=dists.index(min(dists))
298 self.graph_coords=(xvector[self.index],yvector[self.index])
299 #-----------------------------------------
300 #CSV-HELPING FUNCTIONS
302 def transposed2(lists, defval=0):
304 transposes a list of lists, i.e. from [[a,b,c],[x,y,z]] to [[a,x],[b,y],[c,z]] without losing
306 (by Zoran Isailovski on the Python Cookbook online)
308 if not lists: return []
309 return map(lambda *row: [elem or defval for elem in row], *lists)
311 def csv_write_dictionary(f, data, sorting='COLUMNS'):
313 Writes a CSV file from a dictionary, with keys as first column or row
314 Keys are in "random" order.
316 Keys should be strings
317 Values should be lists or other iterables
321 t_values=transposed2(values)
324 if sorting=='COLUMNS':
325 writer.writerow(keys)
326 for item in t_values:
327 writer.writerow(item)
330 print 'Not implemented!' #FIXME: implement it.
333 #-----------------------------------------
337 debug stuff from latest rewrite of hooke_playlist.py
338 should be removed sooner or later (or substituted with new debug code!)
341 print confo.load_config('hooke.conf')
343 if __name__ == '__main__':