Merged with trunk
[hooke.git] / hooke / libhooke.py
old mode 100755 (executable)
new mode 100644 (file)
similarity index 88%
rename from libhooke.py
rename to hooke/libhooke.py
index d035c71..eb4ce79
@@ -12,37 +12,33 @@ With algorithms contributed by Francesco Musiani (University of Bologna, Italy)
 This program is released under the GNU General Public License version 2.
 '''
 
 This program is released under the GNU General Public License version 2.
 '''
 
-
-
-import libhookecurve as lhc
-
 import scipy
 import scipy
-import scipy.signal
-import scipy.optimize
-import scipy.stats
 import numpy
 import xml.dom.minidom
 import os
 import numpy
 import xml.dom.minidom
 import os
+import os.path
 import string
 import csv
 from matplotlib.ticker import ScalarFormatter
 
 
 import string
 import csv
 from matplotlib.ticker import ScalarFormatter
 
 
+from . import libhookecurve as lhc
+
 HOOKE_VERSION=['0.8.3_devel', 'Seinei', '2008-04-16']
 HOOKE_VERSION=['0.8.3_devel', 'Seinei', '2008-04-16']
-WX_GOOD=['2.6','2.8'] 
-    
-class PlaylistXML:
+WX_GOOD=['2.6','2.8']
+
+class PlaylistXML(object):
         '''
         This module allows for import/export of an XML playlist into/out of a list of HookeCurve objects
         '''
         '''
         This module allows for import/export of an XML playlist into/out of a list of HookeCurve objects
         '''
-        
+
         def __init__(self):
         def __init__(self):
-            
+
             self.playlist=None #the DOM object representing the playlist data structure
             self.playpath=None #the path of the playlist XML file
             self.plaything=None
             self.hidden_attributes=['curve'] #This list contains hidden attributes that we don't want to go into the playlist.
             self.playlist=None #the DOM object representing the playlist data structure
             self.playpath=None #the path of the playlist XML file
             self.plaything=None
             self.hidden_attributes=['curve'] #This list contains hidden attributes that we don't want to go into the playlist.
-        
+
         def export(self, list_of_hooke_curves, generics):
             '''
             Creates an initial playlist from a list of files.
         def export(self, list_of_hooke_curves, generics):
             '''
             Creates an initial playlist from a list of files.
@@ -51,21 +47,21 @@ class PlaylistXML:
             <element path="/my/file/path/"/ attribute="attribute">
             <element path="...">
             </playlist>
             <element path="/my/file/path/"/ attribute="attribute">
             <element path="...">
             </playlist>
-            '''   
-        
+            '''
+
             #create the output playlist, a simple XML document
             impl=xml.dom.minidom.getDOMImplementation()
             #create the document DOM object and the root element
             newdoc=impl.createDocument(None, "playlist",None)
             top_element=newdoc.documentElement
             #create the output playlist, a simple XML document
             impl=xml.dom.minidom.getDOMImplementation()
             #create the document DOM object and the root element
             newdoc=impl.createDocument(None, "playlist",None)
             top_element=newdoc.documentElement
-            
+
             #save generics variables
             playlist_generics=newdoc.createElement("generics")
             top_element.appendChild(playlist_generics)
             for key in generics.keys():
                 newdoc.createAttribute(key)
                 playlist_generics.setAttribute(key,str(generics[key]))
             #save generics variables
             playlist_generics=newdoc.createElement("generics")
             top_element.appendChild(playlist_generics)
             for key in generics.keys():
                 newdoc.createAttribute(key)
                 playlist_generics.setAttribute(key,str(generics[key]))
-            
+
             #save curves and their attributes
             for item in list_of_hooke_curves:
                 #playlist_element=newdoc.createElement("curve")
             #save curves and their attributes
             for item in list_of_hooke_curves:
                 #playlist_element=newdoc.createElement("curve")
@@ -74,17 +70,17 @@ class PlaylistXML:
                 for key in item.__dict__:
                     if not (key in self.hidden_attributes):
                         newdoc.createAttribute(key)
                 for key in item.__dict__:
                     if not (key in self.hidden_attributes):
                         newdoc.createAttribute(key)
-                        playlist_element.setAttribute(key,str(item.__dict__[key]))    
-            
+                        playlist_element.setAttribute(key,str(item.__dict__[key]))
+
             self.playlist=newdoc
             self.playlist=newdoc
