Esempio n. 1
0
class ColorMapperFixSingleVal(ColorMapper):
    coloratval = ColorTrait('black')
    val = 0

    def map_screen(self, data_array):
        res = super(ColorMapperFixSingleVal,self).map_screen(data_array)
        res[data_array==self.val] = self.coloratval_
        return res
Esempio n. 2
0
class SmithResistanceGrid(AbstractOverlay):
    # The color of the axis line.
    grid_color = ColorTrait("gray")

    # The line thickness (in pixels) of the axis line.
    grid_weight = Float(1.0)

    # The dash style of the axis line.
    grid_style = LineStyle('dot')

    def overlay(self, component, gc, view_bounds=None, mode='normal'):
        """ Draws this component overlaid on another component.

        Overrides AbstractOverlay.
        """
        if not self.visible:
            return
        self._draw_component(gc, view_bounds, mode, component)
        return

    def _draw_component(self,
                        gc,
                        view_bounds=None,
                        mode='normal',
                        component=None):
        """ Draws the component.

        This method is preserved for backwards compatibility. Overrides
        PlotComponent.
        """
        if not self.visible:
            return

        with gc:
            gc.set_stroke_color(self.grid_color_)
            gc.set_line_width(self.grid_weight)
            gc.set_line_dash(self.grid_style_)

            map_x = self.x_mapper.map_screen
            map_y = self.y_mapper.map_screen
            gc.clip_to_rect(
                map_x(self.x_mapper.range.low), map_y(self.y_mapper.range.low),
                map_x(self.x_mapper.range.high) -
                map_x(self.x_mapper.range.low),
                map_y(self.y_mapper.range.high) -
                map_y(self.y_mapper.range.low))

            x_center = self.x_mapper.map_screen(0)
            y_center = self.y_mapper.map_screen(0)
            radius = self.y_mapper.map_screen(1) - self.y_mapper.map_screen(0)

            # TODO: adapt to zoom level (fixed number of pixels of spacing)
            for i in range(10):
                r = i * radius / 10
                gc.arc(x_center + r, y_center, radius - r, 0, 2 * pi)
                gc.stroke_path()
Esempio n. 3
0
class Plot_i(HasTraits):

    plot = Instance(Plot)
    color = ColorTrait('blue')
    marker = marker_trait
    marker_size = Int(4)
    line_width = Int(4)
    traits_view = View(Group(Tabbed(Group( \
        Group(Item('color', label="Color"), \
            Item('marker', label="Marker"), \
            orientation = 'vertical'), \
        Group( \
            Item('marker_size', label= "Size"), \
            Item('line_width', label = 'Linewidth'), \
            orientation = 'vertical'), \
        dock = 'tab', orientation = 'vertical')), \
        Item('plot', editor=ComponentEditor(), show_label=False), orientation = 'horizontal'), \
        width=800, height=600, resizable=True, title="Chaco Plot")

    def __init__(self,X,Y):
        super(Plot_i, self).__init__()
        self.load_data(X,Y)
        self.start()

    def load_data(self,X,Y) :
        self.X = X
        self.Y = Y
        plotdata = ArrayPlotData(x = X, y = Y)
        plot = Plot(plotdata)
        self.renderer_line = plot.plot(('x','y'),type = 'line', color = "blue")[0]
        self.renderer_scat = plot.plot(('x','y'),type = 'scatter', color = "blue")[0]
        self.plot = plot

    def start(self):
        self.configure_traits()

    def _color_changed(self):
        self.renderer_line.color = self.color
        self.renderer_scat.color = self.color

    def _marker_changed(self):
        self.renderer_scat.marker = self.marker

    def _marker_size_changed(self):
        self.renderer_scat.marker_size = self.marker_size

    def _line_width_changed(self):
        self.renderer_line.line_width = self.line_width
