Пример #1
0
class Converter ( HasStrictTraits ):
    
    # Trait definitions:
    input_amount  = CFloat( 12.0,    desc = "the input quantity" )
    input_units   = Units( 'inches', desc = "the input quantity's units" )
    output_amount = Property( depends_on = [ 'input_amount', 'input_units',
                                             'output_units' ],
                              desc = "the output quantity" ) 
    output_units  = Units( 'feet',   desc = "the output quantity's units" )

    # User interface views:
    traits_view = View( 
        VGroup( 
            HGroup( 
                Item( 'input_amount', springy = True ),
                Item( 'input_units', show_label = False ),
                label       = 'Input',
                show_border = True
            ),
            HGroup(
                Item( 'output_amount', style = 'readonly', springy = True ),
                Item( 'output_units',  show_label = False ),
                label       = 'Output',
                show_border = True
            ),
            help = ViewHelp
        ),
        title   = 'Units Converter',
        buttons = [ 'Undo', 'OK', 'Help' ]
    )
    
    # Property implementations
    def _get_output_amount ( self ):
        return ((self.input_amount * self.input_units_) / self.output_units_)
Пример #2
0
class WarpScalarFactory(PipeFactory):
    """Applies the WarpScalar mayavi filter to the given VTK object."""

    _target = Instance(filters.WarpScalar, ())

    warp_scale = CFloat(1.0,
                        adapts="filter.scale_factor",
                        help="scale of the warp scalar")
Пример #3
0
class Title(SingletonModuleFactory):
    """Creates a title for the figure.

    **Function signature**:: 
    
        title(text, ...)

    """

    size = CFloat(1, help="the size of the title")

    height = CFloat(0.8,
                    adapts='y_position',
                    help="""height of the title, in portion of the 
                                 figure height""")

    def _size_changed(self):
        self._target.width = min(0.05 * self.size * len(self._text), 1)
        self._target.x_position = 0.5 * (1 - self._target.width)

    _target = Instance(modules.Text)

    def __target_default(self):
        """ This is called only if no existing title is found."""
        width = min(0.05 * self.size * len(self._text), 1)
        text = modules.Text(
            text=self._text,
            y_position=self.height,
            x_position=0.5 * (1 - width),
        )
        text.width = width
        return text

    def __init__(self, text, **kwargs):
        self._text = text  # This will be used by _size_changed
        if not 'name' in kwargs:
            # The name is used as au unique marker to identify the
            # title. We need to set it ASAP.
            self.name = kwargs['name'] = 'Title'
        super(Title, self).__init__(**kwargs)
        self._target.text = self._text
        # We need to set position after Text is initiated, as text will
        # override these positions
        self._target.y_position = self.height
        self._size_changed()
Пример #4
0
class TubeFactory(PipeFactory):
    """Applies the Tube mayavi filter to the given VTK object."""

    _target = Instance(filters.Tube, ())

    tube_sides = CInt(6,
                      adapts='filter.number_of_sides',
                      desc="""number of sides of the tubes used to 
                        represent the lines.""")

    tube_radius = CFloat(0.05,
                         adapts='filter.radius',
                         desc="""radius of the tubes used to represent the
                        lines.""")
Пример #5
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
Пример #6
0
class Text(ModuleFactory):
    """ Adds a text on the figure.
    
        **Function signature**::
        
            text(x, y, text, ...) 

        x, and y are the position of the origin of the text. If no z
        keyword argument is given, x and y are the 2D projection of the 
        figure, they belong to [0, 1]. If a z keyword  argument is given, the 
        text is positionned in 3D, in figure coordinnates.
        """

    width = Trait(None,
                  None,
                  CFloat,
                  adapts='width',
                  help="""width of the text.""")

    z = Trait(None,
              None,
              CFloat,
              help="""Optional z position. When specified, the
                        text is positioned in 3D""")

    _target = Instance(modules.Text, ())

    opacity = CFloat(1,
                     adapts="property.opacity",
                     help="""The opacity of the text.""")

    def __init__(self, x, y, text, **kwargs):
        """ Override init as for different positional arguments."""
        if 'z' in kwargs and kwargs['z'] is not None:
            self._target.z_position = kwargs['z']
            self._target.position_in_3d = True
        elif not (x < 1. and x > 0. and y > 0. and y < 1.):
            raise ValueError('Text positions should be in [0, 1] if no z'
                             'position is given')
        super(Text, self).__init__(None, **kwargs)
        self._target.text = text
        self._target.x_position = x
        self._target.y_position = y
