示例#1
0
class Axes(AxesLikeModuleFactory):
    """ Creates axes for the current (or given) object."""

    xlabel = String(None,
                    adapts='axes.x_label',
                    help='the label of the x axis')

    ylabel = String(None,
                    adapts='axes.y_label',
                    help='the label of the y axis')

    zlabel = String(None,
                    adapts='axes.z_label',
                    help='the label of the z axis')

    nb_labels = Range(0,
                      50,
                      2,
                      adapts='axes.number_of_labels',
                      desc='The number of labels along each direction')

    ranges = Trait(
        None,
        None,
        CArray(shape=(6, )),
        help="""[xmin, xmax, ymin, ymax, zmin, zmax]
                            Ranges of the labels displayed on the axes.
                            Default is the object's extents.""",
    )

    x_axis_visibility = true(
        adapts='axes.x_axis_visibility',
        help="Whether or not the x axis is visible (boolean)")

    y_axis_visibility = true(
        adapts='axes.y_axis_visibility',
        help="Whether or not the y axis is visible (boolean)")

    z_axis_visibility = true(
        adapts='axes.z_axis_visibility',
        help="Whether or not the z axis is visible (boolean)")

    _target = Instance(modules.Axes, ())

    def _extent_changed(self):
        """ Code to modify the extents for
        """
        axes = self._target
        axes.axes.use_data_bounds = False
        axes.axes.bounds = self.extent
        if self.ranges is None:
            axes.axes.ranges = \
                axes.module_manager.source.outputs[0].bounds

    def _ranges_changed(self):
        if self.ranges is not None:
            self._target.axes.ranges = self.ranges
            self._target.axes.use_ranges = True
示例#2
0
class Text3D(ModuleFactory):
    """ Positions text at a 3D location in the scene.

        **Function signature**::

            text3d(x, y, z, text, ...)

        x, y, and z are the position of the origin of the text. The
        text is positionned in 3D, in figure coordinnates.
        """

    _target = Instance(modules.Text3D, ())

    scale = Either(CFloat(1),
                   CArray(shape=(3, )),
                   help="""The scale of the text, in figure units.
                                Either a float, or 3-tuple of floats.""")

    orientation = CArray(shape=(3, ),
                         adapts='orientation',
                         desc="""the angles giving the orientation of the
                        text. If the text is oriented to the camera,
                        these angles are referenced to the axis of the
                        camera. If not, these angles are referenced to
                        the z axis.""")

    orient_to_camera = true(adapts='orient_to_camera',
                            desc="""if the text is kept oriented to the
                        camera, or is pointing in a specific direction,
                        regardless of the camera position.""")

    def __init__(self, x, y, z, text, **kwargs):
        """ Override init as for different positional arguments."""
        if not 'scale' in kwargs:
            kwargs['scale'] = 1
        super(Text3D, self).__init__(None, **kwargs)
        self._target.text = text
        self._target.position = (x, y, z)

    def _scale_changed(self):
        scale = self.scale
        if operator.isNumberType(scale):
            scale = scale * np.ones((3, ))
        self._target.scale = scale
