Esempio n. 1
0
 def __init__(self, ax, maxdist=10, on_move=None,
              on_release=None, on_enter=None, useblit=True,
              line_props=None):
     super(RectangleSelection, self).__init__(ax, on_move=on_move,
                                         on_release=on_release,
                                             on_enter=on_enter,
                                             useblit=useblit,
                                             line_props=line_props)
     self.anchor = None
     self.origin = None
     self.origin_pix = None
     self.shape = 'rectangle'
     self.maxdist = maxdist
     self._extents = [0, 0, 0, 0]
     self.active_handle = None
     self.modifiers = set()
     x = (0, 0, 0, 0)
     y = (0, 0, 0, 0)
     props = dict()
     self._center_handle = ToolHandles(ax, x, y, marker='s',
                                       marker_props=props)
     self._corner_handles = ToolHandles(ax, x, y, marker_props=props)
     self._edge_handles = ToolHandles(ax, x, y, marker='s',
                                      marker_props=props)
     self._corner_order = ['NW', 'NE', 'SE', 'SW']
     self._edge_order = ['W', 'N', 'E', 'S']
     self._artists.extend([self._center_handle.artist,
                      self._corner_handles.artist,
                      self._edge_handles.artist])
     self.connect_event('key_press_event', self.on_key)
     self.connect_event('key_release_event', self.off_key)
Esempio n. 2
0
    def __init__(self, ax, on_move=None, on_release=None, on_enter=None,
                 maxdist=10, line_props=None):
        super(LineTool, self).__init__(ax, on_move=on_move, on_enter=on_enter,
                                       on_release=on_release)

        props = dict(color='r', linewidth=1, alpha=0.4, solid_capstyle='butt')
        props.update(line_props if line_props is not None else {})
        self.linewidth = props['linewidth']
        self.maxdist = maxdist
        self._active_pt = None

        x = (0, 0)
        y = (0, 0)
        self._end_pts = np.transpose([x, y])

        self._line = lines.Line2D(x, y, visible=False, animated=True, **props)
        ax.add_line(self._line)

        self._handles = ToolHandles(ax, x, y)
        self._handles.set_visible(False)
        self._artists = [self._line, self._handles.artist]

        if on_enter is None:
            def on_enter(pts):
                x, y = np.transpose(pts)
                print("length = %0.2f" % np.sqrt(np.diff(x)**2 + np.diff(y)**2))
        self.callback_on_enter = on_enter

        self.connect_event('button_press_event', self.on_mouse_press)
        self.connect_event('button_release_event', self.on_mouse_release)
        self.connect_event('motion_notify_event', self.on_move)
Esempio n. 3
0
    def __init__(self,
                 ax,
                 on_move=None,
                 on_release=None,
                 on_enter=None,
                 maxdist=10,
                 line_props=None):
        super(LineTool, self).__init__(ax,
                                       on_move=on_move,
                                       on_enter=on_enter,
                                       on_release=on_release)

        props = dict(color='r', linewidth=1, alpha=0.4, solid_capstyle='butt')
        props.update(line_props if line_props is not None else {})
        self.linewidth = props['linewidth']
        self.maxdist = maxdist
        self._active_pt = None

        x = (0, 0)
        y = (0, 0)
        self._end_pts = np.transpose([x, y])

        self._line = lines.Line2D(x, y, visible=False, animated=True, **props)
        ax.add_line(self._line)

        self._handles = ToolHandles(ax, x, y)
        self._handles.set_visible(False)
        self._artists = [self._line, self._handles.artist]

        if on_enter is None:

            def on_enter(pts):
                x, y = np.transpose(pts)
                print "length = %0.2f" % np.sqrt(np.diff(x)**2 + np.diff(y)**2)

        self.callback_on_enter = on_enter

        self.connect_event('button_press_event', self.on_mouse_press)
        self.connect_event('button_release_event', self.on_mouse_release)
        self.connect_event('motion_notify_event', self.on_move)
Esempio n. 4
0
    def __init__(self, ax, on_move=None, on_enter=None, on_release=None,
                 useblit=True, maxdist=10, line_props=None):
        super(LineTool, self).__init__(ax, on_move=on_move, on_enter=on_enter,
                                       on_release=on_release, useblit=useblit)
        if not line_props:
            line_props = dict()
        self.linewidth = line_props.get('linewidth', 1)
        self.shape = 'line'
        self.maxdist = maxdist
        self._active_pt = None

        x = (0, 0)
        y = (0, 0)
        self._end_pts = np.transpose([x, y])

        self._handles = ToolHandles(ax, x, y)
        self._handles.set_visible(False)
        self._artists = [self._line, self._handles.artist]

        if on_enter is None:
            def on_enter(pts):
                x, y = np.transpose(pts)
                print("length = %0.2f" % np.sqrt(np.diff(x)**2 + np.diff(y)**2))
        self.callback_on_enter = on_enter