-            
+
         def load(self,filename):
             '''
             loads a playlist file
             '''
             myplay=file(filename)
             self.playpath=filename
         def load(self,filename):
             '''
             loads a playlist file
             '''
             myplay=file(filename)
             self.playpath=filename
-            
+
             #the following 3 lines are needed to strip newlines. otherwise, since newlines
             #are XML elements too (why?), the parser would read them (and re-save them, multiplying
             #newlines...)
             #the following 3 lines are needed to strip newlines. otherwise, since newlines
             #are XML elements too (why?), the parser would read them (and re-save them, multiplying
             #newlines...)
@@ -92,37 +88,42 @@ class PlaylistXML:
             the_file=myplay.read()
             the_file_lines=the_file.split('\n')
             the_file=''.join(the_file_lines)
             the_file=myplay.read()
             the_file_lines=the_file.split('\n')
             the_file=''.join(the_file_lines)
-                       
-            self.playlist=xml.dom.minidom.parseString(the_file)  
-                           
+
+            self.playlist=xml.dom.minidom.parseString(the_file)
+
             #inner parsing functions
             def handlePlaylist(playlist):
                 list_of_files=playlist.getElementsByTagName("element")
                 generics=playlist.getElementsByTagName("generics")
                 return handleFiles(list_of_files), handleGenerics(generics)
             #inner parsing functions
             def handlePlaylist(playlist):
                 list_of_files=playlist.getElementsByTagName("element")
                 generics=playlist.getElementsByTagName("generics")
                 return handleFiles(list_of_files), handleGenerics(generics)
-            
+
             def handleGenerics(generics):
                 generics_dict={}
                 if len(generics)==0:
                     return generics_dict
             def handleGenerics(generics):
                 generics_dict={}
                 if len(generics)==0:
                     return generics_dict
-                
+
                 for attribute in generics[0].attributes.keys():
                     generics_dict[attribute]=generics[0].getAttribute(attribute)
                 return generics_dict
                 for attribute in generics[0].attributes.keys():
                     generics_dict[attribute]=generics[0].getAttribute(attribute)
                 return generics_dict
-        
+
             def handleFiles(list_of_files):
                 new_playlist=[]
                 for myfile in list_of_files:
                     #rebuild a data structure from the xml attributes
             def handleFiles(list_of_files):
                 new_playlist=[]
                 for myfile in list_of_files:
                     #rebuild a data structure from the xml attributes
-                    the_curve=lhc.HookeCurve(myfile.getAttribute('path'))
-                    for attribute in myfile.attributes.keys(): #extract attributes for the single curve
+                    the_curve=lhc.HookeCurve(
+                        os.path.join(os.path.dirname(self.playpath),
+                                     myfile.getAttribute('path')))
+                    for attribute in myfile.attributes.keys():
+                        #extract attributes for the single curve
+                        if attribute == 'path':
+                            continue # we already added this attribute
                         the_curve.__dict__[attribute]=myfile.getAttribute(attribute)
                     new_playlist.append(the_curve)
                         the_curve.__dict__[attribute]=myfile.getAttribute(attribute)
                     new_playlist.append(the_curve)
-                
+
                 return new_playlist #this is the true thing returned at the end of this function...(FIXME: clarity)
                 return new_playlist #this is the true thing returned at the end of this function...(FIXME: clarity)
-                    
+
             return handlePlaylist(self.playlist)
             return handlePlaylist(self.playlist)
-            
+
 
         def save(self,output_filename):
             '''
 
         def save(self,output_filename):
             '''
@@ -133,30 +134,37 @@ class PlaylistXML:
             except IOError:
                 print 'libhooke.py : Cannot save playlist. Wrong path or filename'
                 return
             except IOError:
                 print 'libhooke.py : Cannot save playlist. Wrong path or filename'
                 return
-            
+
             self.playlist.writexml(outfile,indent='\n')
             outfile.close()
 
             self.playlist.writexml(outfile,indent='\n')
             outfile.close()
 
+def config_file_path(filename, config_dir=None):
+    if config_dir == None:
+        config_dir = os.path.abspath(
+            os.path.join(os.path.dirname(os.path.dirname(__file__)), 'conf'))
+    return os.path.join(config_dir, filename)
 
 
-class HookeConfig:
+class HookeConfig(object):
     '''
     Handling of Hooke configuration file
     '''
     Handling of Hooke configuration file