示例#3
0
class DataModuleFactory(ModuleFactory):
    """ Base class for all the module factories operating on data (ie not
        text and outline) """

    reset_zoom = true(help="""Reset the zoom to accomodate the data newly
                        added to the scene. Defaults to True.""")

    extent = CArray(shape=(6,),
                    help="""[xmin, xmax, ymin, ymax, zmin, zmax]
                            Default is the x, y, z arrays extent. Use
                            this to change the extent of the object
                            created.""", )

    def _extent_changed(self):
        tools.set_extent(self._target, self.extent)

    transparent = false(help="""make the opacity of the actor depend on the
                               scalar.""")

    def _transparent_changed(self):
        if self.transparent:
            data_range = \
                self._target.module_manager.scalar_lut_manager.data_range
            self._target.module_manager.scalar_lut_manager.lut.alpha_range = \
                                                                (0.2, 0.8)
            data_range = ( numpy.mean(data_range)
                            + 0.4 * ( data_range.max() - data_range.min())
                                * numpy.array([-1, 1]))
            self._target.module_manager.scalar_lut_manager.data_range = \
                data_range

    colormap = Trait('blue-red', lut_mode_list(),
                        help="""type of colormap to use.""")

    def _colormap_changed(self):
        colormap = self.colormap
        if colormap[-2:] == "_r":
            colormap = colormap[:-2]
            self._target.module_manager.scalar_lut_manager.reverse_lut = True
            self._target.module_manager.vector_lut_manager.reverse_lut = True
        self._target.module_manager.scalar_lut_manager.lut_mode = colormap
        self._target.module_manager.vector_lut_manager.lut_mode = colormap


    vmin = Trait(None, None, CFloat,
                    help="""vmin is used to scale the colormap.
                            If None, the min of the data will be used""")

    vmax = Trait(None, None, CFloat,
                    help="""vmax is used to scale the colormap.
                            If None, the max of the data will be used""")

    def _vmin_changed(self):
        if self.vmin == None and self.vmax == None:
            self._target.module_manager.scalar_lut_manager.use_default_range\
                    = True
            return

        self._target.module_manager.scalar_lut_manager.use_default_range \
                    = False
        vmin, vmax = \
                self._target.module_manager.scalar_lut_manager.data_range
        if self.vmin is not None:
            vmin = self.vmin
        if self.vmax is not None:
            vmax = self.vmax
        self._target.module_manager.scalar_lut_manager.data_range = \
                        (vmin, vmax)

    _vmax_changed = _vmin_changed

    def __init__(self, *args, **kwargs):
        super(DataModuleFactory, self).__init__(*args, **kwargs)
        # We are adding data to the scene, reset the zoom:
        scene = self._scene.scene
        if scene is not None and self.reset_zoom:
            scene.reset_zoom()
示例#4
0
class BarChart(Pipeline):
    """
    Plots vertical glyphs (like bars) scaled vertical, to do
    histogram-like plots.

    This functions accepts a wide variety of inputs, with positions given
    in 2-D or in 3-D.

    **Function signatures**::

        barchart(s, ...)
        barchart(x, y, s, ...)
        barchart(x, y, f, ...)
        barchart(x, y, z, s, ...)
        barchart(x, y, z, f, ...)

    If only one positional argument is passed, it can be a 1-D, 2-D, or 3-D
    array giving the length of the vectors. The positions of the data
    points are deducted from the indices of array, and an
    uniformly-spaced data set is created.

    If 3 positional arguments (x, y, s) are passed the last one must be
    an array s, or a callable, f, that returns an array. x and y give the
    2D coordinates of positions corresponding to the s values.

    If 4 positional arguments (x, y, z, s) are passed, the 3 first are
    arrays giving the 3D coordinates of the data points, and the last one
    is an array s, or a callable, f, that returns an array giving the
    data value.
    """

    _source_function = Callable(vertical_vectors_source)

    _pipeline = [
        VectorsFactory,
    ]

    mode = Trait('cube',
                 bar_mode_dict,
                 desc='The glyph used to represent the bars.')

    lateral_scale = CFloat(0.9,
                           desc='The lateral scale of the glyph, '
                           'in units of the distance between nearest points')

    auto_scale = true(desc='whether to compute automatically the '
                      'lateral scaling of the glyphs. This might be '
                      'computationally expensive.')

    def __call_internal__(self, *args, **kwargs):
        """ Override the call to be able to scale automatically the axis.
        """
        g = Pipeline.__call_internal__(self, *args, **kwargs)
        gs = g.glyph.glyph_source
        # Use a cube source for glyphs.
        if not 'mode' in kwargs:
            gs.glyph_source = gs.glyph_dict['cube_source']
        # Position the glyph tail on the point.
        gs.glyph_position = 'tail'
        gs.glyph_source.center = (0.0, 0.0, 0.5)
        g.glyph.glyph.orient = False
        if not 'color' in kwargs:
            g.glyph.color_mode = 'color_by_scalar'
        if not 'scale_mode' in kwargs:
            g.glyph.scale_mode = 'scale_by_vector_components'
        g.glyph.glyph.clamping = False
        # The auto-scaling code. It involves finding the minimum
        # distance between points, which can be very expensive. We
        # shortcut this calculation for structured data
        if len(args) == 1 or self.auto_scale:
            min_axis_distance = 1
        else:
            x, y, z = g.mlab_source.x, g.mlab_source.y, g.mlab_source.z
            min_axis_distance = \
                    tools._min_axis_distance(x, y, z)
        scale_factor = g.glyph.glyph.scale_factor * min_axis_distance
        lateral_scale = kwargs.pop('lateral_scale', self.lateral_scale)
        try:
            g.glyph.glyph_source.glyph_source.y_length = \
                    lateral_scale / (scale_factor)
            g.glyph.glyph_source.glyph_source.x_length = \
                    lateral_scale / (scale_factor)
        except TraitError:
            " Not all types of glyphs have controlable y_length and x_length"

        return g