Esempio n. 5
0
class LineTool(CanvasToolBase):
    """Widget for line selection in a plot.

    Parameters
    ----------
    ax : :class:`matplotlib.axes.Axes`
        Matplotlib axes where tool is displayed.
    on_move : function
        Function called whenever a control handle is moved.
        This function must accept the end points of line as the only argument.
    on_release : function
        Function called whenever the control handle is released.
    on_enter : function
        Function called whenever the "enter" key is pressed.
    maxdist : float
        Maximum pixel distance allowed when selecting control handle.
    line_props : dict
        Properties for :class:`matplotlib.lines.Line2D`.

    Attributes
    ----------
    end_points : 2D array
        End points of line ((x1, y1), (x2, y2)).
    """
    def __init__(self, ax, on_move=None, on_release=None, on_enter=None,
                 maxdist=10, line_props=None):
        super(LineTool, self).__init__(ax, on_move=on_move, on_enter=on_enter,
                                       on_release=on_release)

        props = dict(color='r', linewidth=1, alpha=0.4, solid_capstyle='butt')
        props.update(line_props if line_props is not None else {})
        self.linewidth = props['linewidth']
        self.maxdist = maxdist
        self._active_pt = None

        x = (0, 0)
        y = (0, 0)
        self._end_pts = np.transpose([x, y])

        self._line = lines.Line2D(x, y, visible=False, animated=True, **props)
        ax.add_line(self._line)

        self._handles = ToolHandles(ax, x, y)
        self._handles.set_visible(False)
        self._artists = [self._line, self._handles.artist]

        if on_enter is None:
            def on_enter(pts):
                x, y = np.transpose(pts)
                print("length = %0.2f" % np.sqrt(np.diff(x)**2 + np.diff(y)**2))
        self.callback_on_enter = on_enter

        self.connect_event('button_press_event', self.on_mouse_press)
        self.connect_event('button_release_event', self.on_mouse_release)
        self.connect_event('motion_notify_event', self.on_move)

    @property
    def end_points(self):
        return self._end_pts

    @end_points.setter
    def end_points(self, pts):
        self._end_pts = np.asarray(pts)

        self._line.set_data(np.transpose(pts))
        self._handles.set_data(np.transpose(pts))
        self._line.set_linewidth(self.linewidth)

        self.set_visible(True)
        self.redraw()

    def on_mouse_press(self, event):
        if event.button != 1 or not self.ax.in_axes(event):
            return
        self.set_visible(True)
        idx, px_dist = self._handles.closest(event.x, event.y)
        if px_dist < self.maxdist:
            self._active_pt = idx
        else:
            self._active_pt = 0
            x, y = event.xdata, event.ydata
            self._end_pts = np.array([[x, y], [x, y]])

    def on_mouse_release(self, event):
        if event.button != 1:
            return
        self._active_pt = None
        self.callback_on_release(self.geometry)

    def on_move(self, event):
        if event.button != 1 or self._active_pt is None:
            return
        if not self.ax.in_axes(event):
            return
        self.update(event.xdata, event.ydata)
        self.callback_on_move(self.geometry)

    def update(self, x=None, y=None):
        if x is not None:
            self._end_pts[self._active_pt, :] = x, y
        self.end_points = self._end_pts

    @property
    def geometry(self):
        return self.end_points
