mirror of
https://github.com/wassname/scikit-image.git
synced 2026-08-14 12:50:39 +08:00
You can call redraw before the first draw event so that the background never gets saved. In this case, skip blitting so we don't need the background image.
155 lines
4.5 KiB
Python
155 lines
4.5 KiB
Python
import numpy as np
|
|
|
|
try:
|
|
from matplotlib import lines
|
|
except ImportError:
|
|
print("Could not import matplotlib -- skimage.viewer not available.")
|
|
|
|
|
|
__all__ = ['CanvasToolBase', 'ToolHandles']
|
|
|
|
|
|
def _pass(*args):
|
|
pass
|
|
|
|
|
|
class CanvasToolBase(object):
|
|
"""Base canvas tool for matplotlib axes.
|
|
|
|
Parameters
|
|
----------
|
|
"""
|
|
def __init__(self, ax, on_move=None, on_enter=None, on_release=None,
|
|
useblit=True):
|
|
self.ax = ax
|
|
self.canvas = ax.figure.canvas
|
|
self.img_background = None
|
|
self.cids = []
|
|
self._artists = []
|
|
self.active = True
|
|
|
|
if useblit:
|
|
self.connect_event('draw_event', self._blit_on_draw_event)
|
|
self.useblit = useblit
|
|
|
|
self.callback_on_move = _pass if on_move is None else on_move
|
|
self.callback_on_enter = _pass if on_enter is None else on_enter
|
|
self.callback_on_release = _pass if on_release is None else on_release
|
|
|
|
self.connect_event('key_press_event', self._on_key_press)
|
|
|
|
def connect_event(self, event, callback):
|
|
"""Connect callback with an event.
|
|
|
|
This should be used in lieu of `figure.canvas.mpl_connect` since this
|
|
function stores call back ids for later clean up.
|
|
"""
|
|
cid = self.canvas.mpl_connect(event, callback)
|
|
self.cids.append(cid)
|
|
|
|
def disconnect_events(self):
|
|
"""Disconnect all events created by this widget."""
|
|
for c in self.cids:
|
|
self.canvas.mpl_disconnect(c)
|
|
|
|
def ignore(self, event):
|
|
"""Return True if event should be ignored.
|
|
|
|
This method (or a version of it) should be called at the beginning
|
|
of any event callback.
|
|
"""
|
|
return not self.active
|
|
|
|
def set_visible(self, val):
|
|
for artist in self._artists:
|
|
artist.set_visible(val)
|
|
|
|
def _blit_on_draw_event(self, event=None):
|
|
self.img_background = self.canvas.copy_from_bbox(self.ax.bbox)
|
|
self._draw_artists()
|
|
|
|
def _draw_artists(self):
|
|
for artist in self._artists:
|
|
self.ax.draw_artist(artist)
|
|
|
|
def redraw(self):
|
|
"""Redraw image and canvas artists.
|
|
|
|
This method should be called by subclasses when artists are updated.
|
|
"""
|
|
if self.useblit and self.img_background is not None:
|
|
self.canvas.restore_region(self.img_background)
|
|
self._draw_artists()
|
|
self.canvas.blit(self.ax.bbox)
|
|
else:
|
|
self.canvas.draw_idle()
|
|
|
|
def _on_key_press(self, event):
|
|
if event.key == 'enter':
|
|
self.callback_on_enter(self.geometry)
|
|
self.set_visible(False)
|
|
self.redraw()
|
|
|
|
@property
|
|
def geometry(self):
|
|
"""Geometry information that gets passed to callback functions."""
|
|
raise NotImplementedError
|
|
|
|
|
|
class ToolHandles(object):
|
|
"""Control handles for canvas tools.
|
|
|
|
Parameters
|
|
----------
|
|
ax : :class:`matplotlib.axes.Axes`
|
|
Matplotlib axes where tool handles are displayed.
|
|
x, y : 1D arrays
|
|
Coordinates of control handles.
|
|
marker : str
|
|
Shape of marker used to display handle. See `matplotlib.pyplot.plot`.
|
|
marker_props : dict
|
|
Additional marker properties. See :class:`matplotlib.lines.Line2D`.
|
|
"""
|
|
def __init__(self, ax, x, y, marker='o', marker_props=None):
|
|
self.ax = ax
|
|
|
|
props = dict(marker=marker, markersize=7, mfc='w', ls='none',
|
|
alpha=0.5, visible=False)
|
|
props.update(marker_props if marker_props is not None else {})
|
|
self._markers = lines.Line2D(x, y, animated=True, **props)
|
|
self.ax.add_line(self._markers)
|
|
self.artist = self._markers
|
|
|
|
@property
|
|
def x(self):
|
|
return self._markers.get_xdata()
|
|
|
|
@property
|
|
def y(self):
|
|
return self._markers.get_ydata()
|
|
|
|
def set_data(self, pts, y=None):
|
|
"""Set x and y positions of handles"""
|
|
if y is not None:
|
|
x = pts
|
|
pts = np.array([x, y])
|
|
self._markers.set_data(pts)
|
|
|
|
def set_visible(self, val):
|
|
self._markers.set_visible(val)
|
|
|
|
def set_animated(self, val):
|
|
self._markers.set_animated(val)
|
|
|
|
def draw(self):
|
|
self.ax.draw_artist(self._markers)
|
|
|
|
def closest(self, x, y):
|
|
"""Return index and pixel distance to closest index."""
|
|
pts = np.transpose((self.x, self.y))
|
|
# Transform data coordinates to pixel coordinates.
|
|
pts = self.ax.transData.transform(pts)
|
|
diff = pts - ((x, y))
|
|
dist = np.sqrt(np.sum(diff**2, axis=1))
|
|
return np.argmin(dist), np.min(dist)
|