Esempio n. 4
0
class ScatterPlotTraits(HasTraits):

    plot = Instance(Plot)
    color = ColorTrait("blue")
    marker = marker_trait
    marker_size = Int(4)
    x = Array()
    y = Array()

    traits_view = View(Group(Item('color', label="Color", style="custom"),
                             Item('marker', label="Marker"),
                             Item('marker_size', label="Size"),
                             Item('plot',
                                  editor=ComponentEditor(),
                                  show_label=False),
                             orientation="vertical"),
                       width=800,
                       height=600,
                       resizable=True,
                       title="Chaco Plot")

    def __init__(self):
        super(ScatterPlotTraits, self).__init__()
        x = linspace(-14, 14, 10)
        y = sin(x) * x**3
        plotdata = ArrayPlotData(x=x, y=y)
        plot = Plot(plotdata)
        self.x = x
        self.y = y

        self.renderer = plot.plot(("x", "y"), type="scatter", color="blue")[0]
        self.plot = plot

    def _color_changed(self):
        self.renderer.color = self.color

    def _marker_changed(self):
        self.renderer.marker = self.marker

    def _marker_size_changed(self):
        self.renderer.marker_size = self.marker_size
Esempio n. 5
0
class Line(AbstractOverlay):
    orientation = Enum("h", "v")
    color = ColorTrait("green")
    width = Int(1)

    def overlay(self, component, gc, *args, **kw):
        if component is None:
            return
        gc.save_state()
        gc.set_stroke_color(self.color_)
        gc.set_line_width(self.width)
        if self.orientation == "h":
            mid = component.y + component.height / 2
            gc.move_to(component.x, mid)
            gc.line_to(component.x2, mid)
        else:
            mid = component.x + component.width / 2
            gc.move_to(mid, component.y)
            gc.line_to(mid, component.y2)
        gc.stroke_path()
        gc.restore_state()
Esempio n. 6
0
from enthought.template.api \
    import MutableTemplate, TRange, TStr, TList, TDerived

from enable_editor \
    import EnableEditor

from scatter_plot \
    import ScatterPlot

#-------------------------------------------------------------------------------
#  Trait definitions:
#-------------------------------------------------------------------------------

# Template color trait:
TColor = ColorTrait(template='copy')

#-------------------------------------------------------------------------------
#  'ScatterPlotNM' class:
#-------------------------------------------------------------------------------


class ScatterPlotNM(MutableTemplate):

    #-- Template Traits --------------------------------------------------------

    # The title of the plot:
    title = TStr('NxM Scatter Plots')

    # The type of marker to use.  This is a mapped trait using strings as the
    # keys:
Esempio n. 7
0
class MyLineInspector(DragTool):

    # The axis that this tool is parallel to.
    axis = Enum("index", "value", "index_x", "index_y")

    # The possible inspection modes of the tool.
    #
    # space:
    #    The tool maps from screen space into the data space of the plot.
    # indexed:
    #    The tool maps from screen space to an index into the plot's index array.
    inspect_mode = Enum("space", "indexed")

    # Respond to user mouse events?
    is_interactive = Bool(True)

    # Does the tool respond to updates in the metadata on the data source
    # and update its own position?
    is_listener = Bool(False)

    # If interactive, does the line inspector write the current data space point
    # to the appropriate data source's metadata?
    write_metadata = Bool(False)

    # The name of the metadata field to listen or write to.
    metadata_name = Str("selections")

    callback = Any()
    token = Any()
    handle_size = Float(5)

    #------------------------------------------------------------------------
    # Override default values of inherited traits in BaseTool
    #------------------------------------------------------------------------

    # This tool is visible (overrides BaseTool).
    visible = True
    # This tool is drawn as an overlay (overrides BaseTool).
    draw_mode = "overlay"

    # TODO:STYLE

    # Color of the line.
    color = ColorTrait("grey")
    # Width in pixels of the line.
    line_width = Float(1.0)
    # Dash style of the line.
    line_style = LineStyle("dash")

    index_position = Float(-1)

    # Last recorded position of the mouse
    _last_position = Trait(None, Any)

    def draw(self, gc, view_bounds=None):
        """ Draws this tool on a graphics context.  
        
        Overrides BaseTool.
        """
        # We draw at different points depending on whether or not we are
        # interactive.  If both listener and interactive are true, then the
        # selection metadata on the plot component takes precendence.
        plot = self.component
        if plot is None:
            return

