class AmbiguousUnion(properties.HasProperties): u = properties.Union( doc='ambiguous', props=[SomeProps, SameProps], strict_instances=True, )
class UnambigousUnion(properties.HasProperties): u = properties.Union( doc='unambiguous', props=[SomeProps, DifferentProps], strict_instances=True, )
class SurfaceElement(ProjectElement): """Contains mesh, data, textures, and options of a surface""" geometry = properties.Union('Structure of the surface element', props=(SurfaceGeometry, SurfaceGridGeometry)) textures = properties.List( 'Images mapped on the surface element', prop=ImageTexture, required=False, default=list, ) subtype = properties.StringChoice('Category of Surface', choices=('surface', ), default='surface') def toVTK(self): """Convert the surface to a its appropriate VTK data object type.""" from vtk.util import numpy_support as nps output = self.geometry.toVTK() # TODO: handle textures # Now add point data: for data in self.data: arr = data.array.array c = nps.numpy_to_vtk(num_array=arr) c.SetName(data.name) output.GetPointData().AddArray(c) return output
class HasOptionalUnion(properties.HasProperties): mybc = properties.Union( 'union of bool or color', props=[properties.Bool(''), properties.Color('')], required=False, )
class Slide(_BaseCollaborationModel, spatial.base._BaseResource): """Slides provide a snapshot of a 3D scene They also provide a canvas for annotating the scene. By creating several slides, you can tell a story around your 3D data. """ BASE_TYPE = 'slides' scene = spatial.base.InstanceSnapshot( 'Current state of the 3D scene', instance_class=Scene, ) annotation_plane = spatial.base.InstanceSnapshot( 'Drawing plane for annotations perpendicular to line of sight', instance_class=DrawingPlane, ) annotations = properties.List( 'List of annotations on the scene', properties.Union( '', props=[ spatial.base.InstanceSnapshot('', AnnotationText), spatial.base.InstanceSnapshot('', AnnotationInk), ], ), max_length=30, default=list, )
class ManyProperties(properties.HasProperties): mystr = properties.String( 'my string', serializer=reverse, deserializer=reverse, ) myarr = properties.Array( 'my array', serializer=to_string, deserializer=from_string, ) myinst = properties.Instance( 'my HP1', instance_class=HP1, serializer=serialize_a_only, deserializer=deserialize_from_a, ) mylist = properties.List( 'my list of HP1', prop=HP1, serializer=sum_of_a, deserializer=from_sum, ) myunion = properties.Union( 'string or HP1', props=(HP1, properties.String('')), serializer=just_the_classname, deserializer=reverse, )
class _BaseElementSurface(_BaseElement): """Base class for surface elements""" data = properties.List( 'Data defined on the element', prop=properties.Union( '', props=[ Pointer('', DataBasic), Pointer('', DataCategory), Pointer('', TextureProjection), ], ), max_length=100, default=list, ) defaults = InstanceSnapshot( 'Default visualization options', OptionsSurface, default={ 'visible': True, 'color': { 'value': 'random' }, 'opacity': { 'value': 1. }, 'wireframe': { 'active': False }, 'textures': [], }, )
class ManyProperties(properties.HasProperties): mystr = properties.String( 'my string', required=False, ) myarr = properties.Array( 'my array', required=False, ) myinst = properties.Instance( 'my HP1', instance_class=HP1, required=False, ) mylist = properties.List( 'my list of HP1', prop=HP1, required=False, default=properties.utils.undefined ) myunion = properties.Union( 'string or HP1', props=(HP1, properties.String('')), required=False, )
class _BaseElementPointSet(_BaseElement): """Base class for point-set elements""" data = properties.List( 'Data defined on the element', prop=properties.Union( '', props=[ Pointer('', DataBasic), Pointer('', DataCategory), Pointer('', TextureProjection), ], ), max_length=100, default=list, ) defaults = InstanceSnapshot( 'Default visualization options', OptionsPoints, default={ 'visible': True, 'color': { 'value': 'random' }, 'opacity': { 'value': 1. }, }, )
class _BaseOptionsData(_BaseOptionsItem): """Represents static or mapped data""" value = properties.Float( 'Static value, used if data is unspecified', required=False, ) data = properties.Union( 'Data for attribute visualization', props=[ Pointer('', DataBasic), Pointer('', DataCategory), ], required=False, ) mapping = properties.Union( 'Mapping to apply to data for visualization; must be specified ' 'if data is specified', props=[ Pointer('', MappingContinuous), Pointer('', MappingDiscrete), Pointer('', MappingCategory), ], required=False, ) @properties.validator def _validate_data(self): """Ensure value or data/mapping are set""" if self.data and not self.mapping: raise properties.ValidationError( message=( 'Mapping must be specified on visualization options if ' 'data is present'), reason='missing', prop='mapping', instance=self, ) if not self.data and self.value is None: raise properties.ValidationError( message=('Value must be specified on visualization options if ' 'data is not'), reason='missing', prop='value', instance=self, )
def test_is_pointer(): assert utils.is_pointer(PointerSubclass('', properties.HasProperties)) assert utils.is_pointer( properties.Union('', props=[ PointerSubclass('', properties.HasProperties), properties.extras.Pointer( '', properties.HasProperties), ])) assert not utils.is_pointer( properties.Instance('', properties.HasProperties)) assert not utils.is_pointer( properties.Union('', props=[ PointerSubclass('', properties.HasProperties), properties.Instance('', properties.HasProperties), ]))
class ValidateColorThenString(properties.HasProperties): values = properties.Union( 'Values', props=[ properties.List('', properties.Color('')), properties.List('', properties.String('')), ], )
class HasIntAndList(properties.HasProperties): myints = properties.Union('union of int or int list', props=[ properties.Integer(''), properties.List( '', properties.Integer(''), min_length=2) ])
class HasOptPropsUnion(properties.HasProperties): mybc = properties.Union( 'union of bool or color', props=[ properties.Bool('', required=False), properties.Color('', required=False), ], required=True, )
class Plot(_BaseSceneComponent): """Object describing the contents of the 3D scene Contains info about how a plot is positioned in the scene, as well as the plot limits. Also contains active elements, slices, and measurements in the plot. """ position = properties.Vector3( 'x,y,z position of the plot center relative to scene origin', default=lambda: [0., 0, 0], ) scale = properties.Vector3( 'x,y,z scale of the plot coordinate system relative to scene ' 'coordinate system', default=lambda: [1., 1, 1], ) rotation = properties.List( 'Quaternion rotation of plot axes relative to scene axes', properties.Float(''), min_length=4, max_length=4, default=lambda: [0., 0, 0, 1], ) lims = properties.List( 'x,y,z limits, defined in plot coordinates', properties.Vector2(''), min_length=3, max_length=3, default=lambda: [[0, 0.00001]] * 3, ) exaggeration = properties.List( 'x,y,z exaggeration of the plot coordinates', properties.Integer('', min=1), default=lambda: [1, 1, 1], ) slice_groups = properties.List( 'Active slice groups; currently only one is supported', SliceGroup, max_length=1, default=lambda: [SliceGroup()], ) measurements = properties.List( 'List of active ruler instances; currently only one is supported', Ruler, max_length=1, default=list, ) views = properties.List( 'List of element views in the plot', properties.Union('', [ view for key, view in _BaseSceneComponent._REGISTRY.items() if key[0] != '_' and issubclass(view, _BaseElementView) ]), max_length=100, default=list, )
class Legend(ContentModel): """Legends to be used with DataMap indices""" values = properties.Union( 'values for mapping indexed data', props=( ColorArray, DateTimeArray, StringArray, ScalarArray ) )
class SurfaceElement(ProjectElement): """Contains mesh, data, textures, and options of a surface""" geometry = properties.Union('Structure of the surface element', props=(SurfaceGeometry, SurfaceGridGeometry)) textures = properties.List( 'Images mapped on the surface element', prop=ImageTexture, required=False, default=list, ) subtype = properties.StringChoice('Category of Surface', choices=('surface', ), default='surface')
class _BaseElementLineSet(_BaseElement): """Base class for line-set elements""" defaults = properties.Union( 'Default visualization options', props=[ InstanceSnapshot('', OptionsLines), InstanceSnapshot('', OptionsTubes), ], default={ 'visible': True, 'color': { 'value': 'random' }, 'opacity': { 'value': 1. }, }, )
class _BaseElementVolume(_BaseElement): """Base class for volume elements""" defaults = properties.Union( 'Default visualization options', props=[ InstanceSnapshot('', OptionsBlockModel), InstanceSnapshot('', OptionsVolumeSlices), ], default={ 'visible': True, 'color': { 'value': 'random' }, 'opacity': { 'value': 1. }, 'wireframe': { 'active': False }, }, )
class ColorData(ProjectElementData): """Data array of RGB colors specified as three integers 0-255 or color If n x 3 integers is provided, these will simply be clipped to values between 0 and 255 inclusive; invalid colors will not error. This allows fast array validation rather than slow element-by-element list validation. Other color formats may be used (ie String or Hex colors). However, for large arrays, validation of these types will be slow. """ array = properties.Union( 'RGB color values at locations on a mesh (see location parameter)', props=( Int3Array, ColorArray ) ) @properties.validator('array') def _clip_colors(self, change): #pylint: disable=no-self-use """This validation call fires immediately when array is set""" if isinstance(change['value'], Int3Array): change['value'].array = np.clip(change['value'].array, 0, 255)
class _BaseElement(_BaseResource): """Base class for elements""" BASE_TYPE = 'elements' data = properties.List( 'Data defined on the element', prop=properties.Union( '', props=[ Pointer('', DataBasic), Pointer('', DataCategory), ], ), max_length=100, default=list, ) @property def num_nodes(self): """Number of nodes (vertices)""" raise NotImplementedError() @property def num_cells(self): """Number of cells""" raise NotImplementedError() @property def location_lengths(self): lengths = { 'nodes': self.num_nodes, 'cells': self.num_cells, } return lengths @properties.validator def _validate_data(self): """Check if element is built correctly""" if not self.data: return True for data in self.data: if isinstance(data, (string_types, TextureProjection)): continue if data.location not in self.location_lengths: raise properties.ValidationError( message='Invalid location {} - valid values: {}'.format( data.location, ', '.join(self.location_lengths)), reason='invalid', prop='data', instance=self, ) if isinstance(data.array, string_types): continue valid_length = self.location_lengths[data.location] if valid_length is None: continue if data.array.shape[0] != valid_length: raise properties.ValidationError( message=('data {index} length {datalen} does not match ' '{loc} length {meshlen}'.format( index=data.name, datalen=data.array.shape[0], loc=data.location, meshlen=valid_length, )), reason='invalid', prop='data', instance=self, ) return True
class DataBasic(_BaseData): """Basic numeric attribute data This data type is defined by an array that directly maps to an element geometry. For no-data values, use NaN. Currently, this only accepts 1D arrays and, when applied to a grid, the array must be stored in row-major order. """ BASE_TYPE = 'data' SUB_TYPE = 'basic' array = Pointer( 'Array of numeric values at locations on an element geometry, ' 'specified by the location property', Array, ) location = properties.StringChoice( 'Location of the data on geometry', choices={ 'nodes': ['N', 'node', 'vertices', 'corners'], 'cells': ['CC', 'cell', 'segments', 'faces', 'blocks'], }) mappings = properties.List( 'Mappings associated with the data', prop=properties.Union( '', props=[ Pointer('', MappingContinuous), Pointer('', MappingDiscrete), ], ), max_length=100, default=list, ) @properties.validator('array') def _validate_array_1d(self, change): """Ensure the array is 1D""" if (isinstance(change['value'], string_types) or change['value'] is properties.undefined): return if not change['value'].is_1d(): raise properties.ValidationError( message='{} must use 1D array'.format( self.__class__.__name__, ), reason='invalid', prop='array', instance=self, ) def to_omf(self, cell_location): self.validate() if self.location == 'nodes': location = 'vertices' else: location = cell_location omf_data = omf.ScalarData( name=self.name or '', description=self.description or '', location=location, array=self.array.array, ) return omf_data
class Surface(CompositeResource): """Contains all the information about a 2D surface""" mesh = properties.Union(doc='Mesh', props=(properties.Instance('', Mesh2D, default=Mesh2D), properties.Instance('', Mesh2DGrid))) data = properties.List( doc='Data', prop=_SurfaceBinder, coerce=True, required=False, default=list, ) textures = properties.List( doc='Textures', prop=Texture2DImage, coerce=True, required=False, default=list, ) opts = properties.Instance( doc='Options', instance_class=_SurfaceOptions, default=_SurfaceOptions, ) def _nbytes(self): return (self.mesh._nbytes() + sum(d.data._nbytes() for d in self.data) + sum(t._nbytes() for t in self.textures)) @properties.validator def _validate_data(self): """Check if resource is built correctly""" for ii, dat in enumerate(self.data): assert dat.location in ('N', 'CC') valid_length = (self.mesh.nC if dat.location == 'CC' else self.mesh.nN) if len(dat.data.array) != valid_length: raise ValueError( 'surface.data[{index}] length {datalen} does not match ' '{loc} length {meshlen}'.format(index=ii, datalen=len( dat.data.array), loc=dat.location, meshlen=valid_length)) return True def _to_omf(self): import omf element = omf.SurfaceElement( name=self.title or '', description=self.description or '', geometry=self.mesh._to_omf(), color=self.opts.color or 'random', data=[], textures=[tex._to_omf() for tex in self.textures]) for data in self.data: if data.location == 'CC': location = 'faces' else: location = 'vertices' omf_data = data.data._to_omf() omf_data.location = location element.data.append(omf_data) return element
class HasBoolColor(properties.HasProperties): mybc = properties.Union( 'union of bool or color', props=[properties.Bool(''), properties.Color('')])
def test_union_default(self): class HasUnionA(properties.HasProperties): a = properties.Union( 'union', (properties.Integer(''), properties.String(''))) hu = HasUnionA() assert hu.a is None hu.a = 5 hu.a = 'hi' del (hu.a) assert hu.a is None class HasUnionB(properties.HasProperties): b = properties.Union( 'union', (properties.Integer('', default=5), properties.String(''))) hu = HasUnionB() assert hu.b == 5 hu.b = 'hi' del (hu.b) assert hu.b is None class HasUnionC(properties.HasProperties): c = properties.Union( 'union', (properties.Integer(''), properties.String( '', default='hi'), properties.Integer(''))) hu = HasUnionC() assert hu.c == 'hi' hu.c = 5 del (hu.c) assert hu.c is None class HasUnionD(properties.HasProperties): d = properties.Union( 'union', (properties.Integer(''), properties.String(''), properties.Integer('')), default=100) hu = HasUnionD() assert hu.d == 100 hu.d = 5 del (hu.d) assert hu.d is None with self.assertRaises(TypeError): properties.Union('union', (properties.Integer(''), properties.Bool('')), default=0.5) with warnings.catch_warnings(record=True) as w: properties.Union('union', (properties.Integer( '', default=5), properties.Bool('', default=True))) assert len(w) == 1 assert issubclass(w[0].category, RuntimeWarning) with warnings.catch_warnings(record=True) as w: properties.Union('union', (properties.Integer( '', default=5), properties.Bool('', default=True)), default=False) assert len(w) > 0 assert issubclass(w[0].category, RuntimeWarning) def twelve(): return 12 HasUnionD._props['d'].default = twelve hu = HasUnionD() assert hu.d == 12 HasUnionD._props['d'].default = properties.undefined hu = HasUnionD() assert hu.d is None
class HasUnionA(properties.HasProperties): a = properties.Union( 'union', (properties.Integer(''), properties.String('')))
class HasProps1(properties.HasProperties): my_hp2 = properties.Instance('my HasProps2', HasProps2) my_union = properties.Union( 'string or int', (properties.String(''), properties.Integer('')) )
class HasUnionC(properties.HasProperties): c = properties.Union( 'union', (properties.Integer(''), properties.String( '', default='hi'), properties.Integer('')))
class HasUnionB(properties.HasProperties): b = properties.Union( 'union', (properties.Integer('', default=5), properties.String('')))
class HasUnionD(properties.HasProperties): d = properties.Union( 'union', (properties.Integer(''), properties.String(''), properties.Integer('')), default=100)