class Annotater(Component): color = ColorTrait((0.0, 0.0, 0.0, 0.2)) style = Trait("rectangular", TraitPrefixList(["rectangular", 'freehand'])) annotation = Event traits_view = View(Group('<component>', id='component'), Group('<links>', id='links'), Group('color', 'style', id='annotater', style='custom')) #--------------------------------------------------------------------------- # Mouse event handlers #--------------------------------------------------------------------------- def _left_down_changed(self, event): event.handled = True self.window.mouse_owner = self self._cur_x, self._cur_y = event.x, event.y self._start_x, self._start_y = event.x, event.y return def _left_up_changed(self, event): event.handled = True self.window.mouse_owner = None if self.xy_in_bounds(event): self.annotation = (min(self._start_x, event.x), min(self._start_y, event.y), abs(self._start_x - event.x), abs(self._start_y - event.y)) self._start_x = self._start_y = self._cur_x = self._cur_y = None self.redraw() return def _mouse_move_changed(self, event): event.handled = True if self._start_x is not None: x = max(min(event.x, self.right - 1.0), self.x) y = max(min(event.y, self.top - 1.0), self.y) if (x != self._cur_x) or (y != self._cur_y): self._cur_x, self._cur_y = x, y self.redraw() return #--------------------------------------------------------------------------- # "Component" interface #--------------------------------------------------------------------------- def _draw(self, gc): "Draw the contents of the control" if self._start_x is not None: with gc: gc.set_fill_color(self.color_) gc.begin_path() gc.rect(min(self._start_x, self._cur_x), min(self._start_y, self._cur_y), abs(self._start_x - self._cur_x), abs(self._start_y - self._cur_y)) gc.fill_path() return
class complex_value(HasTraits): num1 = Trait(1, TraitRange(1, 5), TraitRange(-5, -1)) num2 = Trait( 1, TraitRange(1, 5), TraitPrefixList("one", "two", "three", "four", "five"), ) num3 = Trait( 1, TraitRange(1, 5), TraitPrefixMap({"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}), ) num4 = Trait(1, Trait(1, Tuple, slow), 10) num5 = Trait(1, 10, Trait(1, Tuple, slow))
def test_handler_warning(self): handlers = { "TraitDict": TraitDict, "TraitList": TraitList, "TraitTuple": TraitTuple, "TraitPrefixList": lambda: TraitPrefixList("one", "two"), "TraitPrefixMap": lambda: TraitPrefixMap({}), } for name, handler_factory in handlers.items(): with self.subTest(handler=name): with warnings.catch_warnings(record=True): warnings.simplefilter("error", DeprecationWarning) with self.assertRaises(DeprecationWarning) as cm: handler_factory() self.assertIn(name, str(cm.exception))
class SubsetListEditor(VerticalListEditor): # the name of the trait containing the names --> values dict conditions = Str # the name of the trait containing the metadata dict metadata = Str # a string to evaluate on the metadata to see if we include this condition # in the editor when = Str # override some defaults style = Trait("custom", TraitPrefixList('simple', 'custom', 'text', 'readonly')) mutable = Bool(False) # use the custom editor above, which extends the qt4.ListEditor class def _get_simple_editor_class(self): return _SubsetListEditor
from __future__ import absolute_import from pyface.ui_traits import (Alignment, Border, HasBorder, HasMargin, Image, Margin, Position, convert_bitmap, convert_image) from traits.api import (Any, Delegate, Enum, Expression, Float, HasStrictTraits, List, Range, Str, Trait, TraitError, TraitPrefixList, TraitType) import six #------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------- # Orientation trait: Orientation = Trait('vertical', TraitPrefixList('vertical', 'horizontal')) # Styles for user interface elements: EditorStyle = style_trait = Trait( 'simple', TraitPrefixList( 'simple', 'custom', 'text', 'readonly'), cols=4) # Group layout trait: Layout = Trait('normal', TraitPrefixList('normal', 'split', 'tabbed', 'flow', 'fold'))
class Streamline(Module): # The version of this class. Used for persistence. __version__ = 0 # The streamline generator. stream_tracer = Instance(tvtk.StreamTracer, allow_none=False, record=True) # The seed for the streamlines. seed = Instance(SourceWidget, allow_none=False, record=True) # The update mode of the seed -- this is delegated to the # SourceWidget. update_mode = Delegate('seed', modify=True) # Determines if the streamlines are shown as lines or ribbons or # tubes. streamline_type = Trait('line', TraitPrefixList(['line', 'ribbon', 'tube']), desc='draw streamlines as lines/ribbons/tubes') # The ribbon filter. ribbon_filter = Instance(tvtk.RibbonFilter, allow_none=False, record=True) # The tube filter. tube_filter = Instance(tvtk.TubeFilter, allow_none=False, record=True) # The actor component that represents the visualization. actor = Instance(Actor, allow_none=False, record=True) input_info = PipelineInfo(datasets=['any'], attribute_types=['any'], attributes=['vectors']) ######################################## # Private traits. _first = Bool(True) ######################################## # View related code. # A button to update the streamlines. update_streamlines = Button('Update Streamlines') _tube_group = Group(Item(name='capping'), Item(name='sides_share_vertices'), Item(name='vary_radius'), Item(name='number_of_sides'), Item(name='radius'), Item(name='radius_factor'), Item(name='offset'), Item(name='on_ratio')) _ribbon_group = Group(Item(name='vary_width'), Item(name='width'), Item(name='width_factor'), Item(name='angle')) view = View(Group( Group(Item(name='update_mode'), ), Group( Item(name='update_streamlines'), show_labels=False, ), Group(Item(name='streamline_type'), Item(name='ribbon_filter', style='custom', visible_when='object.streamline_type == "ribbon"', editor=InstanceEditor(view=View(_ribbon_group))), Item(name='tube_filter', style='custom', visible_when='object.streamline_type == "tube"', editor=InstanceEditor(view=View(_tube_group))), show_labels=False, label='Streamline'), label='Streamline'), Group(Item(name='seed', style='custom', resizable=True), label='Seed', show_labels=False), Group(Item(name='stream_tracer', style='custom', resizable=True), label='StreamTracer', show_labels=False), Group(Item(name='actor', style='custom'), label='Actor', show_labels=False), resizable=True) ###################################################################### # `Module` interface ###################################################################### def setup_pipeline(self): """Override this method so that it *creates* the tvtk pipeline. This method is invoked when the object is initialized via `__init__`. Note that at the time this method is called, the tvtk data pipeline will *not* yet be setup. So upstream data will not be available. The idea is that you simply create the basic objects and setup those parts of the pipeline not dependent on upstream sources and filters. You should also set the `actors` attribute up at this point. """ # Create and setup the default objects. self.seed = SourceWidget() self.stream_tracer = tvtk.StreamTracer( maximum_propagation=50, integration_direction='forward', compute_vorticity=True, integrator_type='runge_kutta4', ) self.ribbon_filter = tvtk.RibbonFilter() self.tube_filter = tvtk.TubeFilter() self.actor = Actor() # Setup the actor suitably for this module. self.actor.property.line_width = 2.0 def update_pipeline(self): """Override this method so that it *updates* the tvtk pipeline when data upstream is known to have changed. This method is invoked (automatically) when any of the inputs sends a `pipeline_changed` event. """ mm = self.module_manager if mm is None: return src = mm.source self.configure_connection(self.stream_tracer, src) self.seed.inputs = [src] # Setup the radius/width of the tube/ribbon filters based on # given input. if self._first: b = src.outputs[0].bounds l = [(b[1] - b[0]), (b[3] - b[2]), (b[5] - b[4])] length = sqrt(l[0] * l[0] + l[1] * l[1] + l[2] * l[2]) self.ribbon_filter.width = length * 0.0075 self.tube_filter.radius = length * 0.0075 self._first = False self._streamline_type_changed(self.streamline_type) # Set the LUT for the mapper. self.actor.set_lut(mm.scalar_lut_manager.lut) self.pipeline_changed = True def update_data(self): """Override this method so that it flushes the vtk pipeline if that is necessary. This method is invoked (automatically) when any of the inputs sends a `data_changed` event. """ # Just set data_changed, the components should do the rest if # they are connected. self.data_changed = True ###################################################################### # Non-public methods. ###################################################################### def _streamline_type_changed(self, value): if self.module_manager is None: return st = self.stream_tracer rf = self.ribbon_filter tf = self.tube_filter if value == 'line': configure_outputs(self, st) elif value == 'ribbon': self.configure_connection(rf, st) configure_outputs(self, rf) elif value == 'tube': self.configure_connection(tf, st) configure_outputs(self, tf) self.render() def _update_streamlines_fired(self): self.seed.update_poly_data() self.stream_tracer.update() self.render() def _stream_tracer_changed(self, old, new): if old is not None: old.on_trait_change(self.render, remove=True) seed = self.seed if seed is not None: self.configure_source_data(new, seed.poly_data) new.on_trait_change(self.render) mm = self.module_manager if mm is not None: src = mm.source self.configure_connection(new, src) # A default output so there are no pipeline errors. The # update_pipeline call corrects this if needed. self.outputs = [new.output] self.update_pipeline() def _seed_changed(self, old, new): st = self.stream_tracer if st is not None: self.configure_source_data(st, new.poly_data) self._change_components(old, new) def _ribbon_filter_changed(self, old, new): if old is not None: old.on_trait_change(self.render, remove=True) new.on_trait_change(self.render) self._streamline_type_changed(self.streamline_type) def _tube_filter_changed(self, old, new): if old is not None: old.on_trait_change(self.render, remove=True) new.on_trait_change(self.render) self._streamline_type_changed(self.streamline_type) def _actor_changed(self, old, new): new.scene = self.scene new.inputs = [self] self._change_components(old, new)
# object and is active only while the mouse pointer is in the dialog. # * 'info': A temporary, frameless popup dialog that immediately updates the # object and is active only while the dialog is still over the invoking # control. # * 'wizard': A wizard modal dialog box. A wizard contains a sequence of # pages, which can be accessed by clicking **Next** and **Back** buttons. # Changes to attribute values are applied only when the user clicks the # **Finish** button on the last page. AKind = Trait( "live", TraitPrefixList( "panel", "subpanel", "modal", "nonmodal", "livemodal", "live", "popup", "popover", "info", "wizard", ), desc="the kind of view window to create", cols=4, ) # Apply changes handler: OnApply = Callable(desc="the routine to call when modal changes are applied " "or reverted") # Is the dialog window resizable? IsResizable = Bool(False, desc="whether dialog can be resized or not")
class A(HasTraits): foo = Trait("one", TraitPrefixList("zero", "one", "two"))
# the user commits the change. # * 'nonmodal': A nonmodal dialog box that operates on a clone of the object # until the user commits the change # * 'live': A nonmodal dialog box that immediately updates the object. # * 'livemodal': A modal dialog box that immediately updates the object. # * 'popup': A temporary, frameless popup dialog that immediately updates the # object and is active only while the mouse pointer is in the dialog. # * 'info': A temporary, frameless popup dialog that immediately updates the # object and is active only while the dialog is still over the invoking # control. # * 'wizard': A wizard modal dialog box. A wizard contains a sequence of # pages, which can be accessed by clicking **Next** and **Back** buttons. # Changes to attribute values are applied only when the user clicks the # **Finish** button on the last page. AKind = Trait('live', TraitPrefixList( 'panel', 'subpanel', 'modal', 'nonmodal', 'livemodal', 'live', 'popup', 'popover', 'info', 'wizard'), desc='the kind of view window to create', cols=4) # Apply changes handler: OnApply = Callable(desc='the routine to call when modal changes are applied ' 'or reverted') # Is the dialog window resizable? IsResizable = Bool(False, desc='whether dialog can be resized or not') # Is the view scrollable? IsScrollable = Bool(False, desc='whether view should be scrollable or not') # The valid categories of imported elements that can be dragged into the view:
def PrefixList(list_, default_value=None, **kwargs): from traits.api import Trait, TraitPrefixList if default_value is None: default_value = list_[0] return Trait(default_value, TraitPrefixList(list_), **kwargs)
List, Range, Str, Trait, TraitError, TraitPrefixList, TraitType, ) import six # ------------------------------------------------------------------------- # Trait definitions: # ------------------------------------------------------------------------- # Orientation trait: Orientation = Trait("vertical", TraitPrefixList("vertical", "horizontal")) # Styles for user interface elements: EditorStyle = style_trait = Trait("simple", TraitPrefixList("simple", "custom", "text", "readonly"), cols=4) # Group layout trait: Layout = Trait("normal", TraitPrefixList("normal", "split", "tabbed", "flow", "fold")) # Trait for the default object being edited: AnObject = Expression("object") # The default dock style to use:
class SourceWidget(Component): # The version of this class. Used for persistence. __version__ = 0 # The actual poly data source widget. widget = Instance(tvtk.ThreeDWidget, record=True) # Specifies the updation mode of the poly_data attribute. There # are three modes: 1) 'interactive' -- the poly_data attribute is # updated as the widget is interacted with, 2) 'semi-interactive' # -- poly_data attribute is updated when the traits of the widget # change and when the widget interaction is complete, 3) # 'non-interactive' -- poly_data is updated only explicitly at # users request by calling `object.update_poly_data`. update_mode = Trait( 'interactive', TraitPrefixList(['interactive', 'semi-interactive', 'non-interactive']), desc='the speed at which the poly data is updated') # A list of predefined glyph sources that can be used. widget_list = List(tvtk.Object, record=False) # The poly data that the widget manages. poly_data = Instance(tvtk.PolyData, args=()) ######################################## # Private traits. _first = Bool(True) _busy = Bool(False) _unpickling = Bool(False) ######################################## # View related traits. view = View( Group( Item(name='widget', style='custom', resizable=True, editor=InstanceEditor(name='widget_list')), label='Source Widget', show_labels=False, ), resizable=True, ) ###################################################################### # `Base` interface ###################################################################### def __get_pure_state__(self): d = super(SourceWidget, self).__get_pure_state__() for attr in ('poly_data', '_unpickling', '_first', '_busy'): d.pop(attr, None) return d def __set_pure_state__(self, state): self._unpickling = True # First create all the allowed widgets in the widget_list attr. handle_children_state(self.widget_list, state.widget_list) # Now set their state. set_state(self, state, first=['widget_list'], ignore=['*']) # Set the widget attr depending on value saved. m = [x.__class__.__name__ for x in self.widget_list] w_c_name = state.widget.__metadata__['class_name'] w = self.widget = self.widget_list[m.index(w_c_name)] # Set the input. if len(self.inputs) > 0: self.configure_input_data(w, self.inputs[0].outputs[0]) # Fix for the point widget. if w_c_name == 'PointWidget': w.place_widget() # Set state of rest of the attributes ignoring the widget_list. set_state(self, state, ignore=['widget_list']) # Some widgets need some cajoling to get their setup right. w.update_traits() if w_c_name == 'PlaneWidget': w.origin = state.widget.origin w.normal = state.widget.normal w.update_placement() w.get_poly_data(self.poly_data) elif w_c_name == 'SphereWidget': # XXX: This hack is necessary because the sphere widget # does not update its poly data even when its ivars are # set (plus it does not have an update_placement method # which is a bug). So we force this by creating a similar # sphere source and copy its output. s = tvtk.SphereSource(center=w.center, radius=w.radius, theta_resolution=w.theta_resolution, phi_resolution=w.phi_resolution, lat_long_tessellation=True) s.update() self.poly_data.shallow_copy(s.output) else: w.get_poly_data(self.poly_data) self._unpickling = False # Set the widgets trait so that the widget is rendered if needed. self.widgets = [w] ###################################################################### # `Component` interface ###################################################################### def setup_pipeline(self): """Override this method so that it *creates* the tvtk pipeline. This method is invoked when the object is initialized via `__init__`. Note that at the time this method is called, the tvtk data pipeline will *not* yet be setup. So upstream data will not be available. The idea is that you simply create the basic objects and setup those parts of the pipeline not dependent on upstream sources and filters. You should also set the `actors` attribute up at this point. """ # Setup the glyphs. sources = [ tvtk.SphereWidget(theta_resolution=8, phi_resolution=6), tvtk.LineWidget(clamp_to_bounds=False), tvtk.PlaneWidget(), tvtk.PointWidget(outline=False, x_shadows=False, y_shadows=False, z_shadows=False), ] self.widget_list = sources # The 'widgets' trait is set in the '_widget_changed' handler. self.widget = sources[0] for s in sources: self._connect(s) def update_pipeline(self): """Override this method so that it *updates* the tvtk pipeline when data upstream is known to have changed. This method is invoked (automatically) when any of the inputs sends a `pipeline_changed` event. """ if len(self.inputs) == 0: return inp = self.inputs[0].outputs[0] w = self.widget self.configure_input(w, inp) if self._first: w.place_widget() self._first = False # If the dataset is effectively 2D switch to using the line # widget since that works best. b = inp.bounds l = [(b[1] - b[0]), (b[3] - b[2]), (b[5] - b[4])] max_l = max(l) for i, x in enumerate(l): if x / max_l < 1.0e-6: w = self.widget = self.widget_list[1] w.clamp_to_bounds = True w.align = ['z_axis', 'z_axis', 'y_axis'][i] break # Set our output. w.get_poly_data(self.poly_data) self.outputs = [self.poly_data] self.pipeline_changed = True def update_data(self): """Override this method so that it flushes the vtk pipeline if that is necessary. This method is invoked (automatically) when any of the inputs sends a `data_changed` event. """ self.data_changed = True ###################################################################### # `SourceWidget` interface ###################################################################### def update_poly_data(self): self.widget.get_poly_data(self.poly_data) ###################################################################### # Non-public traits. ###################################################################### def _widget_changed(self, value): # If we are being unpickled do nothing. if self._unpickling: return if value not in self.widget_list: classes = [o.__class__ for o in self.widget_list] vc = value.__class__ self._connect(value) if vc in classes: self.widget_list[classes.index(vc)] = value else: self.widget_list.append(value) recorder = self.recorder if recorder is not None: idx = self.widget_list.index(value) name = recorder.get_script_id(self) lhs = '%s.widget' % name rhs = '%s.widget_list[%d]' % (name, idx) recorder.record('%s = %s' % (lhs, rhs)) if len(self.inputs) > 0: configure_input_data(value, self.inputs[0].outputs[0]) value.place_widget() value.on_trait_change(self.render) self.widgets = [value] def _update_mode_changed(self, value): if value in ['interactive', 'semi-interactive']: self.update_poly_data() self.render() def _on_interaction_event(self, obj, event): if (not self._busy) and (self.update_mode == 'interactive'): self._busy = True self.update_poly_data() self._busy = False def _on_widget_trait_changed(self): if (not self._busy) and (self.update_mode != 'non-interactive'): self._busy = True # This render call forces any changes to the trait to be # rendered only then will updating the poly data make # sense. self.render() self.update_poly_data() self._busy = False def _on_alignment_set(self): w = self.widget w.place_widget() w.update_traits() def _connect(self, obj): """Wires up all the event handlers.""" obj.add_observer('InteractionEvent', self._on_interaction_event) if isinstance(obj, tvtk.PlaneWidget): obj.on_trait_change(self._on_alignment_set, 'normal_to_x_axis') obj.on_trait_change(self._on_alignment_set, 'normal_to_y_axis') obj.on_trait_change(self._on_alignment_set, 'normal_to_z_axis') elif isinstance(obj, tvtk.LineWidget): obj.on_trait_change(self._on_alignment_set, 'align') # Setup the widgets colors. fg = (1, 1, 1) if self.scene is not None: fg = self.scene.foreground self._setup_widget_colors(obj, fg) obj.on_trait_change(self._on_widget_trait_changed) obj.on_trait_change(self.render) def _setup_widget_colors(self, widget, color): trait_names = widget.trait_names() props = [ x for x in trait_names if 'property' in x and 'selected' not in x ] sel_props = [ x for x in trait_names if 'property' in x and 'selected' in x ] for p in props: setattr(getattr(widget, p), 'color', color) setattr(getattr(widget, p), 'line_width', 2) for p in sel_props: # Set the selected color to 'red'. setattr(getattr(widget, p), 'color', (1, 0, 0)) setattr(getattr(widget, p), 'line_width', 2) self.render() def _foreground_changed_for_scene(self, old, new): # Change the default color for the actor. for w in self.widget_list: self._setup_widget_colors(w, new) self.render() def _scene_changed(self, old, new): super(SourceWidget, self)._scene_changed(old, new) self._foreground_changed_for_scene(None, new.foreground)
class ModuleManager(Base): """ The module manager node (represented as 'Colors and Legends'). """ # The source object this is connected to. source = Instance(Base) # The modules contained by this manager. children = List(Module, record=True) # The data type to use for the LUTs. Changing this setting will # change the data range and name of the lookup table/legend bar. # If set to 'auto', it automatically looks for cell and point data # with point data being preferred over cell data and chooses the # one available. If set to 'point data' it uses the input point # data for the LUT and if set to 'cell data' it uses the input # cell data. lut_data_mode = Trait( 'auto', TraitPrefixList(LUT_DATA_MODE_TYPES), desc='specify the data type used by the lookup tables', ) # The scalar lookup table manager. scalar_lut_manager = Instance(LUTManager, args=(), record=True) # The vector lookup table manager. vector_lut_manager = Instance(LUTManager, args=(), record=True) # The name of the ModuleManager. name = Str('Colors and legends') # The icon icon = Str('modulemanager.ico') # The human-readable type for this object type = Str(' colors and legends') # Information about what this object can consume. input_info = PipelineInfo(datasets=['any']) # Information about what this object can produce. output_info = PipelineInfo(datasets=['any']) ###################################################################### # `object` interface ###################################################################### def __get_pure_state__(self): d = super(ModuleManager, self).__get_pure_state__() # Source is setup dynamically, don't pickle it. d.pop('source', None) return d def __set_pure_state__(self, state): # Do everything but our kids. set_state(self, state, ignore=['children']) # Setup children. handle_children_state(self.children, state.children) # Now setup the children. set_state(self, state, first=['children'], ignore=['*']) self.update() ###################################################################### # `ModuleManager` interface ###################################################################### def update(self): """Update any internal data. This is invoked when the source changes or when there are pipeline/data changes upstream. """ if len(self.source.outputs) == 0: return self._setup_scalar_data() self._setup_vector_data() ###################################################################### # `Base` interface ###################################################################### def start(self): """This is invoked when this object is added to the mayavi pipeline. """ # Do nothing if we are already running. if self.running: return # Setup event handlers. self._setup_event_handlers() # Start all our children. for obj in self.children: obj.start() for obj in (self.scalar_lut_manager, self.vector_lut_manager): obj.start() # Call parent method to set the running state. super(ModuleManager, self).start() def stop(self): """Invoked when this object is removed from the mayavi pipeline. """ if not self.running: return # Teardown event handlers. self._teardown_event_handlers() # Stop all our children. for obj in self.children: obj.stop() for obj in (self.scalar_lut_manager, self.vector_lut_manager): obj.stop() # Call parent method to set the running state. super(ModuleManager, self).stop() def add_child(self, child): """This method intelligently adds a child to this object in the MayaVi pipeline. """ if isinstance(child, Module): self.children.append(child) else: # Ask our source to deal with it. self.source.add_child(child) def remove_child(self, child): """Remove specified child from our children. """ self.children.remove(child) ###################################################################### # `TreeNodeObject` interface ###################################################################### def tno_can_add(self, node, add_object): """ Returns whether a given object is droppable on the node. """ try: if issubclass(add_object, Module): return True except TypeError: if isinstance(add_object, Module): return True return False def tno_drop_object(self, node, dropped_object): """ Returns a droppable version of a specified object. """ if isinstance(dropped_object, Module): return dropped_object ###################################################################### # Non-public interface ###################################################################### def _children_changed(self, old, new): self._handle_children(old, new) def _children_items_changed(self, list_event): self._handle_children(list_event.removed, list_event.added) def _handle_children(self, removed, added): # Stop all the old children. for obj in removed: obj.stop() # Setup and start the new ones. for obj in added: obj.trait_set(module_manager=self, scene=self.scene, parent=self) if self.running: # It makes sense to start children only if we are running. # If not, the children will be started when we start. try: obj.start() except: exception() def _source_changed(self): self.output_info.copy_traits(self.source.output_info) self.update() def _setup_event_handlers(self): src = self.source src.on_trait_event(self.update, 'pipeline_changed') src.on_trait_event(self.update, 'data_changed') def _teardown_event_handlers(self): src = self.source src.on_trait_event(self.update, 'pipeline_changed', remove=True) src.on_trait_event(self.update, 'data_changed', remove=True) def _scene_changed(self, value): for obj in self.children: obj.scene = value for obj in (self.scalar_lut_manager, self.vector_lut_manager): obj.scene = value def _lut_data_mode_changed(self, value): self.update() def _setup_scalar_data(self): """Computes the scalar range and an appropriate name for the lookup table.""" input = get_output(self.source.outputs[0]) ps = input.point_data.scalars cs = input.cell_data.scalars data_attr = DataAttributes(name='No scalars') point_data_attr = DataAttributes(name='No scalars') point_data_attr.compute_scalar(ps, 'point') cell_data_attr = DataAttributes(name='No scalars') cell_data_attr.compute_scalar(cs, 'cell') if self.lut_data_mode == 'auto': if len(point_data_attr.range) > 0: data_attr.copy_traits(point_data_attr) elif len(cell_data_attr.range) > 0: data_attr.copy_traits(cell_data_attr) elif self.lut_data_mode == 'point data': data_attr.copy_traits(point_data_attr) elif self.lut_data_mode == 'cell data': data_attr.copy_traits(cell_data_attr) data_attr.config_lut(self.scalar_lut_manager) def _setup_vector_data(self): input = get_output(self.source.outputs[0]) pv = input.point_data.vectors cv = input.cell_data.vectors data_attr = DataAttributes(name='No vectors') point_data_attr = DataAttributes(name='No vectors') point_data_attr.compute_vector(pv, 'point') cell_data_attr = DataAttributes(name='No vectors') cell_data_attr.compute_vector(cv, 'cell') if self.lut_data_mode == 'auto': if len(point_data_attr.range) > 0: data_attr.copy_traits(point_data_attr) elif len(cell_data_attr.range) > 0: data_attr.copy_traits(cell_data_attr) elif self.lut_data_mode == 'point data': data_attr.copy_traits(point_data_attr) elif self.lut_data_mode == 'cell data': data_attr.copy_traits(cell_data_attr) data_attr.config_lut(self.vector_lut_manager) def _visible_changed(self, value): for c in self.children: c.visible = value self.scalar_lut_manager.visible = value self.vector_lut_manager.visible = value super(ModuleManager, self)._visible_changed(value) def _menu_helper_default(self): from mayavi.core.traits_menu import ModuleMenuHelper return ModuleMenuHelper(object=self)
from .enable_traits import spacing_trait, padding_trait, margin_trait,\ border_size_trait#, image_trait from .enable_traits import position_trait, font_trait, engraving_trait from .radio_group import RadioStyle, RadioGroup #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- empty_text_info = (0, 0, 0, 0) LEFT_OR_RIGHT = LEFT | RIGHT TOP_OR_BOTTOM = TOP | BOTTOM orientation_trait = Trait('text', TraitPrefixList(['text', 'component'])) class LabelTraits(HasTraits): text = Str font = font_trait text_position = position_trait("left") color = ColorTrait("black") shadow_color = ColorTrait("white") style = engraving_trait #image = image_trait image_position = position_trait("left") image_orientation = orientation_trait
class PrefixListTrait(HasTraits): value = Trait("one", TraitPrefixList("one", "two", "three"))
# Font trait: font_trait = KivaFont(default_font_name) # Bounds trait bounds_trait = CList([0.0, 0.0]) # (w,h) coordinate_trait = CList([0.0, 0.0]) # (x,y) #bounds_trait = Trait((0.0, 0.0, 20.0, 20.0), valid_bounds, editor=bounds_editor) # Component minimum size trait # PZW: Make these just floats, or maybe remove them altogether. ComponentMinSize = Range(0.0, 99999.0) ComponentMaxSize = ComponentMinSize(99999.0) # Pointer shape trait: Pointer = Trait('arrow', TraitPrefixList(pointer_shapes)) # Cursor style trait: cursor_style_trait = Trait('default', TraitPrefixMap(cursor_styles)) spacing_trait = Range(0, 63, value=4) padding_trait = Range(0, 63, value=4) margin_trait = Range(0, 63) border_size_trait = Range(0, 8, editor=border_size_editor) # Time interval trait: TimeInterval = Trait(None, None, Range(0.0, 3600.0)) # Stretch traits: Stretch = Range(0.0, 1.0, value=1.0) NoStretch = Stretch(0.0)
class SeedStreamline(Streamline): """ This class is a modification of the mayavi Streamline class that accepts an array of seed points as a input rather than a widget. Examples -------- Create a new Streamline instance and add it to a pipeline >>> from solarbextrapolation.mayavi_seed_streamlines import SeedStreamline >>> import numpy as np >>> seeds = [[1, 2, 5], [3, 4, 5]] >>> field_lines = SeedStreamline(seed_points = np.array(seeds)) #doctest: +SKIP >>> myvectorfield.add_child(field_lines) #doctest: +SKIP """ seed_points = Array(allow_none=False) seed = Instance(tvtk.PolyData, args=()) update_mode = Trait( 'interactive', TraitPrefixList(['interactive', 'semi-interactive', 'non-interactive']), desc='the speed at which the poly data is updated') def setup_pipeline(self): """Override this method so that it *creates* the tvtk pipeline. This method is invoked when the object is initialized via `__init__`. Note that at the time this method is called, the tvtk data pipeline will *not* yet be setup. So upstream data will not be available. The idea is that you simply create the basic objects and setup those parts of the pipeline not dependent on upstream sources and filters. You should also set the `actors` attribute up at this point. """ # Create and setup the default objects. self.seed = tvtk.PolyData(points=self.seed_points) self.stream_tracer = tvtk.StreamTracer( maximum_propagation=2000, integration_direction='backward', compute_vorticity=False, integrator_type='runge_kutta4', ) self.ribbon_filter = tvtk.RibbonFilter() self.tube_filter = tvtk.TubeFilter() self.actor = mayavi.components.actor.Actor() # Setup the actor suitably for this module. self.actor.property.line_width = 2.0 def update_pipeline(self): """Override this method so that it *updates* the tvtk pipeline when data upstream is known to have changed. This method is invoked (automatically) when any of the inputs sends a `pipeline_changed` event. """ mm = self.module_manager if mm is None: return src = mm.source self.stream_tracer.input = src.outputs[0] #self.seed.inputs = [src] # Setup the radius/width of the tube/ribbon filters based on # given input. if self._first: b = src.outputs[0].bounds l = [(b[1] - b[0]), (b[3] - b[2]), (b[5] - b[4])] length = np.sqrt(l[0] * l[0] + l[1] * l[1] + l[2] * l[2]) self.ribbon_filter.width = length * 0.0075 self.tube_filter.radius = length * 0.0075 self._first = False self._streamline_type_changed(self.streamline_type) # Set the LUT for the mapper. self.actor.set_lut(mm.scalar_lut_manager.lut) self.pipeline_changed = True def _seed_points_changed(self, old, new): self.seed = tvtk.PolyData(points=self.seed_points) def _stream_tracer_changed(self, old, new): if old is not None: old.on_trait_change(self.render, remove=True) seed = self.seed if seed is not None: new.source = seed new.on_trait_change(self.render) mm = self.module_manager if mm is not None: new.input = mm.source.outputs[0] # A default output so there are no pipeline errors. The # update_pipeline call corrects this if needed. self.outputs = [new.output] self.update_pipeline() def _seed_changed(self, old, new): st = self.stream_tracer if st is not None: st.source = new #.poly_data
class GlyphSource(Component): # The version of this class. Used for persistence. __version__ = 1 # Glyph position. This can be one of ['head', 'tail', 'center'], # and indicates the position of the glyph with respect to the # input point data. Please note that this will work correctly # only if you do not mess with the source glyph's basic size. For # example if you use a ConeSource and set its height != 1, then the # 'head' and 'tail' options will not work correctly. glyph_position = Trait('center', TraitPrefixList(['head', 'tail', 'center']), desc='position of glyph w.r.t. data point') # The Source to use for the glyph. This is chosen from # `self._glyph_list` or `self.glyph_dict`. glyph_source = Instance(tvtk.Object, allow_none=False, record=True) # A dict of glyphs to use. glyph_dict = Dict(desc='the glyph sources to select from', record=False) # A list of predefined glyph sources that can be used. glyph_list = Property(List(tvtk.Object), record=False) ######################################## # Private traits. # The transformation to use to place glyph appropriately. _trfm = Instance(tvtk.TransformFilter, args=()) # Used for optimization. _updating = Bool(False) ######################################## # View related traits. view = View(Group( Group(Item(name='glyph_position')), Group(Item( name='glyph_source', style='custom', resizable=True, editor=InstanceEditor(name='glyph_list'), ), label='Glyph Source', show_labels=False)), resizable=True) ###################################################################### # `Base` interface ###################################################################### def __get_pure_state__(self): d = super(GlyphSource, self).__get_pure_state__() for attr in ('_updating', 'glyph_list'): d.pop(attr, None) return d def __set_pure_state__(self, state): if 'glyph_dict' in state: # Set their state. set_state(self, state, first=['glyph_dict'], ignore=['*']) ignore = ['glyph_dict'] else: # Set the dict state using the persisted list. gd = self.glyph_dict gl = self.glyph_list handle_children_state(gl, state.glyph_list) for g, gs in zip(gl, state.glyph_list): name = camel2enthought(g.__class__.__name__) if name not in gd: gd[name] = g # Set the glyph source's state. set_state(g, gs) ignore = ['glyph_list'] g_name = state.glyph_source.__metadata__['class_name'] name = camel2enthought(g_name) # Set the correct glyph_source. self.glyph_source = self.glyph_dict[name] set_state(self, state, ignore=ignore) ###################################################################### # `Component` interface ###################################################################### def setup_pipeline(self): """Override this method so that it *creates* the tvtk pipeline. This method is invoked when the object is initialized via `__init__`. Note that at the time this method is called, the tvtk data pipeline will *not* yet be setup. So upstream data will not be available. The idea is that you simply create the basic objects and setup those parts of the pipeline not dependent on upstream sources and filters. You should also set the `actors` attribute up at this point. """ self._trfm.transform = tvtk.Transform() # Setup the glyphs. self.glyph_source = self.glyph_dict['glyph_source2d'] def update_pipeline(self): """Override this method so that it *updates* the tvtk pipeline when data upstream is known to have changed. This method is invoked (automatically) when any of the inputs sends a `pipeline_changed` event. """ self._glyph_position_changed(self.glyph_position) self.pipeline_changed = True def update_data(self): """Override this method so that it flushes the vtk pipeline if that is necessary. This method is invoked (automatically) when any of the inputs sends a `data_changed` event. """ self.data_changed = True def render(self): if not self._updating: super(GlyphSource, self).render() ###################################################################### # Non-public methods. ###################################################################### def _glyph_source_changed(self, value): if self._updating: return gd = self.glyph_dict value_cls = camel2enthought(value.__class__.__name__) if value not in gd.values(): gd[value_cls] = value # Now change the glyph's source trait. self._updating = True recorder = self.recorder if recorder is not None: name = recorder.get_script_id(self) lhs = '%s.glyph_source' % name rhs = '%s.glyph_dict[%r]' % (name, value_cls) recorder.record('%s = %s' % (lhs, rhs)) name = value.__class__.__name__ if name == 'GlyphSource2D': self.outputs = [value] else: self.configure_input(self._trfm, value) self.outputs = [self._trfm] value.on_trait_change(self.render) self._updating = False # Now update the glyph position since the transformation might # be different. self._glyph_position_changed(self.glyph_position) def _glyph_position_changed(self, value): if self._updating: return self._updating = True tr = self._trfm.transform tr.identity() g = self.glyph_source name = g.__class__.__name__ # Compute transformation factor if name == 'CubeSource': tr_factor = g.x_length / 2.0 elif name == 'CylinderSource': tr_factor = -g.height / 2.0 elif name == 'ConeSource': tr_factor = g.height / 2.0 elif name == 'SphereSource': tr_factor = g.radius else: tr_factor = 1. # Translate the glyph if value == 'tail': if name == 'GlyphSource2D': g.center = 0.5, 0.0, 0.0 elif name == 'ArrowSource': pass elif name == 'CylinderSource': g.center = 0, tr_factor, 0.0 elif hasattr(g, 'center'): g.center = tr_factor, 0.0, 0.0 elif value == 'head': if name == 'GlyphSource2D': g.center = -0.5, 0.0, 0.0 elif name == 'ArrowSource': tr.translate(-1, 0, 0) elif name == 'CylinderSource': g.center = 0, -tr_factor, 0.0 else: g.center = -tr_factor, 0.0, 0.0 else: if name == 'ArrowSource': tr.translate(-0.5, 0, 0) elif name != 'Axes': g.center = 0.0, 0.0, 0.0 if name == 'CylinderSource': tr.rotate_z(90) self._updating = False self.render() def _get_glyph_list(self): # Return the glyph list as per the original order in earlier # implementation. order = [ 'glyph_source2d', 'arrow_source', 'cone_source', 'cylinder_source', 'sphere_source', 'cube_source', 'axes' ] gd = self.glyph_dict for key in gd: if key not in order: order.append(key) return [gd[key] for key in order] def _glyph_dict_default(self): g = { 'glyph_source2d': tvtk.GlyphSource2D(glyph_type='arrow', filled=False), 'arrow_source': tvtk.ArrowSource(), 'cone_source': tvtk.ConeSource(height=1.0, radius=0.2, resolution=15), 'cylinder_source': tvtk.CylinderSource(height=1.0, radius=0.15, resolution=10), 'sphere_source': tvtk.SphereSource(), 'cube_source': tvtk.CubeSource(), 'axes': tvtk.Axes(symmetric=1) } return g
def __init__(self, list_, **kwargs): super().__init__(kwargs['default_value'], TraitPrefixList(list_), **kwargs)