Esempio n. 6
0
class LineTool(ROIToolBase):
    """Widget for line selection in a plot.

    Parameters
    ----------
    ax : :class:`matplotlib.axes.Axes`
        Matplotlib axes where tool is displayed.
    on_move : function
        Function called whenever a control handle is moved.
        This function must accept the end points of line as the only argument.
    on_release : function
        Function called whenever the control handle is released.
    on_enter : function
        Function called whenever the "enter" key is pressed.
    maxdist : float
        Maximum pixel distance allowed when selecting control handle.
    line_props : dict
        Properties for :class:`matplotlib.lines.Line2D`.

    Attributes
    ----------
    end_points : 2D array
        End points of line ((x1, y1), (x2, y2)).
    """
    def __init__(self, ax, on_move=None, on_enter=None, on_release=None,
                 useblit=True, maxdist=10, line_props=None):
        super(LineTool, self).__init__(ax, on_move=on_move, on_enter=on_enter,
                                       on_release=on_release, useblit=useblit)
        if not line_props:
            line_props = dict()
        self.linewidth = line_props.get('linewidth', 1)
        self.shape = 'line'
        self.maxdist = maxdist
        self._active_pt = None

        x = (0, 0)
        y = (0, 0)
        self._end_pts = np.transpose([x, y])

        self._handles = ToolHandles(ax, x, y)
        self._handles.set_visible(False)
        self._artists = [self._line, self._handles.artist]

        if on_enter is None:
            def on_enter(pts):
                x, y = np.transpose(pts)
                print("length = %0.2f" % np.sqrt(np.diff(x)**2 + np.diff(y)**2))
        self.callback_on_enter = on_enter

    @property
    def end_points(self):
        return self._end_pts

    @end_points.setter
    def end_points(self, pts):
        self._end_pts = pts = np.asarray(pts)
        self._center = (pts[1] + pts[0]) / 2.
        handle_pts = np.vstack((pts[0], self._center, pts[1])).T
        self._line.set_data(np.transpose(pts))
        self._handles.set_data(handle_pts)
        self._line.set_linewidth(self.linewidth)

        self.set_visible(True)
        self.publish_roi()
        self.redraw()

    def on_mouse_press(self, event):
        if event.button != 1 or not self.ax.in_axes(event):
            return
        self.start(event)
        self.set_visible(True)
        idx, px_dist = self._handles.closest(event.x, event.y)
        if px_dist < self.maxdist:
            self._active_pt = idx
        else:
            self._active_pt = 0
            x, y = event.xdata, event.ydata
            self._end_pts = np.array([[x, y], [x, y]])

    def on_mouse_release(self, event):
        if event.button != 1 or not self.active:
            return
        self._active_pt = None
        self.finalize()

    def on_move(self, event):
        if event.button != 1 or self._active_pt is None:
            return
        if not self.ax.in_axes(event):
            return
        self.update(event.xdata, event.ydata)

    def update(self, x=None, y=None):
        if x is not None:
            # check for center
            if self._active_pt == 1:
                xc, yc = self._center
                xo, yo = x - xc, y - yc
                self._end_pts += [xo, yo]
            elif self._active_pt == 0:
                self._end_pts[0, :] = x, y
            else:
                self._end_pts[1, :] = x, y
        self.end_points = self._end_pts

    @property
    def geometry(self):
        pt1, pt2 = self.end_points
        if pt1[0] > pt2[0]:
            pt1, pt2 = pt2, pt1
        return np.array((pt1, pt2))

    @geometry.setter
    def geometry(self, points, linewidth=None):
        self.end_points = points
        if linewidth:
            self.linewidth = linewidth

    def activate(self):
        self.active = True
        if hasattr(self, '_prev_line'):
            self._prev_line.set_data([], [])
        self.redraw()

    @property
    def data(self):
        if self.ax.images:
            return profile_line(self.source_data, self.end_points,
                                self.linewidth)