#        if self.is_listener:
#            tmp = self._get_screen_pts()
#        elif self.is_interactive:
#            tmp = self._last_position
#
#        if tmp:
#            sx, sy = tmp
#        else:
#            return

        if self.axis == "index" or self.axis == "index_x":
            if self.index_position == -1:
                self.index_position = int((plot.x + plot.x2) / 2)
                self.index_changed()

            self._draw_vertical_line(gc, self.index_position)
        else:
            if self.index_position == -1:
                self.index_position = int((plot.y + plot.y2) / 2)
                self.index_changed()
            self._draw_horizontal_line(gc, self.index_position)

        return

    def do_layout(self, *args, **kw):
        pass

    def overlay(self, component, gc, view_bounds=None, mode="normal"):
        """ Draws this component overlaid on a graphics context.
        """
        self.draw(gc, view_bounds)
        return

    def is_draggable(self, x, y):
        """ Returns whether the (x,y) position is in a region that is OK to 
        drag.  
        
        Used by the tool to determine when to start a drag.
        """

        if self.axis == "index" or self.axis == "index_x":

            if x > self.index_position - self.handle_size and \
                x < self.index_position + self.handle_size and \
                y > self.component.y2 - 2*self.handle_size and \
                y < self.component.y2:
                return True
        else:

            if y > self.index_position - self.handle_size and \
                y < self.index_position + self.handle_size and \
                x > self.component.x2 - 2*self.handle_size and \
                x < self.component.x2:
                return True

        return False

    def dragging(self, event):
        """ This method is called for every mouse_move event that the tool 
        receives while the user is dragging the mouse.  
        
        It is recommended that subclasses do most of their work in this method.
        """

        if event.x < self.component.x or event.x > self.component.x2 or \
            event.y < self.component.y or event.y > self.component.y2:
            return

        if self.axis == "index" or self.axis == "index_x":
            self.index_position = event.x
        else:
            self.index_position = event.y

        self.index_changed()
#        index = self.component.map_index((event.x,event.y),index_only=True)
#        if self.axis == "index" or self.axis == "index_x":
#            self.index_position = event.x
##            self.component.request_redraw()
#            self.callback(self, self.axis, index[0])
#        else:
#            self.index_position = event.y
##            self.component.request_redraw()
#            self.callback(self, self.axis, index[1])

    def index_changed(self):

        plot = self.component
        if self.axis == "index" or self.axis == "index_x":
            index = plot.map_index((self.index_position, plot.y),
                                   index_only=True)
            value = plot.map_data([(self.index_position, plot.y)])
            self.callback(self, self.axis, index[0], value[0][0])
        else:
            index = plot.map_index((plot.x, self.index_position),
                                   index_only=True)
            value = plot.map_data([(plot.x, self.index_position)])
            self.callback(self, self.axis, index[1], value[0][1])

    def update_index(self, token, axis, index):
        if token == self.token and axis == self.axis:
            plot = self.component

            if self.axis == "index" or self.axis == "index_x":
                dx = plot.index.get_data()[0].get_data()[index]
                dy = plot.index.get_data()[1].get_data()[0]
                sx = plot.map_screen([(dx, dy)])[0][0]
                self.index_position = sx
                self.component.request_redraw()
            else:
                dx = plot.index.get_data()[0].get_data()[0]
                dy = plot.index.get_data()[1].get_data()[index]
                sy = plot.map_screen([(dx, dy)])[0][1]
                self.index_position = sy
                self.component.request_redraw()


#            if self.index_position != index:
#                self.index_position = index
            pass

    def _draw_vertical_line(self, gc, sx):
        """ Draws a vertical line through screen point (sx,sy) having the height
        of the tool's component.
        """

        if sx < self.component.x or sx > self.component.x2:
            return

        gc.save_state()
        try:
            gc.set_stroke_color(self.color_)
            gc.set_line_width(self.line_width)
            gc.set_line_dash(self.line_style_)
            gc.move_to(sx, self.component.y)
            gc.line_to(sx, self.component.y2)

            gc.stroke_path()
            gc.rect(sx - self.handle_size,
                    self.component.y2 - 2 * self.handle_size,
                    2 * self.handle_size, 2 * self.handle_size)
            gc.fill_path()
        finally:
            gc.restore_state()
        return

    def _draw_horizontal_line(self, gc, sy):
        """ Draws a horizontal line through screen point (sx,sy) having the
        width of the tool's component.
        """
        if sy < self.component.y or sy > self.component.y2:
            return

        gc.save_state()
        try:
            gc.set_stroke_color(self.color_)
            gc.set_line_width(self.line_width)
            gc.set_line_dash(self.line_style_)
            gc.move_to(self.component.x, sy)
            gc.line_to(self.component.x2, sy)

            gc.stroke_path()
            gc.rect(self.component.x2 - 2 * self.handle_size,
                    sy - self.handle_size, 2 * self.handle_size,
                    2 * self.handle_size)
            gc.fill_path()
        finally:
            gc.restore_state()
        return