示例#5
0
class Picker(HasTraits):
    """This module creates a 'Picker' that can interactively select a
    point and/or a cell in the data.  It also can use a world point
    picker (i.e. a generic point in space) and will probe for the data
    at that point.

    The Picker is usually called via a callback from the GUI
    interactor window.  After performing a pick on the VTK scene, a
    Picker object creates a `PickedData` object and passes it on to
    the pick_handler trait for further handling.
    """

    # The version of this class.  Used for persistence.
    __version__ = 0

    # Speficifies the pick type.  The 'point_picker' and 'cell_picker'
    # options are self-explanatory.  The 'world_picker' picks a point
    # using a WorldPointPicker and additionally uses a ProbeFilter to
    # probe the data at the picked point.
    pick_type = Trait('point',
                      TraitRevPrefixMap({
                          'point_picker': 1,
                          'cell_picker': 2,
                          'world_picker': 3
                      }),
                      desc='specifies the picker type to use')

    # The pick_handler.  Set this to your own subclass if you want do
    # do something different from the default.
    pick_handler = Trait(DefaultPickHandler(), Instance(PickHandler))

    # Picking tolerance.
    tolerance = Range(0.0, 0.25, 0.025)

    # show the GUI on pick ?
    show_gui = true(desc="whether to show the picker GUI on pick")

    # Raise the GUI on pick ?
    auto_raise = true(desc="whether to raise the picker GUI on pick")

    default_view = View(Group(
        Group(Item(name='pick_type'), Item(name='tolerance'),
              show_border=True),
        Group(Item(name='pick_handler', style='custom'),
              show_border=True,
              show_labels=False),
        Group(Item(name='show_gui'), Item(name='auto_raise'),
              show_border=True),
    ),
                        resizable=True,
                        buttons=['OK'],
                        handler=CloseHandler())

    #################################################################
    # `object` interface.
    #################################################################
    def __init__(self, renwin, **traits):
        super(Picker, self).__init__(**traits)

        self.renwin = renwin
        self.pointpicker = tvtk.PointPicker()
        self.cellpicker = tvtk.CellPicker()
        self.worldpicker = tvtk.WorldPointPicker()
        self.probe_data = tvtk.PolyData()
        self._tolerance_changed(self.tolerance)

        # Use a set of axis to show the picked point.
        self.p_source = tvtk.Axes()
        self.p_mapper = tvtk.PolyDataMapper()
        self.p_actor = tvtk.Actor()
        self.p_source.symmetric = 1
        self.p_actor.pickable = 0
        self.p_actor.visibility = 0
        prop = self.p_actor.property
        prop.line_width = 2
        prop.ambient = 1.0
        prop.diffuse = 0.0
        self.p_mapper.input = self.p_source.output
        self.p_actor.mapper = self.p_mapper

        self.probe_data.points = [[0.0, 0.0, 0.0]]

        self.ui = None

    def __get_pure_state__(self):
        d = self.__dict__.copy()
        for x in [
                'renwin', 'ui', 'pick_handler', '__sync_trait__',
                '__traits_listener__'
        ]:
            d.pop(x, None)
        return d

    def __getstate__(self):
        return state_pickler.dumps(self)

    def __setstate__(self, str_state):
        # This method is unnecessary since this object will almost
        # never be pickled by itself and only via the scene, therefore
        # __init__ will be called when the scene is constructed.
        # However, setstate is defined just for completeness.
        state_pickler.set_state(self, state_pickler.loads_state(str_state))

    #################################################################
    # `Picker` interface.
    #################################################################
    def pick(self, x, y):
        """Calls one of the current pickers and then passes the
        obtained data to the `self.pick_handler` object's
        `handle_pick` method.

        Parameters
        ----------

        - x : X position of the mouse in the window.

        - y : Y position of the mouse in the window.

          Note that the origin of x, y must be at the left bottom
          corner of the window.  Thus, for most GUI toolkits, y must
          be flipped appropriately such that y=0 is the bottom of the
          window.
        """

        data = None
        if self.pick_type_ == 1:
            data = self.pick_point(x, y)
        elif self.pick_type_ == 2:
            data = self.pick_cell(x, y)
        elif self.pick_type_ == 3:
            data = self.pick_world(x, y)

        self.pick_handler.handle_pick(data)
        if self.show_gui:
            self._setup_gui()

    def pick_point(self, x, y):
        """ Picks the nearest point. Returns a `PickedData` instance."""
        self.pointpicker.pick((float(x), float(y), 0.0), self.renwin.renderer)

        pp = self.pointpicker
        id = pp.point_id
        picked_data = PickedData()
        coord = pp.pick_position
        picked_data.coordinate = coord

        if id > -1:
            data = pp.mapper.input.point_data
            bounds = pp.mapper.input.bounds

            picked_data.valid = 1
            picked_data.point_id = id
            picked_data.data = data

            self._update_actor(coord, bounds)
        else:
            self.p_actor.visibility = 0

        self.renwin.render()
        return picked_data

    def pick_cell(self, x, y):
        """ Picks the nearest cell. Returns a `PickedData` instance."""
        try:
            self.cellpicker.pick(float(x), float(y), 0.0, self.renwin.renderer)
        except TypeError:
            # On old versions of VTK, the signature used to be different
            self.cellpicker.pick((float(x), float(y), 0.0),
                                 self.renwin.renderer)

        cp = self.cellpicker
        id = cp.cell_id
        picked_data = PickedData()
        coord = cp.pick_position
        picked_data.coordinate = coord

        if id > -1:
            data = cp.mapper.input.cell_data
            bounds = cp.mapper.input.bounds

            picked_data.valid = 1
            picked_data.cell_id = id
            picked_data.data = data

            self._update_actor(coord, bounds)
        else:
            self.p_actor.visibility = 0

        self.renwin.render()
        return picked_data

    def pick_world(self, x, y):
        """ Picks a world point and probes for data there. Returns a
        `PickedData` instance."""
        self.worldpicker.pick((float(x), float(y), 0.0), self.renwin.renderer)

        # Use the cell picker to get the data that needs to be probed.
        try:
            self.cellpicker.pick((float(x), float(y), 0.0),
                                 self.renwin.renderer)
        except TypeError:
            self.cellpicker.pick(float(x), float(y), 0.0, self.renwin.renderer)

        wp = self.worldpicker
        cp = self.cellpicker
        coord = wp.pick_position
        self.probe_data.points = [list(coord)]
        picked_data = PickedData()
        picked_data.coordinate = coord

        if cp.mapper:
            data = get_last_input(cp.mapper.input)
            # Need to create the probe each time because otherwise it
            # does not seem to work properly.
            probe = tvtk.ProbeFilter()
            probe.source = data
            probe.input = self.probe_data
            probe.update()
            data = probe.output.point_data
            bounds = cp.mapper.input.bounds

            picked_data.valid = 1
            picked_data.world_pick = 1
            picked_data.point_id = 0
            picked_data.data = data

            self._update_actor(coord, bounds)
        else:
            self.p_actor.visibility = 0

        self.renwin.render()
        return picked_data

    def on_ui_close(self):
        """This method makes the picker actor invisible when the GUI
        dialog is closed."""
        self.p_actor.visibility = 0
        self.renwin.renderer.remove_actor(self.p_actor)
        self.ui = None

    #################################################################
    # Non-public interface.
    #################################################################
    def _tolerance_changed(self, val):
        """ Trait handler for the tolerance trait."""
        self.pointpicker.tolerance = val
        self.cellpicker.tolerance = val

    def _update_actor(self, coordinate, bounds):
        """Updates the actor by setting its position and scale."""
        dx = 0.3 * (bounds[1] - bounds[0])
        dy = 0.3 * (bounds[3] - bounds[2])
        dz = 0.3 * (bounds[5] - bounds[4])
        scale = max(dx, dy, dz)
        self.p_source.origin = coordinate
        self.p_source.scale_factor = scale
        self.p_actor.visibility = 1

    def _setup_gui(self):
        """Pops up the GUI control widget."""
        # Popup the GUI control.
        if self.ui is None:
            self.ui = self.edit_traits()
            # Note that we add actors to the renderer rather than to
            # renwin to prevent event notifications on actor
            # additions.
            self.renwin.renderer.add_actor(self.p_actor)
        elif self.auto_raise:
            try:
                self.ui.control.Raise()
            except AttributeError:
                pass