mirror of
https://github.com/wassname/scikit-image.git
synced 2026-08-12 12:30:16 +08:00
ENH: Allow Plugin.add_widget to hook into Plugin attributes.
The `ptype` parameter of widget can now be set to 'plugin'. When this is the case, the plugin will set a plugin attribute whenever the widget is updated. As an example, this commit adds a ComboBox widget which is hooked into the overlay color of the OverlayPlugin.
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
from PyQt4 import QtGui
|
||||
|
||||
import matplotlib as mpl
|
||||
from ..widgets import Slider
|
||||
|
||||
|
||||
class Plugin(QtGui.QDialog):
|
||||
@@ -43,6 +42,7 @@ class Plugin(QtGui.QDialog):
|
||||
if image_filter is not None:
|
||||
self.image_filter = image_filter
|
||||
|
||||
#TODO: Always passing image as first argument may be bad assumption.
|
||||
self.arguments = [image_viewer.original_image]
|
||||
self.keyword_arguments= {}
|
||||
|
||||
@@ -86,9 +86,14 @@ class Plugin(QtGui.QDialog):
|
||||
elif widget.ptype == 'arg':
|
||||
self.arguments.append(widget)
|
||||
widget.callback = self.filter_image
|
||||
elif widget.ptype == 'plugin':
|
||||
widget.callback = self.update_plugin
|
||||
self.layout.addWidget(widget, self.row, 0)
|
||||
self.row += 1
|
||||
|
||||
def update_plugin(self, name, value):
|
||||
setattr(self, name, value)
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""Disconnect all artists and events from ImageViewer.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from skimage.filter import canny
|
||||
|
||||
from .overlayplugin import OverlayPlugin
|
||||
from ..widgets import Slider
|
||||
from ..widgets import Slider, ComboBox
|
||||
|
||||
|
||||
class CannyPlugin(OverlayPlugin):
|
||||
@@ -16,6 +16,7 @@ class CannyPlugin(OverlayPlugin):
|
||||
self.add_widget(Slider('sigma', 0, 5, update_on='release'))
|
||||
self.add_widget(Slider('low threshold', 0, 255, update_on='release'))
|
||||
self.add_widget(Slider('high threshold', 0, 255, update_on='release'))
|
||||
self.add_widget(ComboBox('color', self.color_names, ptype='plugin'))
|
||||
# Update image overlay to default slider values.
|
||||
self.filter_image()
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from ..utils import clear_red
|
||||
|
||||
from .base import Plugin
|
||||
from ..utils import ClearColormap
|
||||
|
||||
|
||||
class OverlayPlugin(Plugin):
|
||||
@@ -12,12 +11,19 @@ class OverlayPlugin(Plugin):
|
||||
Overlay displayed on top of image. This overlay defaults to a color map
|
||||
with alpha values varying linearly from 0 to 1.
|
||||
"""
|
||||
colors = {'red': (1, 0, 0),
|
||||
'yellow': (1, 1, 0),
|
||||
'green': (0, 1, 0),
|
||||
'cyan': (0, 1, 1)}
|
||||
|
||||
def __init__(self, image_viewer, **kwargs):
|
||||
Plugin.__init__(self, image_viewer, **kwargs)
|
||||
self.overlay_cmap = clear_red
|
||||
self._overlay_plot = None
|
||||
self._overlay = None
|
||||
self.cmap = None
|
||||
self.color_names = self.colors.keys()
|
||||
#TODO: `color` doesn't update GUI widget when set manually.
|
||||
self.color = 0
|
||||
|
||||
@property
|
||||
def overlay(self):
|
||||
@@ -31,7 +37,7 @@ class OverlayPlugin(Plugin):
|
||||
ax.images.remove(self._overlay_plot)
|
||||
self._overlay_plot = None
|
||||
elif self._overlay_plot is None:
|
||||
self._overlay_plot = ax.imshow(image, cmap=self.overlay_cmap)
|
||||
self._overlay_plot = ax.imshow(image, cmap=self.cmap)
|
||||
else:
|
||||
self._overlay_plot.set_array(image)
|
||||
self.image_viewer.redraw()
|
||||
@@ -39,3 +45,19 @@ class OverlayPlugin(Plugin):
|
||||
def closeEvent(self, event):
|
||||
self.overlay = None
|
||||
super(OverlayPlugin, self).closeEvent(event)
|
||||
|
||||
@property
|
||||
def color(self):
|
||||
return self._color
|
||||
|
||||
@color.setter
|
||||
def color(self, index):
|
||||
# Update colormap whenever color is changed.
|
||||
name = self.color_names[index]
|
||||
self._color = name
|
||||
rgb = self.colors[name]
|
||||
self.cmap = ClearColormap(rgb)
|
||||
|
||||
if self._overlay_plot is not None:
|
||||
self._overlay_plot.set_cmap(self.cmap)
|
||||
self.image_viewer.redraw()
|
||||
|
||||
@@ -3,7 +3,7 @@ import matplotlib.pyplot as plt
|
||||
from matplotlib.colors import LinearSegmentedColormap
|
||||
|
||||
|
||||
__all__ = ['figimage', 'LinearColormap', 'ClearColormap', 'clear_red']
|
||||
__all__ = ['figimage', 'LinearColormap', 'ClearColormap']
|
||||
|
||||
|
||||
def figimage(image, scale=1, dpi=None, **kwargs):
|
||||
@@ -65,13 +65,10 @@ class LinearColormap(LinearSegmentedColormap):
|
||||
class ClearColormap(LinearColormap):
|
||||
"""Color map that varies linearly from alpha = 0 to 1
|
||||
"""
|
||||
def __init__(self, name, rgb):
|
||||
def __init__(self, rgb, name='clear_color'):
|
||||
r, g, b = rgb
|
||||
cg_speq = {'blue': [(0.0, b), (1.0, b)],
|
||||
'green': [(0.0, g), (1.0, g)],
|
||||
'red': [(0.0, r), (1.0, r)],
|
||||
'alpha': [(0.0, 0.0), (1.0, 1.0)]}
|
||||
LinearColormap.__init__(self, name, cg_speq)
|
||||
|
||||
clear_red = ClearColormap('clear_red', (0.7, 0, 0))
|
||||
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
"""
|
||||
Widgets for interacting with ImageViewer.
|
||||
|
||||
These widgets should be added to a Plugin subclass using its `add_widget`
|
||||
method. The Plugin will delegate action based on the widget's parameter type
|
||||
specified by its `ptype` attribute, which can be:
|
||||
|
||||
'arg' : positional argument passed to Plugin's `filter_image` method.
|
||||
'kwarg' : keyword argument passed to Plugin's `filter_image` method.
|
||||
'plugin' : attribute of Plugin. You'll probably need to make the attribute
|
||||
a class property that updates the display.
|
||||
|
||||
"""
|
||||
from PyQt4 import QtGui
|
||||
from PyQt4 import QtCore
|
||||
from skimage.io._plugins.q_color_mixer import IntelligentSlider
|
||||
|
||||
|
||||
class Slider(IntelligentSlider):
|
||||
"""Slider widget.
|
||||
|
||||
@@ -12,11 +28,56 @@ class Slider(IntelligentSlider):
|
||||
name of the slider.
|
||||
low, high : float
|
||||
Range of slider values.
|
||||
ptype : {'arg' | 'kwarg' | ...}
|
||||
Parameter
|
||||
ptype : {'arg' | 'kwarg' | 'plugin'}
|
||||
Parameter type.
|
||||
"""
|
||||
def __init__(self, name, low, high, ptype='kwarg', callback=None, **kwargs):
|
||||
self.ptype = ptype
|
||||
kwargs.setdefault('orientation', 'horizontal')
|
||||
scale = (high - low) / 1000.0
|
||||
super(Slider, self).__init__(name, scale, low, callback, **kwargs)
|
||||
|
||||
|
||||
class ComboBox(QtGui.QWidget):
|
||||
"""ComboBox widget for selecting among a list of choices.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of slider parameter. If this parameter is passed as a keyword
|
||||
argument, it must match the name of that keyword argument (spaces are
|
||||
replaced with underscores). In addition, this name is displayed as the
|
||||
name of the slider.
|
||||
items: list
|
||||
Allowed parameter values.
|
||||
ptype : {'arg' | 'kwarg' | 'plugin'}
|
||||
Parameter type.
|
||||
"""
|
||||
|
||||
def __init__(self, name, items, ptype='kwarg', callback=None):
|
||||
super(ComboBox, self).__init__()
|
||||
self.ptype = ptype
|
||||
self.callback = callback
|
||||
|
||||
self.name = name
|
||||
self.name_label = QtGui.QLabel()
|
||||
self.name_label.setText(self.name)
|
||||
self.name_label.setAlignment(QtCore.Qt.AlignLeft)
|
||||
|
||||
self._combo_box = QtGui.QComboBox()
|
||||
self._combo_box.addItems(items)
|
||||
|
||||
self.layout = QtGui.QHBoxLayout(self)
|
||||
self.layout.addWidget(self.name_label)
|
||||
self.layout.addWidget(self._combo_box, alignment=QtCore.Qt.AlignLeft)
|
||||
|
||||
self._combo_box.currentIndexChanged.connect(self._value_changed)
|
||||
# self.connect(self._combo_box,
|
||||
# SIGNAL("currentIndexChanged(int)"), self.updateUi)
|
||||
|
||||
@property
|
||||
def val(self):
|
||||
return self._combo_box.value()
|
||||
|
||||
def _value_changed(self, value):
|
||||
self.callback(self.name, value)
|
||||
|
||||
Reference in New Issue
Block a user