Esempio n. 8
0
class SmithCircle(AbstractOverlay):
    # The color of the axis line.
    line_color = ColorTrait("black")

    # The line thickness (in pixels) of the axis line.
    line_weight = Float(1.0)

    # The dash style of the axis line.
    line_style = LineStyle('solid')

    #    def __init__(self, component=None, **kwargs):
    #        # Override init so that our component gets set last.  We want the
    #        # _component_changed() event handler to get run last.
    #        super(self.__class__, self).__init__(**kwargs)
    #        if component is not None:
    #            self.component = component

    def overlay(self, component, gc, view_bounds=None, mode='normal'):
        """ Draws this component overlaid on another component.

        Overrides AbstractOverlay.
        """
        if not self.visible:
            return
        self._draw_component(gc, view_bounds, mode, component)
        return


#    def _draw_overlay(self, gc, view_bounds=None, mode='normal'):
#        """ Draws the overlay layer of a component.

#        Overrides PlotComponent.
#        """
#        self._draw_component(gc, view_bounds, mode)
#        return

    def _draw_component(self,
                        gc,
                        view_bounds=None,
                        mode='normal',
                        component=None):
        """ Draws the component.

        This method is preserved for backwards compatibility. Overrides
        PlotComponent.
        """
        if not self.visible:
            return

        def center_radius(
                mapper):  #data_low, data_high, screen_low, screen_high):
            map = mapper.map_screen
            return map(0), map(1) - map(0)

        with gc:
            gc.set_stroke_color(self.line_color_)
            gc.set_line_width(self.line_weight)
            gc.set_line_dash(self.line_style_)
            map_x = self.x_mapper.map_screen
            map_y = self.y_mapper.map_screen
            gc.clip_to_rect(
                map_x(self.x_mapper.range.low), map_y(self.y_mapper.range.low),
                map_x(self.x_mapper.range.high) -
                map_x(self.x_mapper.range.low),
                map_y(self.y_mapper.range.high) -
                map_y(self.y_mapper.range.low))

            x_center, radius = center_radius(self.x_mapper)
            y_center, radius = center_radius(self.y_mapper)

            # outer ring
            gc.arc(x_center, y_center, radius, 0, 2 * pi)
            gc.stroke_path()

            # horizontal axis
            gc.move_to(x_center - radius, y_center)
            gc.line_to(x_center + radius, y_center)
            gc.stroke_path()
Esempio n. 9
0
class SmithReactanceGrid(AbstractOverlay):
    # The color of the axis line.
    grid_color = ColorTrait("gray")

    # The line thickness (in pixels) of the axis line.
    grid_weight = Float(1.0)

    # The dash style of the axis line.
    grid_style = LineStyle('dot')

    def overlay(self, component, gc, view_bounds=None, mode='normal'):
        """ Draws this component overlaid on another component.

        Overrides AbstractOverlay.
        """
        if not self.visible:
            return
        self._draw_component(gc, view_bounds, mode, component)
        return

    def _draw_component(self,
                        gc,
                        view_bounds=None,
                        mode='normal',
                        component=None):
        """ Draws the component.

        This method is preserved for backwards compatibility. Overrides
        PlotComponent.
        """
        if not self.visible:
            return

        with gc:
            gc.set_stroke_color(self.grid_color_)
            gc.set_line_width(self.grid_weight)
            gc.set_line_dash(self.grid_style_)

            map_x = self.x_mapper.map_screen
            map_y = self.y_mapper.map_screen
            gc.clip_to_rect(
                map_x(self.x_mapper.range.low), map_y(self.y_mapper.range.low),
                map_x(self.x_mapper.range.high) -
                map_x(self.x_mapper.range.low),
                map_y(self.y_mapper.range.high) -
                map_y(self.y_mapper.range.low))

            x_center = self.x_mapper.map_screen(0)
            y_center = self.y_mapper.map_screen(0)
            rad = self.y_mapper.map_screen(1) - self.y_mapper.map_screen(0)

            # TODO: adapt to zoom level (fixed number of pixels of spacing)
            rad2 = rad**2
            for i in range(6):
                r1 = i * rad / 5
                tmp = (rad2 - r1**2) / (rad2 + r1**2)
                gc.arc(x_center + rad, y_center + r1, r1, pi - arcsin(tmp),
                       1.5 * pi)
                gc.stroke_path()
                gc.arc(x_center + rad, y_center - r1, r1, 0.5 * pi,
                       pi + arcsin(tmp))
                gc.stroke_path()

            stoprad = 2 * rad / 10
            stoprad2 = stoprad**2
            for i in range(6):
                r2 = 7 * rad / (i + 1)
                tmp = (rad2 - r2**2) / (rad2 + r2**2)
                tmp2 = (stoprad2 - r2**2) / (stoprad2 + r2**2)
                gc.arc(x_center + rad, y_center + r2, r2, pi - arcsin(tmp),
                       pi - arcsin(tmp2))
                gc.stroke_path()
                gc.arc(x_center + rad, y_center - r2, r2, pi + arcsin(tmp2),
                       pi + arcsin(tmp))
                gc.stroke_path()
