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.
128 outfile=file(output_filename,'w')
129 self.playlist.writexml(outfile,indent='\n')
135 Handling of Hooke configuration file
137 Mostly based on the simple-yet-useful examples of the Python Library Reference
138 about xml.dom.minidom
140 FIXME: starting to look a mess, should require refactoring
145 self.config['plugins']=[]
146 self.config['drivers']=[]
147 self.config['plotmanips']=[]
149 def load_config(self, filename):
150 myconfig=file(filename)
152 #the following 3 lines are needed to strip newlines. otherwise, since newlines
153 #are XML elements too, the parser would read them (and re-save them, multiplying
155 #yes, I'm an XML n00b
156 the_file=myconfig.read()
157 the_file_lines=the_file.split('\n')
158 the_file=''.join(the_file_lines)
160 self.config_tree=xml.dom.minidom.parseString(the_file)
162 def getText(nodelist):
163 #take the text from a nodelist
164 #from Python Library Reference 13.7.2
166 for node in nodelist:
167 if node.nodeType == node.TEXT_NODE:
171 def handleConfig(config):
172 display_elements=config.getElementsByTagName("display")
173 plugins_elements=config.getElementsByTagName("plugins")
174 drivers_elements=config.getElementsByTagName("drivers")
175 workdir_elements=config.getElementsByTagName("workdir")
176 defaultlist_elements=config.getElementsByTagName("defaultlist")
177 plotmanip_elements=config.getElementsByTagName("plotmanips")
178 handleDisplay(display_elements)
179 handlePlugins(plugins_elements)
180 handleDrivers(drivers_elements)
181 handleWorkdir(workdir_elements)
182 handleDefaultlist(defaultlist_elements)
183 handlePlotmanip(plotmanip_elements)
185 def handleDisplay(display_elements):
186 for element in display_elements:
187 for attribute in element.attributes.keys():
188 self.config[attribute]=element.getAttribute(attribute)
190 def handlePlugins(plugins):
191 for plugin in plugins[0].childNodes:
193 self.config['plugins'].append(str(plugin.tagName))
194 except: #if we allow fancy formatting of xml, there is a text node, so tagName fails for it...
196 #FIXME: code duplication
197 def handleDrivers(drivers):
198 for driver in drivers[0].childNodes:
200 self.config['drivers'].append(str(driver.tagName))
201 except: #if we allow fancy formatting of xml, there is a text node, so tagName fails for it...
204 def handlePlotmanip(plotmanips):
205 for plotmanip in plotmanips[0].childNodes:
207 self.config['plotmanips'].append(str(plotmanip.tagName))
208 except: #if we allow fancy formatting of xml, there is a text node, so tagName fails for it...
211 def handleWorkdir(workdir):
213 default working directory
215 wdir=getText(workdir[0].childNodes)
216 self.config['workdir']=wdir.strip()
218 def handleDefaultlist(defaultlist):
222 dflist=getText(defaultlist[0].childNodes)
223 self.config['defaultlist']=dflist.strip()
225 handleConfig(self.config_tree)
226 #making items in the dictionary more machine-readable
227 for item in self.config.keys():
229 self.config[item]=float(self.config[item])
230 except TypeError: #we are dealing with a list, probably. keep it this way.
232 self.config[item]=eval(self.config[item])
233 except: #not a list, not a tuple, probably a string?
235 except ValueError: #if we can't get it to a number, it must be None or a string
236 if string.lower(self.config[item])=='none':
237 self.config[item]=None
244 def save_config(self, config_filename):
245 print 'Not Implemented.'
251 this class defines what a clicked point on the curve plot is
255 self.is_marker=None #boolean ; decides if it is a marker
256 self.is_line_edge=None #boolean ; decides if it is the edge of a line (unused)
257 self.absolute_coords=(None,None) #(float,float) ; the absolute coordinates of the clicked point on the graph
258 self.graph_coords=(None,None) #(float,float) ; the coordinates of the plot that are nearest in X to the clicked point
259 self.index=None #integer ; the index of the clicked point with respect to the vector selected
260 self.dest=None #0 or 1 ; 0=top plot 1=bottom plot
263 def find_graph_coords(self, xvector, yvector):
265 Given a clicked point on the plot, finds the nearest point in the dataset (in X) that
266 corresponds to the clicked point.
270 best_dist=10**9 #should be more than enough given the scale
272 for index in scipy.arange(1,len(xvector),1):
273 dist=((self.absolute_coords[0]-xvector[index])**2)+(100*((self.absolute_coords[1]-yvector[index])))**2
274 #TODO, generalize? y coordinate is multiplied by 100 due to scale differences in the plot
279 self.index=best_index
280 self.graph_coords=(xvector[best_index],yvector[best_index])
283 #-----------------------------------------
284 #CSV-HELPING FUNCTIONS
286 def transposed2(lists, defval=0):
288 transposes a list of lists, i.e. from [[a,b,c],[x,y,z]] to [[a,x],[b,y],[c,z]] without losing
290 (by Zoran Isailovski on the Python Cookbook online)
292 if not lists: return []
293 return map(lambda *row: [elem or defval for elem in row], *lists)
295 def csv_write_dictionary(f, data, sorting='COLUMNS'):
297 Writes a CSV file from a dictionary, with keys as first column or row
298 Keys are in "random" order.
300 Keys should be strings
301 Values should be lists or other iterables
305 t_values=transposed2(values)
308 if sorting=='COLUMNS':
309 writer.writerow(keys)
310 for item in t_values:
311 writer.writerow(item)
314 print 'Not implemented!' #FIXME: implement it.
317 #-----------------------------------------
321 debug stuff from latest rewrite of hooke_playlist.py
322 should be removed sooner or later (or substituted with new debug code!)
325 print confo.load_config('hooke.conf')
327 if __name__ == '__main__':