tvaLib
tools_constructors.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # tvaLib Copyright (c) 2012-2016 Paul G. St-Aubin
3 # Ecole Polytechnique de Montreal, McGill University
4 # Python 2.7; (dt) Spyder Windows 10 64-bit; ipython Ubuntu 15.04 64-bit
5 
9 from re import search as re_search
10 #Numpy (It is necessary to fail import gracefully to accomodate failure screen. Numpy, and others, are mandatory anyways and should be checked at start of program)
11 try: from numpy import array as np_array
12 except: pass
13 
14 import tools_parse as Parse
15 
16 
17 
18 
21 class SuperList():
22  ''' A SuperList is an object which behaves similar to a regular python list
23  but includes methods that are useful for manipulating the data
24  contained inside the list. This is especially useful for lists of
25  object instances which may not be manipulated with simple list
26  comprehensions.
27 
28  This is a generic class from which many object-instance-dependant
29  methods are derived, but defines the generic object structure.
30 
31  '''
32  def __init__(self):
33  self.data = []
34  return
35 
36  def __repr__(self): return self.__class__.__name__+' '+str(self.data)
37  def __str__(self): return self.__class__.__name__+' '+str(self.data)
38  def __len__(self): return len(self.data)
39  def __getitem__(self, i): return self.data[i]
40  def __iter__(self): return iter(self.data)
41  def __add__(self, slist): self.data += slist.data; return None
42  def append(self,value): return self.data.append(value)
43  def reverse(self): self.data.reverse();return None
44  def count(self, value): return self.data.count(value)
45  def index(self, value): return self.data.index(value)
46  def asNpArray(self): return np_array(self.data)
47  def write(self):
48  if(len(self.data)>0 and hasattr(self.data[0],'write')): return str([x.write() for x in self.data])
49  else: return str(self.data)
50 
51  def get(self, i=None, id=None, name=None):
52  if(i != None):
53  return self.data[i]
54  elif(id != None and len(self.data) > 0 and hasattr(self.data[0], 'id')):
55  for i in self.data:
56  if(i.id == id):
57  return i
58  return False
59  elif(name != None and len(self.data) > 0 and hasattr(self.data[0], 'name')):
60  for i in self.data:
61  if(i.name == name):
62  return i
63  return False
64  else:
65  return False
66 
67  def getIndex(self, **kwargs):
68  ''' Get index of object based on that object's property value.
69 
70  Example usage to return the index for a child object who's name is
71  'foobar':
72 
73  idx = myList.getIndex(name='foobar')
74 
75  '''
76  if(kwargs is not None):
77  for key, value in kwargs.iteritems():
78  if(len(self.data) > 0 and hasattr(self.data[0], key)):
79  for i in range(len(self.data)):
80  if(getattr(self.data[i], key) == value): return i
81  return None
82 
83 
84  def getRange(self): return range(len(self.data))
85 
86 
87 
89  ''' This is a SuperList with added string parsing functionality. '''
90  def __init__(self, input, type='float', dimension=2, datatype='point', **kwargs):
91  SuperList.__init__(self)
92  self.dimension = dimension
93  self.type = type
94  self.datatype = datatype
95  self.load(input, **kwargs)
96  return
97 
98  def addItem(self,data):
99  if(self.dimension==3 and self.datatype=='point'): self.data.append(SuperPointList(data))
100  elif(self.dimension==2 and self.datatype=='point'): self.data.append(SuperPoint(data))
101  elif(self.dimension==2 and self.datatype=='bound'): self.data.append(SuperBound(data))
102  else: self.data.append(data)
103  return True
104 
105  def load(self, input, **kwargs):
106  input_list = self.read(input, **kwargs)
107  for item in input_list:
108  self.addItem(item)
109  return True
110 
111  def read(self, data, **kwargs):
112  if(data and type(data) == list):
113  return data
114  elif(data):
115  if(self.dimension==3): return Parse.list3D(data.encode('ascii','ignore'), i_type=self.type)
116  elif(self.dimension==2): return Parse.list2D(data.encode('ascii','ignore'), i_type=self.type)
117  else: return Parse.list1D(data.encode('ascii','ignore'), i_type=self.type, **kwargs)
118  else: return []
119 
120  def write(self):
121  ''' This should be called from the parent object in order to store the
122  data properly in a DB using SQLAlchemy.
123  '''
124  try: return_val = '['+','.join(map(str, [data.write() for data in self.data]))+']'
125  except: return_val = '['+','.join(map(str, self.data))+']'
126 
127  if(return_val == '[]'): return ''
128  else: return return_val
129 
130 
132  def __init__(self,point):
133  ''' Generic point object '''
134  self.size = min(3,len(point))
135  self.x = point[0]
136  self.y = point[1]
137  if(len(point) > 2): self.z = point[2]
138  return
139 
140  def __repr__(self): return self.write()
141  def __str__(self): return self.write()
142  def __len__(self): return self.size
143  def __getitem__(self,i):
144  ''' Map features to indeces and allow calling by index. '''
145  if(i==1 and self.size>1): return self.y
146  elif(i==2 and self.size>2): return self.z
147  else: return self.x
148 
149  def write(self):
150  try: return '['+str(self.x)+','+str(self.y)+','+str(self.z)+']'
151  except: return '['+str(self.x)+','+str(self.y)+']'
152 
154  def __init__(self,bounds):
155  ''' Generic bound object '''
156  self.lower = bounds[0]
157  self.upper = bounds[1]
158  return
159 
160  def __repr__(self): return self.write()
161  def __str__(self): return self.write()
162 
163  def write(self):
164  return '['+str(self.lower)+','+str(self.upper)+']'
165 
167  def __init__(self,points):
168  ''' Normally, points is a list of SuperPoints but it can also be a
169  2-dimensional list.
170  '''
171  self.pos = []
172  for point in points:
173  if(isinstance(points[0], SuperPoint)): self.pos.append(point)
174  else: self.pos.append(SuperPoint(point))
175  return
176 
177  def __repr__(self): return 'SuperPointList(type '+self.__class__.__name__+') '+str(self.pos)
178  def __str__(self): return 'SuperPointList(type '+self.__class__.__name__+') '+str(self.pos)
179  def __len__(self): return len(self.pos)
180  def __getitem__(self,i): return self.pos[i]
181  def __iter__(self): return iter(self.pos)
182  def append(self,value): return self.pos.append(value)
183  def reverse(self): self.pos.reverse();return None
184  def count(self, value): return self.pos.count(value)
185 
186  def getXCoordinates(self): return[point.x for point in self.pos]
187  def getYCoordinates(self): return[point.y for point in self.pos]
188 
189  def write(self):
190  storage_value = []
191  for pos in self.pos:
192  storage_value.append(pos)
193  return '['+','.join(map(str, storage_value))+']'
194 
195 
196 
199 class Tree():
200  def __init__(self, level=0, parent=None):
201  self.level = level
202  self.parent = parent
203  self.branches = []
204 
205  def __len__(self): return len(self.branches)
206  def __getitem__(self,i): return self.branches[i]
207  def __iter__(self): return iter(self.branches)
208 
209  def addBranch(self, **kwargs):
210  self.branches.append(Tree(level=self.level+1, parent=self, **kwargs))
211 
213  if(not hasattr(self, 'paths')): self.genPathsToBranchEnds()
214  return self.paths
215 
216  def genPathsToBranchEnds(self, path=None, structure=None):
217  if(path == None): path = []
218  if(not structure):
219  self.paths = []
220  structure = self.crawlbranchesForStructure()
221  for struct in range(len(structure)):
222  if(not structure[struct]): self.paths.append(path+[struct])
223  else: self.genPathsToBranchEnds(path=path+[struct], structure=structure[struct])
224  return True
225 
227  if(not self.branches): return []
228  indexLevel=[]
229  for branch in range(len(self.branches)):
230  if(self.branches[branch].level < self.level): continue
231  else: indexLevel.append(self.branches[branch].crawlbranchesForStructure())
232  return indexLevel
233 
234 
235  def goToBranch(self,list_):
236  if(len(self.branches) > 0 and list_ and len(list_) > 1): return self.branches[list_[0]].goToBranch(list_[1:])
237  else: return self
238 
239  def countTips(self):
240  if(not hasattr(self, 'paths')): self.genPathsToBranchEnds()
241  return len(self.paths)
242 
243 
244 
248  def parseString(self, string):
249  if(string and type(string)==unicode): return string.encode('ascii','ignore')
250  else: return string
251 
252  def interpret(self, value='', attr=None, returnIndices=True, interpretStrAsLiteralIndex=False):
253  ''' Interpret value as a search term in SQLalchemy:
254  ===============================================
255  Return index corresponding to matching search criteria.
256 
257  'value' is the search criteria parameter and this functions expects
258  an ID, a range of IDs or a name to be passed as a string (or INT if
259  a single ID). NOTE: ID is one larger than index, and the returned
260  index is ALWAYS an INT.
261 
262  Conditions:
263  ===========
264  value is empty: return all
265  value is string 'all': return all
266  attr is not None: return lietaral search for a specified attribute equal to value
267  value is an INT: return equivalent index, i.e. one less than value (useful for large structured lists where selection is relative)
268  value is STRING that looks like an INT: return a corresponding index of the object matching it's idx attribute to value
269  data has name attribute equal to value: return a corresponding index of the matching object
270  value is LIST of INT: return a corresponding list of index values (one less, each)
271  value is STRING that looks like a list of INT: return a corresponding list of index values (one less than equivalent STRING value, each)
272  value is STRING that looks like a range of INT (e.g. 1-10): return a corresponding list of index values (one less than equivalent range value, each)
273 
274  Output options:
275  ===============
276  returnIndices True: returns a range of indeces
277  returnIndices False: returns data itself
278  '''
279  if(len(self.data) <= 0): return []
280 
281  #Parse string into list if applicable
282  if(type(value)==str and not re_search('[^\d\-,]', value) and (value.find(',')!=-1 or value.find('-')!=-1)): value = Parse.list1D(value)
283 
284  indeces = []
285  if(value and value != 'all'):
286  if(attr):
287  indeces = [self.getIndex(**{attr:value})]
288  elif(type(value)==int and len(self.data) >= value):
289  indeces = [value-1]
290  elif(type(value)==str and value.isdigit() and 0 < int(value) and int(value) <= len(self.data)):
291  if(interpretStrAsLiteralIndex): indeces = [int(value)-1]
292  else: indeces = [self.getIndex(idx=int(value))]
293  elif(hasattr(self.data[0], 'name') and self.getIndex(name=str(value))):
294  indeces = [self.getIndex(name=str(value))]
295  elif(isinstance(value, SuperList) or isinstance(value, SuperListParse) or (type(value)==list and len(value) and max(value) <= len(self.data))):
296  indeces = [self.getIndex(idx=x) for x in value]
297  else: indeces = range(len(self.data))
298 
299  if(returnIndices): return indeces
300  else: return [self.data[x] for x in indeces]
def genPathsToBranchEnds(self, path=None, structure=None)
Generic recursive structures.
def join(obj1, obj2, postSmoothing=True)
Definition: tools_obj.py:816
def get(self, i=None, id=None, name=None)
def __init__(self, input, type='float', dimension=2, datatype='point', kwargs)
def interpret(self, value='', attr=None, returnIndices=True, interpretStrAsLiteralIndex=False)
Generic data format structures.
def __init__(self, level=0, parent=None)
The following objects define generic constructors.