Esempio n. 10
0
class StackedRenderer(BaseXYPlot):

    index_name = Str('date')
    value_names = List(Str)

    # Accept any recarray as data
    data = Array

    index = Property
    value = Property

    # Traits for setting appearance.
    # The line style {"dot", "dash", "solid", others?}
    line_style = LineStyle

    # Outline thickness.  Use 0 for no outline
    line_width = Float(1.0)

    # Outline color
    line_color = ColorTrait("black")

    def _gather_points(self):
        """
        Gathers up the data points that are within our bounds and stores them
        """
        if self._cache_valid:
            return
        if not self.index:
            return

        values = []

        idx = self.data[self.index_name].get_data()
        index_mask = self.index_range.mask_data(idx)

        for itm in self.data.dtype.names:
            values.append(self.data[itm][index_mask])

        print idx, values

        value_lengths = array(map(len, values))

        if len(idx) == 0 or any(value_lengths == 0) or any(
                len(idx) != value_lengths):
            print "Chaco: using empty dataset; index_len=%d, value_lengths=%s." \
                                % (len(idx), str(value_lengths))
            self._cached_data_pts = []
            self._cache_valid = True
            return

        points = column_stack([
            idx,
        ] + values)

        for ds in [self.open, self.high, self.low, self.close, self.average]:
            value, tmp_value_mask = ds.get_data_mask()
            values.append(value)
            if value_mask is None:
                value_mask = tmp_value_mask
            else:
                value_mask &= tmp_value_mask

        # Broaden the range masks by 1
        #index_range_mask = broaden(self.index_mapper.range.mask_data(index))
        #value_range_mask = broaden(self.value_mapper.range.mask_data(points, high_ndx=2, low_ndx=3))
        index_range_mask = self.index_mapper.range.mask_data(idx)
        value_range_mask = self.value_mapper.range.mask_data(points,
                                                             high_ndx=2,
                                                             low_ndx=3)
        nan_mask = invert(isnan(index_mask)) & invert(isnan(value_mask))
        point_mask = index_mask & value_mask & nan_mask & \
                     index_range_mask & value_range_mask

        self._cached_data_pts = compress(point_mask, points, axis=0)

        self._cache_valid = True
        return

    def _draw_component(self, gc, view_bounds=None, mode="normal"):
        # Gather the points within the view range into self._cached_data_pts

        #self._gather_points()
        self._gather_points()
        if self._cached_data_pts.size == 0:
            # No data.
            return

        names = self.data.dtype.names
        pts = zip(names, self._cached_data_pts.transpose())
        for pt in pts:
            setattr(self, *pt)

        # Map data points into screen space
        values = [self.index_mapper.map_screen(getattr(self, self.index_name))]

        for itm in names:
            if itm != self.index_name:
                values.append(self.value_mapper.map_screen(getattr(self, itm)))

        # Render the screen space points
        gc.save_state()
        gc.set_antialias(False)
        gc.clip_to_rect(self.x, self.y, self.width, self.height)
        self._render(gc, values)
        gc.restore_state()

    def _get_index(self):
        return self.data[self.index_name]

    def _set_index(self, new_index):
        self.index = new_index

    def _get_value(self):
        return self.data[self.value_name]

    def _set_value(self, new_value):
        self.value = new_value