Esempio n. 7
0
class RectangleSelection(PolygonToolBase):

    def __init__(self, ax, maxdist=10, on_move=None,
                 on_release=None, on_enter=None, useblit=True,
                 line_props=None):
        super(RectangleSelection, self).__init__(ax, on_move=on_move,
                                            on_release=on_release,
                                                on_enter=on_enter,
                                                useblit=useblit,
                                                line_props=line_props)
        self.anchor = None
        self.origin = None
        self.origin_pix = None
        self.shape = 'rectangle'
        self.maxdist = maxdist
        self._extents = [0, 0, 0, 0]
        self.active_handle = None
        self.modifiers = set()
        x = (0, 0, 0, 0)
        y = (0, 0, 0, 0)
        props = dict()
        self._center_handle = ToolHandles(ax, x, y, marker='s',
                                          marker_props=props)
        self._corner_handles = ToolHandles(ax, x, y, marker_props=props)
        self._edge_handles = ToolHandles(ax, x, y, marker='s',
                                         marker_props=props)
        self._corner_order = ['NW', 'NE', 'SE', 'SW']
        self._edge_order = ['W', 'N', 'E', 'S']
        self._artists.extend([self._center_handle.artist,
                         self._corner_handles.artist,
                         self._edge_handles.artist])
        self.connect_event('key_press_event', self.on_key)
        self.connect_event('key_release_event', self.off_key)

    def start(self, event):
        super(RectangleSelection, self).start(event)
        self.anchor = None
        self.origin = self.verts[0]
        self.origin_pix = (event.x, event.y)
        if not self.active_handle == 'C':
            self.extents = [0, 0, 0, 0]
        self._line.set_visible(True)

    def on_key(self, event):
        if self._busy:
            self.modifiers.add(event.key)

    def off_key(self, event):
        if self._busy and event.key in self.modifiers:
            self.modifiers.remove(event.key)

    def on_move(self, event):
        if not self._busy or not event.xdata:
            return
        if self.active_handle and not self.active_handle == 'C':
            x1, x2, y1, y2 = self._extents_on_press
            if self.active_handle in ['E', 'W'] + self._corner_order:
                x2 = event.xdata
            if self.active_handle in ['N', 'S'] + self._corner_order:
                y2 = event.ydata
            self.modifiers = set()
            self.extents = np.array([x1, x2, y1, y2])
        elif ' ' in self.modifiers or self.active_handle == 'C':
            # move command
            if not self.anchor:
                self.anchor = event.xdata, event.ydata
            else:
                dx = event.xdata - self.anchor[0]
                dy = event.ydata - self.anchor[1]
                x1, x2, y1, y2 = self.extents
                x1 += dx
                x2 += dx
                y1 += dy
                y2 += dy
                self.extents = np.array([x1, x2, y1, y2])
                self.origin = [self.origin[0] + dx, self.origin[1] + dy]
                self.anchor = event.xdata, event.ydata
        else:
            if not self.origin:
                self.start()
            dx = (event.xdata - self.origin[0]) / 2.
            dy = (event.ydata - self.origin[1]) / 2.
            center = np.array(self.origin)
            if 'shift' in self.modifiers or 'ctrl+shift' in self.modifiers:
                # square command
                dx_pix = abs(event.x - self.origin_pix[0])
                dy_pix = abs(event.y - self.origin_pix[1])
                if not dx_pix:
                    return
                maxd = max(abs(dx_pix), abs(dy_pix))
                if abs(dx_pix) < maxd:
                    dx *= maxd / abs(dx_pix)
                if abs(dy_pix) < maxd:
                    dy *= maxd / abs(dy_pix)
            if 'control' in self.modifiers or 'ctrl+shift' in self.modifiers:
                # from center
                dx *= 2
                dy *= 2
            else:
                # from corner
                center += np.array([dx, dy])
            self.extents = np.array([center[0] - dx, center[0] + dx,
                                    center[1] - dy, center[1] + dy])

    def set_verts(self):
        x1, x2, y1, y2 = self.extents
        self.verts = [[x1, y1], [x1, y2], [x2, y2], [x2, y1],
                          [x1, y1]]
        self.update()

    def on_mouse_release(self, event):
        self._extents_on_press = None
        self.modifiers = set()
        self.finalize()

    def on_mouse_press(self, event):
        self._set_active_handle(event)
        self.start(event)

    def _set_active_handle(self, event):
        """Set active handle based on the location of the mouse event"""
        # Note: event.xdata/ydata in data coordinates, event.x/y in pixels
        c_idx, c_dist = self._corner_handles.closest(event.x, event.y)
        e_idx, e_dist = self._edge_handles.closest(event.x, event.y)
        m_idx, m_dist = self._center_handle.closest(event.x, event.y)

        # Set active handle as closest handle, if mouse click is close enough.
        if c_dist > self.maxdist and e_dist > self.maxdist:
            self.active_handle = None
        elif c_dist < e_dist:
            self.active_handle = self._corner_order[c_idx]
        else:
            self.active_handle = self._edge_order[e_idx]
        if not self.active_handle and m_dist < self.maxdist:
            self.active_handle = 'C'
        # Save coordinates of rectangle at the start of handle movement.
        x1, x2, y1, y2 = self.extents
        # Switch variables so that only x2 and/or y2 are updated on move.
        if self.active_handle in ['W', 'SW', 'NW']:
            x1, x2 = x2, event.xdata
        if self.active_handle in ['N', 'NW', 'NE']:
            y1, y2 = y2, event.ydata
        self._extents_on_press = x1, x2, y1, y2

    @property
    def _rect_bbox(self):
        if not len(self.extents):
            return 0, 0, 0, 0
        x1, x2, y1, y2 = np.array(self.extents).tolist()
        x0, x1 = np.sort((x1, x2))
        y0, y1 = np.sort((y1, y2))
        width = x1 - x0
        height = y1 - y0
        return x0, y0, width, height

    @property
    def corners(self):
        """Corners of rectangle from lower left, moving clockwise."""
        x0, y0, width, height = self._rect_bbox
        xc = x0, x0 + width, x0 + width, x0
        yc = y0, y0, y0 + height, y0 + height
        return xc, yc

    @property
    def edge_centers(self):
        """Midpoint of rectangle edges from left, moving clockwise."""
        x0, y0, width, height = self._rect_bbox
        w = width / 2.
        h = height / 2.
        xe = x0, x0 + w, x0 + width, x0 + w
        ye = y0 + h, y0, y0 + h, y0 + height
        return xe, ye

    @property
    def extents(self):
        return self._extents

    @extents.setter
    def extents(self, extents):
        x1, x2, y1, y2 = extents
        xmin, xmax = np.sort([x1, x2])
        ymin, ymax = np.sort([y1, y2])
        self._extents = np.array([xmin, xmax, ymin, ymax])

        # Update displayed handles
        self._center_handle.set_data((x2 + x1) / 2, (y2 + y1) / 2)
        self._corner_handles.set_data(*self.corners)
        self._edge_handles.set_data(*self.edge_centers)

        self._center_handle.set_visible(True)
        self._corner_handles.set_visible(True)
        self._edge_handles.set_visible(True)
        self.set_verts()

    @property
    def geometry(self):
        return self._rect_bbox

    @geometry.setter
    def geometry(self, x0, y0, width, height):
        self.extents = [x0, x0 + width, y0, y0 + height]