Пример #7
0
class CustomBarChart(Pipeline):
	"""
	2012.2.21
		custom version of BarChart. It has two more keyword arguments, x_scale, y_scale,
			which is in charge of the lateral_scale in the X and Y direction.
		
	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')

	def __call__(self, *args, **kwargs):
		""" Override the call to be able to scale automaticaly the axis.
		"""
		g = Pipeline.__call__(self, *args, **kwargs)
		gs = g.glyph.glyph_source
		# Use a cube source for glyphs.
		if not 'mode' in kwargs:
			gs.glyph_source = gs.glyph_list[-1]
		# 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
		x, y, z = g.mlab_source.x, g.mlab_source.y, g.mlab_source.z
		scale_factor = g.glyph.glyph.scale_factor* \
					tools._min_axis_distance(x, y, z)
		x_scale = kwargs.pop('x_scale', self.lateral_scale)
		y_scale = kwargs.pop('y_scale', self.lateral_scale)
		try:
			g.glyph.glyph_source.glyph_source.y_length = \
					y_scale/(scale_factor)
			g.glyph.glyph_source.glyph_source.x_length = \
					x_scale/(scale_factor)
		except TraitError:
			" Not all types of glyphs have controlable y_length and x_length"

		return g
	
	def get_all_traits(self):
		"""
		2012.2.21
			this function determines the set of possible keys in kwargs.
			add two keywords, x_scale, y_scale.
			
		Returns all the traits of class, and the classes in the pipeline.
		"""
		#call the parental one first.
		traits = Pipeline.get_all_traits(self)
		
		traits['x_scale'] = Trait(0.9, desc='The scale of the glyph on the x-axis, '
				'in units of the distance between nearest points')
		traits['y_scale'] = Trait(0.9, desc='The scale of the glyph on the y-axis, '
				'in units of the distance between nearest points')
		return traits
Пример #8
0
class Mesh(Pipeline):
    """
    Plots a surface using grid-spaced data supplied as 2D arrays.

    **Function signatures**::

        mesh(x, y, z, ...)
    
    x, y, z are 2D arrays, all of the same shape, giving the positions of
    the vertices of the surface. The connectivity between these points is
    implied by the connectivity on the arrays. 

    For simple structures (such as orthogonal grids) prefer the `surf` function,
    as it will create more efficient data structures. For mesh defined by
    triangles rather than regular implicit connectivity, see the 
    `triangular_mesh` function.
    """

    scale_mode = Trait('none', {
        'none': 'data_scaling_off',
        'scalar': 'scale_by_scalar',
        'vector': 'scale_by_vector'
    },
                       help="""the scaling mode for the glyphs
                            ('vector', 'scalar', or 'none').""")

    scale_factor = CFloat(0.05,
                          desc="""scale factor of the glyphs used to represent 
                        the vertices, in fancy_mesh mode. """)

    tube_radius = Trait(0.025,
                        CFloat,
                        None,
                        help="""radius of the tubes used to represent the
                        lines, in mesh mode. If None, simple lines are used.
                        """)

    scalars = Array(help="""optional scalar data.""")

    mask = Array(help="boolean mask array to suppress some data points.")

    representation = Trait(
        'surface',
        'wireframe',
        'points',
        'mesh',
        'fancymesh',
        desc="""the representation type used for the surface.""")

    _source_function = Callable(grid_source)

    _pipeline = [
        ExtractEdgesFactory, GlyphFactory, TubeFactory, SurfaceFactory
    ]

    def __call_internal__(self, *args, **kwargs):
        """ Override the call to be able to choose whether to apply
        filters.
        """
        self.source = self._source_function(*args, **kwargs)
        kwargs.pop('name', None)
        self.store_kwargs(kwargs)
        # Copy the pipeline so as not to modify it for the next call
        self.pipeline = self._pipeline[:]
        if not self.kwargs['representation'] in ('mesh', 'fancymesh'):
            self.pipeline.remove(ExtractEdgesFactory)
            self.pipeline.remove(TubeFactory)
            self.pipeline.remove(GlyphFactory)
            self.pipeline = [
                PolyDataNormalsFactory,
            ] + self.pipeline
        else:
            if self.kwargs['tube_radius'] == None:
                self.pipeline.remove(TubeFactory)
            if not self.kwargs['representation'] == 'fancymesh':
                self.pipeline.remove(GlyphFactory)
            self.kwargs['representation'] = 'surface'
        return self.build_pipeline()
Пример #9
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
Пример #10
0
class Loop(HasTraits):
    """ A current loop class.
    """

    #-------------------------------------------------------------------------
    # Public traits
    #-------------------------------------------------------------------------
    direction = Array(float,
                      value=(0, 0, 1),
                      cols=3,
                      shape=(3, ),
                      desc='directing vector of the loop',
                      enter_set=True,
                      auto_set=False)

    radius = CFloat(0.1,
                    desc='radius of the loop',
                    enter_set=True,
                    auto_set=False)

    position = Array(float,
                     value=(0, 0, 0),
                     cols=3,
                     shape=(3, ),
                     desc='position of the center of the loop',
                     enter_set=True,
                     auto_set=False)

    _plot = None

    Bnorm = Property(depends_on='direction,position,radius')

    view = View('position', 'direction', 'radius', '_')

    #-------------------------------------------------------------------------
    # Loop interface
    #-------------------------------------------------------------------------
    def base_vectors(self):
        """ Returns 3 orthognal base vectors, the first one colinear to
            the axis of the loop.
        """
        # normalize n
        n = self.direction / (self.direction**2).sum(axis=-1)

        # choose two vectors perpendicular to n
        # choice is arbitrary since the coil is symetric about n
        if np.abs(n[0]) == 1:
            l = np.r_[n[2], 0, -n[0]]
        else:
            l = np.r_[0, n[2], -n[1]]

        l /= (l**2).sum(axis=-1)
        m = np.cross(n, l)
        return n, l, m

    @on_trait_change('Bnorm')
    def redraw(self):
        if hasattr(self, 'app') and self.app.scene._renderer is not None:
            self.display()
            self.app.visualize_field()

    def display(self):
        """
        Display the coil in the 3D view.
        """
        n, l, m = self.base_vectors()
        theta = np.linspace(0, 2 * np.pi, 30)[..., np.newaxis]
        coil = self.radius * (np.sin(theta) * l + np.cos(theta) * m)
        coil += self.position
        coil_x, coil_y, coil_z = coil.T
        if self._plot is None:
            self._plot = self.app.scene.mlab.plot3d(coil_x,
                                                    coil_y,
                                                    coil_z,
                                                    tube_radius=0.007,
                                                    color=(0, 0, 1),
                                                    name='Coil')
        else:
            self._plot.mlab_source.set(x=coil_x, y=coil_y, z=coil_z)

    def _get_Bnorm(self):
        """
        returns the magnetic field for the current loop calculated 
        from eqns (1) and (2) in Phys Rev A Vol. 35, N 4, pp. 1535-1546; 1987. 
        """
        ### Translate the coordinates in the coil's frame
        n, l, m = self.base_vectors()
        R = self.radius
        r0 = self.position
        r = np.c_[np.ravel(X), np.ravel(Y), np.ravel(Z)]

        # transformation matrix coil frame to lab frame
        trans = np.vstack((l, m, n))

        r -= r0  #point location from center of coil
        r = np.dot(r, linalg.inv(trans))  #transform vector to coil frame

        #### calculate field

        # express the coordinates in polar form
        x = r[:, 0]
        y = r[:, 1]
        z = r[:, 2]
        rho = np.sqrt(x**2 + y**2)
        theta = np.arctan2(x, y)

        E = special.ellipe((4 * R * rho) / ((R + rho)**2 + z**2))
        K = special.ellipk((4 * R * rho) / ((R + rho)**2 + z**2))
        Bz = 1 / np.sqrt((R + rho)**2 + z**2) * (K + E *
                                                 (R**2 - rho**2 - z**2) /
                                                 ((R - rho)**2 + z**2))
        Brho = z / (rho *
                    np.sqrt((R + rho)**2 + z**2)) * (-K + E *
                                                     (R**2 + rho**2 + z**2) /
                                                     ((R - rho)**2 + z**2))
        # On the axis of the coil we get a divided by zero here. This returns a
        # NaN, where the field is actually zero :
        Brho[np.isnan(Brho)] = 0

        B = np.c_[np.cos(theta) * Brho, np.sin(theta) * Brho, Bz]

        # Rotate the field back in the lab's frame
        B = np.dot(B, trans)

        Bx, By, Bz = B.T
        Bx = np.reshape(Bx, X.shape)
        By = np.reshape(By, X.shape)
        Bz = np.reshape(Bz, X.shape)

        Bnorm = np.sqrt(Bx**2 + By**2 + Bz**2)

        # We need to threshold ourselves, rather than with VTK, to be able
        # to use an ImageData
        Bmax = 10 * np.median(Bnorm)

        Bx[Bnorm > Bmax] = np.NAN
        By[Bnorm > Bmax] = np.NAN
        Bz[Bnorm > Bmax] = np.NAN
        Bnorm[Bnorm > Bmax] = np.NAN

        self.Bx = Bx
        self.By = By
        self.Bz = Bz
        return Bnorm
Пример #11
0
class ImagePlot(HasTraits):
    plot = Instance(Plot)
    meanrate = CFloat(0.0)

    updater = Instance(UpdateEvents)

    #Plot properties
    decay_factor = Range(0., 1)
    colormap = Enum(color_map_name_dict.keys())

    channel = Enum(range(getDefaultMonChannelAddress().nChannels))

    #Private properties
    _cmap = Trait(Greys, Callable)

    def _colormap_default(self):
        return 'Greys'

    def _decay_factor_default(self):
        return 0.5

    def _meanrate_default(self):
        return 0.

    traits_view = View(Item('plot', editor=ComponentEditor(),
                            show_label=False),
                       Item('meanrate', label='MeanRate(Hz)'),
                       menubar=MenuBar(
                           Menu(Action(name="Edit Plot", action="edit_plot"),
                                CloseAction,
                                name="File")),
                       handler=Controller,
                       width=500,
                       height=500,
                       resizable=True,
                       title="Aer2DViewer",
                       buttons=['OK'])

    plot_edit_view = View(Group(Item('decay_factor'), Item('colormap'),
                                Item('channel')),
                          buttons=['OK', 'Cancel'])

    def __init__(self, dims=(128, 10)):
        super(ImagePlot, self).__init__()
        z = numpy.zeros(dims)
        self.plotdata = ArrayPlotData(imagedata=z)
        plot = Plot(self.plotdata)
        plot.img_plot("imagedata",
                      xbounds=(0, dims[1]),
                      ybounds=(0, dims[0]),
                      colormap=self._cmap)
        self.plot = plot
        self.flag = True

    def _colormap_changed(self):
        self._cmap = color_map_name_dict[self.colormap]
        if hasattr(self, 'plot'):
            value_range = self.plot.color_mapper.range
            self.plot.color_mapper = self._cmap(value_range)
        self.plot.request_redraw()

    def _channel_changed(self):
        print('Switching to channel: %d' % self.channel)
        self.updater.channel = self.channel
        self.updater.z = self.updater.z * 0
        try:
            self.updater.eventsQueue.stop()
        except:
            pass
        pyNCS.pyST.STas.addrBuildHashTable(self.updater.stcs[self.channel])

        self.updater.eventsQueue = pyAex.aexclient.AEXMonClient(
            MonChannelAddress=self.updater.stcs,
            channels=[self.channel],
            host=self.updater.host,
            port=self.updater.port,
            autostart=True,
            fps=self.updater.fps)
Пример #12
0
class ImagePlot(HasTraits):
    plot = Instance(Plot)
    meanrate = CFloat(0.0)

    updater = Instance(UpdateEvents)

    #Plot properties
    tDuration = Range(0., 20)
    channel = Enum(range(getDefaultMonChannelAddress().nChannels))

    def _tDuration_default(self):
        return 5.

    def _meanrate_default(self):
        return 0.

    traits_view = View(Item('plot', editor=ComponentEditor(),
                            show_label=False),
                       Item('meanrate', label='MeanRate(Hz)'),
                       menubar=MenuBar(
                           Menu(Action(name="Edit Plot", action="edit_plot"),
                                CloseAction,
                                name="File")),
                       handler=Controller,
                       width=800,
                       height=500,
                       resizable=True,
                       title="Aer1DViewer",
                       buttons=['OK'])

    plot_edit_view = View(
        Group(
            Item('tDuration'),
            #Item('colormap'),
            Item('channel')),
        buttons=['OK', 'Cancel'])

    def __init__(self, dims=(128, 10)):
        super(ImagePlot, self).__init__()
        #z = numpy.zeros(dims)
        self.plotdata = ArrayPlotData(neurons=[0], times=[0])
        plot = Plot(self.plotdata)
        plot.plot(
            ("times", "neurons"),
            type="scatter",
            marker="dot",
            marker_size=1,
            color='black',
        )
        self.plot = plot

    def _channel_changed(self):
        print('Switching to channel: %d' % self.channel)
        self.updater.channel = self.channel
        self.updater.tot_neurons = []
        self.updater.tot_times = []
        try:
            self.updater.eventsQueue.stop()
        except:
            pass
        pyNCS.pyST.STas.addrBuildHashTable(self.updater.stcs[self.channel])
        self.updater.eventsQueue = pyAex.aexclient.AEXMonClient(
            MonChannelAddress=self.updater.stcs,
            channels=[self.channel],
            host=self.updater.host,
            port=self.updater.port,
            autostart=True,
            fps=self.updater.fps)