# EOF ####################################################################
Esempio n. 11
0
class Thingy(HasTraits):
    color = ColorTrait('black')
Esempio n. 12
0
class SegmentPlot(BaseXYPlot):
    """ A plot consisting of disconnected line segments.
    """

    # The color of the line.
    color = black_color_trait

    # The color to use to highlight the line when selected.
    selected_color = ColorTrait("lightyellow")

    # The style of the selected line.
    selected_line_style = LineStyle("solid")

    # The name of the key in self.metadata that holds the selection mask
    metadata_name = Str("selections")

    # The thickness of the line.
    line_width = Float(1.0)

    # The line dash style.
    line_style = LineStyle

    # Traits UI View for customizing the plot.
    traits_view = tui.View(tui.Item("color", style="custom"),
                           "line_width",
                           "line_style",
                           buttons=["OK", "Cancel"])

    #------------------------------------------------------------------------
    # Private traits
    #------------------------------------------------------------------------

    # Cached list of non-NaN arrays of (x,y) data-space points; regardless of
    # self.orientation, this is always stored as (index_pt, value_pt).  This is
    # different from the default BaseXYPlot definition.
    _cached_data_pts = List

    # Cached list of non-NaN arrays of (x,y) screen-space points.
    _cached_screen_pts = List

    def hittest(self, screen_pt, threshold=7.0):
        # NotImplemented
        return None

    def get_screen_points(self):
        self._gather_points()
        return [self.map_screen(ary) for ary in self._cached_data_pts]

    #------------------------------------------------------------------------
    # Private methods; implements the BaseXYPlot stub methods
    #------------------------------------------------------------------------

    def _gather_points(self):
        """
        Collects the data points that are within the bounds of the plot and 
        caches them.
        """
        if self._cache_valid or not self.index or not self.value:
            return

        index = self.index.get_data()
        value = self.value.get_data()

        # Check to see if the data is completely outside the view region
        for ds, rng in ((self.index, self.index_range), (self.value,
                                                         self.value_range)):
            low, high = ds.get_bounds()
            if low > rng.high or high < rng.low:
                return

        if len(index) == 0 or len(value) == 0 or len(index) != len(value):
            self._cached_data_pts = []
            self._cache_valid = True

        size_diff = len(value) - len(index)
        if size_diff > 0:
            warnings.warn('len(value) %d - len(index) %d = %d' \
                          % (len(value), len(index), size_diff))
            index_max = len(index)
            value = value[:index_max]
        else:
            index_max = len(value)
            index = index[:index_max]
        if index_max % 2:
            # We need an even number of points. Exclude the final one and
            # continue.
            warnings.warn('need an even number of points; got %d' % index_max)
            index = index[:index_max - 1]
            value = value[:index_max - 1]

        # TODO: restore the functionality of rendering highlighted portions
        # of the line
        #selection = self.index.metadata.get(self.metadata_name, None)
        #if selection is not None and type(selection) in (ndarray, list) and \
        #        len(selection) > 0:

        # Exclude NaNs and Infs.
        finite_mask = np.isfinite(value) & np.isfinite(index)
        # Since the line segment ends are paired, we need to exclude the whole pair if
        # one is not finite.
        finite_mask[::2] &= finite_mask[1::2]
        finite_mask[1::2] &= finite_mask[::2]
        self._cached_data_pts = [
            np.column_stack([index[finite_mask], value[finite_mask]])
        ]
        self._cache_valid = True

    def _render(self, gc, points, selected_points=None):
        if len(points) == 0:
            return

        gc.save_state()
        try:
            gc.set_antialias(True)
            gc.clip_to_rect(self.x, self.y, self.width, self.height)

            if selected_points is not None:
                self._render_segments(gc, selected_points,
                                      self.selected_color_,
                                      self.line_width + 10.0,
                                      self.selected_line_style_)

            # Render using the normal style
            self._render_segments(gc, points, self.color_, self.line_width,
                                  self.line_style_)
        finally:
            gc.restore_state()

    def _render_segments(self, gc, points, color, line_width, line_style):
        gc.set_stroke_color(color)
        gc.set_line_width(line_width)
        gc.set_line_dash(line_style)
        gc.begin_path()
        for ary in points:
            if len(ary) > 0:
                gc.line_set(ary[::2], ary[1::2])
        gc.stroke_path()

    @on_trait_change('color,line_style,line_width')
    def _redraw(self):
        self.invalidate_draw()
        self.request_redraw()