Esempio n. 8
0
class LineTool(CanvasToolBase):
    """Widget for line selection in a plot.

    Parameters
    ----------
    ax : :class:`matplotlib.axes.Axes`
        Matplotlib axes where tool is displayed.
    on_move : function
        Function called whenever a control handle is moved.
        This function must accept the end points of line as the only argument.
    on_release : function
        Function called whenever the control handle is released.
    on_enter : function
        Function called whenever the "enter" key is pressed.
    maxdist : float
        Maximum pixel distance allowed when selecting control handle.
    line_props : dict
        Properties for :class:`matplotlib.lines.Line2D`.

    Attributes
    ----------
    end_points : 2D array
        End points of line ((x1, y1), (x2, y2)).
    """
    def __init__(self,
                 ax,
                 on_move=None,
                 on_release=None,
                 on_enter=None,
                 maxdist=10,
                 line_props=None):
        super(LineTool, self).__init__(ax,
                                       on_move=on_move,
                                       on_enter=on_enter,
                                       on_release=on_release)

        props = dict(color='r', linewidth=1, alpha=0.4, solid_capstyle='butt')
        props.update(line_props if line_props is not None else {})
        self.linewidth = props['linewidth']
        self.maxdist = maxdist
        self._active_pt = None

        x = (0, 0)
        y = (0, 0)
        self._end_pts = np.transpose([x, y])

        self._line = lines.Line2D(x, y, visible=False, animated=True, **props)
        ax.add_line(self._line)

        self._handles = ToolHandles(ax, x, y)
        self._handles.set_visible(False)
        self._artists = [self._line, self._handles.artist]

        if on_enter is None:

            def on_enter(pts):
                x, y = np.transpose(pts)
                print "length = %0.2f" % np.sqrt(np.diff(x)**2 + np.diff(y)**2)

        self.callback_on_enter = on_enter

        self.connect_event('button_press_event', self.on_mouse_press)
        self.connect_event('button_release_event', self.on_mouse_release)
        self.connect_event('motion_notify_event', self.on_move)

    @property
    def end_points(self):
        return self._end_pts

    @end_points.setter
    def end_points(self, pts):
        self._end_pts = np.asarray(pts)

        self._line.set_data(np.transpose(pts))
        self._handles.set_data(np.transpose(pts))
        self._line.set_linewidth(self.linewidth)

        self.set_visible(True)
        self.redraw()

    def on_mouse_press(self, event):
        if event.button != 1 or not self.ax.in_axes(event):
            return
        self.set_visible(True)
        idx, px_dist = self._handles.closest(event.x, event.y)
        if px_dist < self.maxdist:
            self._active_pt = idx
        else:
            self._active_pt = 0
            x, y = event.xdata, event.ydata
            self._end_pts = np.array([[x, y], [x, y]])

    def on_mouse_release(self, event):
        if event.button != 1:
            return
        self._active_pt = None
        self.callback_on_release(self.geometry)

    def on_move(self, event):
        if event.button != 1 or self._active_pt is None:
            return
        if not self.ax.in_axes(event):
            return
        self.update(event.xdata, event.ydata)
        self.callback_on_move(self.geometry)

    def update(self, x=None, y=None):
        if x is not None:
            self._end_pts[self._active_pt, :] = x, y
        self.end_points = self._end_pts

    @property
    def geometry(self):
        return self.end_points