-    
+
     Mostly based on the simple-yet-useful examples of the Python Library Reference
     about xml.dom.minidom
     Mostly based on the simple-yet-useful examples of the Python Library Reference
     about xml.dom.minidom
-    
+
     FIXME: starting to look a mess, should require refactoring
     '''
     FIXME: starting to look a mess, should require refactoring
     '''
-    
-    def __init__(self):
+
+    def __init__(self, config_dir=None):
         self.config={}
         self.config={}
+        self.config['install']={}
         self.config['plugins']=[]
         self.config['drivers']=[]
         self.config['plotmanips']=[]
         self.config['plugins']=[]
         self.config['drivers']=[]
         self.config['plotmanips']=[]
-                
+        self.config_dir = config_dir
+
     def load_config(self, filename):
     def load_config(self, filename):
-        myconfig=file(filename)
-                    
+        myconfig=file(config_file_path(filename, config_dir=self.config_dir))
+
         #the following 3 lines are needed to strip newlines. otherwise, since newlines
         #are XML elements too, the parser would read them (and re-save them, multiplying
         #newlines...)
         #the following 3 lines are needed to strip newlines. otherwise, since newlines
         #are XML elements too, the parser would read them (and re-save them, multiplying
         #newlines...)
@@ -164,9 +172,9 @@ class HookeConfig:
         the_file=myconfig.read()
         the_file_lines=the_file.split('\n')
         the_file=''.join(the_file_lines)
         the_file=myconfig.read()
         the_file_lines=the_file.split('\n')
         the_file=''.join(the_file_lines)
-                       
-        self.config_tree=xml.dom.minidom.parseString(the_file)  
-        
+
+        self.config_tree=xml.dom.minidom.parseString(the_file)
+
         def getText(nodelist):
             #take the text from a nodelist
             #from Python Library Reference 13.7.2
         def getText(nodelist):
             #take the text from a nodelist
             #from Python Library Reference 13.7.2
@@ -175,26 +183,34 @@ class HookeConfig:
                 if node.nodeType == node.TEXT_NODE:
                     rc += node.data
             return rc
                 if node.nodeType == node.TEXT_NODE:
                     rc += node.data
             return rc
-        
+
         def handleConfig(config):
         def handleConfig(config):
+            install_elements=config.getElementsByTagName("install")
             display_elements=config.getElementsByTagName("display")
             plugins_elements=config.getElementsByTagName("plugins")
             drivers_elements=config.getElementsByTagName("drivers")
             display_elements=config.getElementsByTagName("display")
             plugins_elements=config.getElementsByTagName("plugins")
             drivers_elements=config.getElementsByTagName("drivers")
-            workdir_elements=config.getElementsByTagName("workdir")
             defaultlist_elements=config.getElementsByTagName("defaultlist")
             plotmanip_elements=config.getElementsByTagName("plotmanips")
             defaultlist_elements=config.getElementsByTagName("defaultlist")
             plotmanip_elements=config.getElementsByTagName("plotmanips")
+            handleInstall(install_elements)
             handleDisplay(display_elements)
             handlePlugins(plugins_elements)
             handleDrivers(drivers_elements)
             handleDisplay(display_elements)
             handlePlugins(plugins_elements)
             handleDrivers(drivers_elements)
-            handleWorkdir(workdir_elements)
             handleDefaultlist(defaultlist_elements)
             handlePlotmanip(plotmanip_elements)
             handleDefaultlist(defaultlist_elements)
             handlePlotmanip(plotmanip_elements)
-            
+
+        def handleInstall(install_elements):
+            for install in install_elements:
+                for node in install.childNodes:
+                    if node.nodeType == node.TEXT_NODE:
+                        continue
+                    path = os.path.abspath(getText(node.childNodes).strip())
+                    self.config['install'][str(node.tagName)] = path
+
         def handleDisplay(display_elements):
             for element in display_elements:
                 for attribute in element.attributes.keys():
                     self.config[attribute]=element.getAttribute(attribute)
         def handleDisplay(display_elements):
             for element in display_elements:
                 for attribute in element.attributes.keys():
                     self.config[attribute]=element.getAttribute(attribute)