Esempio n. 13
0
class ZoomOverlay(AbstractOverlay):
    '''
    
    Adapted from a Chaco example.
    '''

    source = Instance(BaseXYPlot)
    destination = Instance(Component)

    border_color = ColorTrait((0, 0, 0.7, 1))
    border_width = Int(1)
    fill_color = ColorTrait("lightblue")
    alpha = Float(0.3)

    traits_view = View(Group(Item('fill_color', label="Color", style="simple"),
                             Item('border_width',
                                  label="Border Width",
                                  style="custom"),
                             Item('border_color', label="Border Color"),
                             orientation="vertical"),
                       width=500,
                       height=300,
                       resizable=True,
                       title="Configure Settings",
                       buttons=['OK', 'Cancel'])

    #*************************************calculate_points()*************************************
    def calculate_points(self, component):
        '''
        
        Args: 
        Returns:
        Raises:
        '''
        # find selection range on source plot
        x_start, x_end = self._get_selection_screencoords()
        if x_start > x_end:
            x_start, x_end = x_end, x_start

        y_end = self.source.y
        y_start = self.source.y2

        left_top = array([x_start, y_end])
        left_mid = array([x_start, y_start])
        right_top = array([x_end, y_end])
        right_mid = array([x_end, y_start])

        # Offset y because we want to avoid overlapping the trapezoid with the topmost
        # pixels of the destination plot.
        #y = self.destination.y + 1
        y = 100

        left_end = array([self.destination.x, y])
        right_end = array([self.source.x2, y])

        polygon = array(
            (left_top, left_mid, left_end, right_end, right_mid, right_top))
        left_line = array((left_top, left_mid, left_end))
        right_line = array((right_end, right_mid, right_top))

        return left_line, right_line, polygon

    #*************************************overlay()*************************************
    def overlay(self, component, gc, view_bounds=None, mode="normal"):
        '''
        
        Args: 
        Returns:
        Raises:
        '''

        tmp = self._get_selection_screencoords()
        if tmp is None:
            return

        left_line, right_line, polygon = self.calculate_points(component)

        with gc:
            gc.translate_ctm(*component.position)
            gc.set_alpha(self.alpha)
            gc.set_fill_color(self.fill_color_)
            gc.set_line_width(self.border_width)
            gc.set_stroke_color(self.border_color_)
            gc.begin_path()
            gc.lines(polygon)
            gc.fill_path()

            gc.begin_path()
            gc.lines(left_line)
            gc.lines(right_line)
            gc.stroke_path()

        return

    #*************************************_get_selection_screencords()*************************************
    def _get_selection_screencoords(self):
        '''
        
        Args: 
        Returns:
        Raises:
        '''
        selection = self.source.index.metadata["selections"]
        if selection is not None and len(selection) == 2:
            mapper = self.source.index_mapper
            return mapper.map_screen(array(selection))
        else:
            return None

    #*************************************_source_changed()*************************************
    def _source_changed(self, old, new):
        '''
        
        Args: 
        Returns:
        Raises:
        '''
        if old is not None and old.controller is not None:
            old.controller.on_trait_change(self._selection_update_handler,
                                           "selection",
                                           remove=True)
        if new is not None and new.controller is not None:
            new.controller.on_trait_change(self._selection_update_handler,
                                           "selection")
        return

    #*************************************_selection_update_handler()*************************************
    def _selection_update_handler(self, value):
        '''
        
        Args: 
        Returns:
        Raises:
        '''
        if value is not None and self.destination is not None:
            r = self.destination.index_mapper.range
            start, end = amin(value), amax(value)
            r.low = start
            r.high = end

        self.source.request_redraw()
        self.destination.request_redraw()
        return