from traits.api import *
from pyparty import Canvas
from pyparty.utils import to_normrgb
import operator as oper
from collections import OrderedDict
def radius(obj):
return getattr(obj, 'equivalent_diameter')/2.0
SHORTCUTS = {'d':'equivalent_diameter',
'r': radius } # r ?
# Don't change order; may affect multisplot; not sure
COMP_OPS = OrderedDict([
("==",np.equal), ("!=",np.not_equal), ("<",np.less),
(">",np.greater), (">=",np.greater_equal), ("<=",np.less_equal)
] )
LOGIC_OPS = OrderedDict([
("&",np.logical_and), ("|",np.logical_or)
])
#http://code.activestate.com/recipes/577616-split-strings-w-multiple-separators/
def multisplit(s, sep):
splitchar = []
stack = [s]
for char in sep:
pieces = []
for substr in stack:
pieces.extend(substr.split(char))
stack = pieces
if char in s:
splitchar.append(char)
return stack, splitchar
class ModelError(Exception):
""" """
# Name is classname/vairable name
class Model(HasTraits):
classifier = Str()
_classfcn = Property(depends_on='classifier')
color = Any(None)
def _color_changed(self, old, new):
if new:
self.color=to_normrgb(new)
def parse_canvas(self, canvas):
""" Apply masks to canvas. Should split the parsing of the operators into python expressions and return,
and have parsed canvas work with those, but for now, wrapping everything into a single method for prototyping."""
masks = []
lops = []
# Split on '|' and '&'
logic_ops, LOGIC_CHARS = multisplit(self.classifier, LOGIC_OPS.keys())
# NEED SOMEHOW TO SPLIT BY LOGIC CHARS AND ITERATE OVER OTEHR EXPRESSION
for op in logic_ops: # op is (d < 50)
nospace = "".join(op.split()) # Strip whitespace
### Paranethesis operations
#( (foo) & (bar) ) | (baz); can't handle these
if nospace.count('(') != 1 or nospace.count(')') != 1:
raise ModelError("Cannot handle muli-paranethesis expression: %s" % op)
if nospace[0] != '(' or nospace[-1] != ')':
raise ModelError("Invalid logic function: %s" % op)
nospace = nospace.strip("(").strip(")")
# Split on comparison operator (<, == etc..)
comp_split, COMP_CHAR = multisplit(nospace, COMP_OPS.keys())
if len(comp_split) != 2:
raise ModelError('Invalid comparison operator: %s---> [ %s ]' % (op, ", ".join(COMP_OPS) ))
variable, value = comp_split
value = float(value)
if len(COMP_CHAR) != 1:
raise ModelError("Comparison operator list != 1 %s" % COMP_CHAR)
comp_char = COMP_CHAR[0]
# Return partial function for value attribute
if variable in SHORTCUTS:
variable = SHORTCUTS[variable]
if isinstance(variable, str):
variable = oper.attrgetter(variable)
# NEED OBJECT ACCESS STARTING HERE!
descriptor_array = variable(canvas) #c.area
# Worth doing
if not isinstance(descriptor_array, np.ndarray):
raise ModelError('Attribute inspection not return an array')
comp_op = COMP_OPS[comp_char]
mask = comp_op(descriptor_array, value)
masks.append(mask)
if LOGIC_CHARS:
ls = [LOGIC_OPS[char] for char in LOGIC_CHARS]
ms, mf = masks.pop(0), masks.pop(0)
l = ls.pop(0)
lout = l(ms,mf)
while masks:
m = masks.pop(0)
lout = l(lout, m)
else:
lout = masks[0] #Should only be one mask, no?
# HOW TO HANDLE NULL VALUES EG NEGATIVES??
# Copy canvas and particles and shit
cp = []
cp[:] = canvas.particles[lout]
cout = Canvas.copy(canvas)
cout._particles.plist[:] = cp[:]
if self.color:
def cmap(p):
p.color = self.color
return p
cout = cout.pmap(cmap)
return cout
#return lout
def _get__classfcn(self):
return eval(self.classifier)
class Diameter(Model):
classifier = '(d > 20) & (d < 70)'
# color = None
# classifier = '(d > 15)'
m1 = Diameter(color='teal')
c=Canvas.random_circles()
from pyparty import Canvas, splot
c=Canvas.random_circles()
f = m1.parse_canvas(c)
ax1, ax2 = splot(1,2)
c.show(ax1)
f.show(ax2);
--------------------------------------------------------------------------- CanvasAttributeError Traceback (most recent call last) <ipython-input-3-2bc5a23f3ff0> in <module>() 4 from pyparty import Canvas, splot 5 c=Canvas.random_circles() ----> 6 f = m1.parse_canvas(c) 7 8 ax1, ax2 = splot(1,2) <ipython-input-1-9d9dc0d34fec> in parse_canvas(self, canvas) 125 p.color = self.color 126 return p --> 127 cout = cout.pmap(cmap) 128 129 return cout /home/glue/Desktop/pyparty/pyparty/tools/canvas.py in pmap(self, fcn, *fcnargs, **fcnkwargs) 197 self._particles.map(fcn, *fcnargs, **fcnkwargs) 198 else: --> 199 cout = Canvas.copy(self) 200 cout._particles.map(fcn, *fcnargs, **fcnkwargs) 201 return cout /home/glue/Desktop/pyparty/pyparty/tools/canvas.py in copy(cls, obj, grid, background, particles, rez, _threshfcn) 974 975 if not _threshfcn: --> 976 _threshfcn = obj.threshfcn 977 978 return cls(background=background, /home/glue/Desktop/pyparty/pyparty/tools/canvas.py in threshfcn(self) 144 def threshfcn(self): 145 try: --> 146 return self._threshtype 147 except AttributeError: 148 return None /home/glue/Desktop/pyparty/pyparty/tools/canvas.py in __getattr__(self, attr) 899 raise CanvasAttributeError('"%s" could not be found on %s, ' 900 'underlying manager, or on one-or multiple of the ' --> 901 'Particles' % (attr, self.__class__.__name__) ) 902 903 def __iter__(self): CanvasAttributeError: "_threshtype" could not be found on Canvas, underlying manager, or on one-or multiple of the Particles