-                    
+
         def handlePlugins(plugins):
             for plugin in plugins[0].childNodes:
                 try:
         def handlePlugins(plugins):
             for plugin in plugins[0].childNodes:
                 try:
@@ -208,28 +224,21 @@ class HookeConfig:
                     self.config['drivers'].append(str(driver.tagName))
                 except: #if we allow fancy formatting of xml, there is a text node, so tagName fails for it...
                     pass
                     self.config['drivers'].append(str(driver.tagName))
                 except: #if we allow fancy formatting of xml, there is a text node, so tagName fails for it...
                     pass
-        
+
         def handlePlotmanip(plotmanips):
             for plotmanip in plotmanips[0].childNodes:
                 try:
                     self.config['plotmanips'].append(str(plotmanip.tagName))
                 except: #if we allow fancy formatting of xml, there is a text node, so tagName fails for it...
                     pass
         def handlePlotmanip(plotmanips):
             for plotmanip in plotmanips[0].childNodes:
                 try:
                     self.config['plotmanips'].append(str(plotmanip.tagName))
                 except: #if we allow fancy formatting of xml, there is a text node, so tagName fails for it...
                     pass
-        
-        def handleWorkdir(workdir):
-            '''
-            default working directory
-            '''
-            wdir=getText(workdir[0].childNodes)
-            self.config['workdir']=wdir.strip()
-            
+
         def handleDefaultlist(defaultlist):
             '''
             default playlist
             '''
             dflist=getText(defaultlist[0].childNodes)
             self.config['defaultlist']=dflist.strip()
         def handleDefaultlist(defaultlist):
             '''
             default playlist
             '''
             dflist=getText(defaultlist[0].childNodes)
             self.config['defaultlist']=dflist.strip()
-            
+
         handleConfig(self.config_tree)
         #making items in the dictionary more machine-readable
         for item in self.config.keys():
         handleConfig(self.config_tree)
         #making items in the dictionary more machine-readable
         for item in self.config.keys():
@@ -245,13 +254,13 @@ class HookeConfig:
                     self.config[item]=None
                 else:
                     pass
                     self.config[item]=None
                 else:
                     pass
-                                                
+
         return self.config
         return self.config
-        
-        
+
+
     def save_config(self, config_filename):
         print 'Not Implemented.'
     def save_config(self, config_filename):
         print 'Not Implemented.'
-        pass    
+        pass
 
 
 class EngrFormatter(ScalarFormatter):
 
 
 class EngrFormatter(ScalarFormatter):
@@ -315,38 +324,38 @@ class ClickedPoint:
     this class defines what a clicked point on the curve plot is
     '''
     def __init__(self):
     this class defines what a clicked point on the curve plot is
     '''
     def __init__(self):
-        
+
         self.is_marker=None #boolean ; decides if it is a marker
         self.is_line_edge=None #boolean ; decides if it is the edge of a line (unused)
         self.absolute_coords=(None,None) #(float,float) ; the absolute coordinates of the clicked point on the graph
         self.graph_coords=(None,None) #(float,float) ; the coordinates of the plot that are nearest in X to the clicked point
         self.index=None #integer ; the index of the clicked point with respect to the vector selected
         self.dest=None #0 or 1 ; 0=top plot 1=bottom plot
         self.is_marker=None #boolean ; decides if it is a marker
         self.is_line_edge=None #boolean ; decides if it is the edge of a line (unused)
         self.absolute_coords=(None,None) #(float,float) ; the absolute coordinates of the clicked point on the graph
         self.graph_coords=(None,None) #(float,float) ; the coordinates of the plot that are nearest in X to the clicked point
         self.index=None #integer ; the index of the clicked point with respect to the vector selected
         self.dest=None #0 or 1 ; 0=top plot 1=bottom plot
-                
-        
+
+
     def find_graph_coords_old(self, xvector, yvector):
         '''
         Given a clicked point on the plot, finds the nearest point in the dataset (in X) that
         corresponds to the clicked point.
         OLD & DEPRECATED - to be removed
         '''
     def find_graph_coords_old(self, xvector, yvector):
         '''
         Given a clicked point on the plot, finds the nearest point in the dataset (in X) that
         corresponds to the clicked point.
         OLD & DEPRECATED - to be removed
         '''
