Files
scikit-image/skimage/viewer/plugins/base.py
T
2012-07-20 18:19:37 -05:00

190 lines
6.5 KiB
Python

from PyQt4 import QtGui
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from skimage.io._plugins.q_color_mixer import IntelligentSlider
class PlotCanvas(FigureCanvasQTAgg):
"""Canvas for displaying images.
This canvas derives from Matplotlib, and has attributes `fig` and `ax`,
which point to Matplotlib figure and axes.
"""
def __init__(self, parent, height, width, **kwargs):
print height, width
self.fig, self.ax = plt.subplots(figsize=(height, width), **kwargs)
FigureCanvasQTAgg.__init__(self, self.fig)
FigureCanvasQTAgg.setSizePolicy(self,
QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Expanding)
FigureCanvasQTAgg.updateGeometry(self)
# Note: `setParent` must be called after `FigureCanvasQTAgg.__init__`.
self.setParent(parent)
class Plugin(QtGui.QDialog):
"""Base class for widgets that interact with the axes.
Parameters
----------
image_viewer : ImageViewer instance.
Window containing image used in measurement/manipulation.
useblit : bool
If True, use blitting to speed up animation. Only available on some
backends. If None, set to True when using Agg backend, otherwise False.
Attributes
----------
image_viewer : ImageViewer
Window containing image used in measurement.
image : array
Image used in measurement/manipulation.
overlay : array
Image used in measurement/manipulation.
"""
draws_on_image = False
def __init__(self, image_viewer, callback=None, height=100, width=400,
useblit=None):
self.image_viewer = image_viewer
QtGui.QDialog.__init__(self, image_viewer)
self.image_viewer.plugins.append(self)
self.setWindowTitle('Image Plugin')
self.layout = QtGui.QGridLayout(self)
self.resize(width, height)
self.row = 0
if callback is not None:
self.callback = callback
self.arguments = [image_viewer.original_image]
self.keyword_arguments= {}
self.overlay = self.image_viewer.overlay
self.image = self.image_viewer.image
if useblit is None:
useblit = True if mpl.backends.backend.endswith('Agg') else False
self.useblit = useblit
self.cids = []
self.artists = []
if self.draws_on_image:
self.connect_event('draw_event', self.on_draw)
def on_draw(self, event):
"""Save image background when blitting.
The saved image is used to "clear" the figure before redrawing artists.
"""
if self.useblit:
bbox = self.image_viewer.ax.bbox
self.img_background = self.image_viewer.canvas.copy_from_bbox(bbox)
def caller(self, *args):
arguments = [self._get_value(a) for a in self.arguments]
kwargs = dict([(name, self._get_value(a))
for name, a in self.keyword_arguments.iteritems()])
self.callback(*arguments, **kwargs)
def _get_value(self, param):
if hasattr(param, 'val'):
return param.val()
else:
return param
def add_argument(self, name, low, high, callback):
name, slider = self.add_slider(name, low, high, callback)
self.arguments[name] = slider
def add_keyword_argument(self, name, low, high, callback):
name, slider = self.add_slider(name, low, high, callback)
self.keyword_arguments[name] = slider
def add_slider(self, name, low, high, callback):
slider = IntelligentSlider(name, low, high, callback,
orientation='horizontal')
self.layout.addWidget(slider, self.row, 0)
self.row += 1
return name.replace(' ', '_'), slider
def redraw(self):
self.canvas.draw_idle()
def closeEvent(self, event):
"""Disconnect all artists and events from ImageViewer.
Note that events must be connected using `self.connect_event` and
artists must be appended to `self.artists`.
"""
self.disconnect_image_events()
self.remove_artists()
self.image_viewer.plugins.remove(self)
self.image_viewer.redraw()
self.close()
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.image_viewer.connect_event(event, callback)
self.cids.append(cid)
def disconnect_image_events(self):
"""Disconnect all events created by this widget."""
for c in self.cids:
self.image_viewer.disconnect_event(c)
def remove_artists(self):
"""Disconnect artists that are connected to the *image plot*."""
for a in self.artists:
self.image_viewer.remove_artist(a)
class PlotPlugin(Plugin):
"""Plugin for ImageViewer that contains a plot Canvas.
Parameters
----------
image_viewer : ImageViewer instance.
Window containing image used in measurement/manipulation.
figure : :class:`~matplotlib.figure.Figure`
If None, create a figure with a single axes.
useblit : bool
If True, use blitting to speed up animation. Only available on some
backends. If None, set to True when using Agg backend, otherwise False.
Attributes
----------
image_viewer : ImageViewer
Window containing image used in measurement.
image : array
Image used in measurement/manipulation.
overlay : array
Image used in measurement/manipulation.
"""
def __init__(self, image_viewer, useblit=None, **kwargs):
Plugin.__init__(self, image_viewer, **kwargs)
# Add plot for displaying intensity profile.
self.add_plot()
def add_plot(self, height=4, width=4):
self.canvas = PlotCanvas(self, height, width)
self.fig = self.canvas.fig
#TODO: Converted color is slightly different than Qt background.
qpalette = QtGui.QPalette()
qcolor = qpalette.color(QtGui.QPalette.Window)
bgcolor = qcolor.toRgb().value()
if np.isscalar(bgcolor):
bgcolor = str(bgcolor / 255.)
self.fig.patch.set_facecolor(bgcolor)
self.ax = self.canvas.ax
self.layout.addWidget(self.canvas, self.row, 0)