-                   
+
         #FIXME: a general algorithm using min() is needed!
         #print '---DEPRECATED FIND_GRAPH_COORDS_OLD---'
         best_index=0
         best_dist=10**9 #should be more than enough given the scale
         #FIXME: a general algorithm using min() is needed!
         #print '---DEPRECATED FIND_GRAPH_COORDS_OLD---'
         best_index=0
         best_dist=10**9 #should be more than enough given the scale
-                
+
         for index in scipy.arange(1,len(xvector),1):
             dist=((self.absolute_coords[0]-xvector[index])**2)+(100*((self.absolute_coords[1]-yvector[index])))**2
                         #TODO, generalize? y coordinate is multiplied by 100 due to scale differences in the plot
             if dist<best_dist:
                 best_index=index
                 best_dist=dist
         for index in scipy.arange(1,len(xvector),1):
             dist=((self.absolute_coords[0]-xvector[index])**2)+(100*((self.absolute_coords[1]-yvector[index])))**2
                         #TODO, generalize? y coordinate is multiplied by 100 due to scale differences in the plot
             if dist<best_dist:
                 best_index=index
                 best_dist=dist
-                        
+
         self.index=best_index
         self.graph_coords=(xvector[best_index],yvector[best_index])
         return
         self.index=best_index
         self.graph_coords=(xvector[best_index],yvector[best_index])
         return
-            
+
     def find_graph_coords(self,xvector,yvector):
         '''
         Given a clicked point on the plot, finds the nearest point in the dataset that
     def find_graph_coords(self,xvector,yvector):
         '''
         Given a clicked point on the plot, finds the nearest point in the dataset that
@@ -355,12 +364,12 @@ class ClickedPoint:
         dists=[]
         for index in scipy.arange(1,len(xvector),1):
             dists.append(((self.absolute_coords[0]-xvector[index])**2)+((self.absolute_coords[1]-yvector[index])**2))
         dists=[]
         for index in scipy.arange(1,len(xvector),1):
             dists.append(((self.absolute_coords[0]-xvector[index])**2)+((self.absolute_coords[1]-yvector[index])**2))
-                        
+
         self.index=dists.index(min(dists))
         self.graph_coords=(xvector[self.index],yvector[self.index])
 #-----------------------------------------
         self.index=dists.index(min(dists))
         self.graph_coords=(xvector[self.index],yvector[self.index])
 #-----------------------------------------
-#CSV-HELPING FUNCTIONS        
-        
+#CSV-HELPING FUNCTIONS
+
 def transposed2(lists, defval=0):
     '''
     transposes a list of lists, i.e. from [[a,b,c],[x,y,z]] to [[a,x],[b,y],[c,z]] without losing
 def transposed2(lists, defval=0):
     '''
     transposes a list of lists, i.e. from [[a,b,c],[x,y,z]] to [[a,x],[b,y],[c,z]] without losing
@@ -369,12 +378,12 @@ def transposed2(lists, defval=0):
     '''
     if not lists: return []
     return map(lambda *row: [elem or defval for elem in row], *lists)
     '''
     if not lists: return []
     return map(lambda *row: [elem or defval for elem in row], *lists)
-        
+
 def csv_write_dictionary(f, data, sorting='COLUMNS'):
     '''
     Writes a CSV file from a dictionary, with keys as first column or row
     Keys are in "random" order.
 def csv_write_dictionary(f, data, sorting='COLUMNS'):
     '''
     Writes a CSV file from a dictionary, with keys as first column or row
     Keys are in "random" order.
-    
+
     Keys should be strings
     Values should be lists or other iterables
     '''
     Keys should be strings
     Values should be lists or other iterables
     '''
@@ -387,13 +396,13 @@ def csv_write_dictionary(f, data, sorting='COLUMNS'):
         writer.writerow(keys)
         for item in t_values:
             writer.writerow(item)
         writer.writerow(keys)
         for item in t_values:
             writer.writerow(item)
-        
+
     if sorting=='ROWS':
         print 'Not implemented!' #FIXME: implement it.
 
 
     if sorting=='ROWS':
         print 'Not implemented!' #FIXME: implement it.
 
 
-#-----------------------------------------        
-                    
+#-----------------------------------------
+
 def debug():
     '''
     debug stuff from latest rewrite of hooke_playlist.py
 def debug():
     '''
     debug stuff from latest rewrite of hooke_playlist.py