mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-04 05:53:05 +08:00
Fix figure canvas creation.
Avoid use of matplotlib's pyplot functions for creating figure canvases. In particular, key press events were ignored by the canvas.
This commit is contained in:
@@ -5,25 +5,11 @@ try:
|
||||
except ImportError:
|
||||
print("Could not import PyQt4 -- skimage.viewer not available.")
|
||||
|
||||
try:
|
||||
import matplotlib.pyplot as plt
|
||||
except ImportError:
|
||||
print("Could not import matplotlib -- skimage.viewer not available.")
|
||||
|
||||
from ..utils import MatplotlibCanvas
|
||||
from ..utils import new_plot
|
||||
from .base import Plugin
|
||||
|
||||
|
||||
class PlotCanvas(MatplotlibCanvas):
|
||||
"""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):
|
||||
self.fig, self.ax = plt.subplots(figsize=(height, width), **kwargs)
|
||||
super(PlotCanvas, self).__init__(parent, self.fig, **kwargs)
|
||||
self.setMinimumHeight(150)
|
||||
__all__ = ['PlotPlugin']
|
||||
|
||||
|
||||
class PlotPlugin(Plugin):
|
||||
@@ -45,8 +31,9 @@ class PlotPlugin(Plugin):
|
||||
self.canvas.draw_idle()
|
||||
|
||||
def add_plot(self, height=4, width=4):
|
||||
self.canvas = PlotCanvas(self, height, width)
|
||||
self.fig = self.canvas.fig
|
||||
self.fig, self.ax = new_plot(figsize=(height, width))
|
||||
self.canvas = self.fig.canvas
|
||||
self.canvas.setMinimumHeight(150)
|
||||
#TODO: Converted color is slightly different than Qt background.
|
||||
qpalette = QtGui.QPalette()
|
||||
qcolor = qpalette.color(QtGui.QPalette.Window)
|
||||
@@ -54,5 +41,4 @@ class PlotPlugin(Plugin):
|
||||
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)
|
||||
|
||||
@@ -3,8 +3,11 @@ import warnings
|
||||
import numpy as np
|
||||
|
||||
try:
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib as mpl
|
||||
from matplotlib.figure import Figure
|
||||
from matplotlib import _pylab_helpers
|
||||
from matplotlib.colors import LinearSegmentedColormap
|
||||
from matplotlib.backends.backend_qt4 import FigureManagerQT
|
||||
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
|
||||
except ImportError:
|
||||
FigureCanvasQTAgg = object # hack to prevent nosetest and autodoc errors
|
||||
@@ -18,7 +21,7 @@ except ImportError:
|
||||
|
||||
|
||||
__all__ = ['init_qtapp', 'start_qtapp', 'RequiredAttr', 'figimage',
|
||||
'LinearColormap', 'ClearColormap', 'MatplotlibCanvas']
|
||||
'LinearColormap', 'ClearColormap', 'FigureCanvas', 'new_plot']
|
||||
|
||||
|
||||
QApp = None
|
||||
@@ -55,38 +58,6 @@ class RequiredAttr(object):
|
||||
self.val = val
|
||||
|
||||
|
||||
def figimage(image, scale=1, dpi=None, **kwargs):
|
||||
"""Return figure and axes with figure tightly surrounding image.
|
||||
|
||||
Unlike pyplot.figimage, this actually plots onto an axes object, which
|
||||
fills the figure. Plotting the image onto an axes allows for subsequent
|
||||
overlays of axes artists.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : array
|
||||
image to plot
|
||||
scale : float
|
||||
If scale is 1, the figure and axes have the same dimension as the
|
||||
image. Smaller values of `scale` will shrink the figure.
|
||||
dpi : int
|
||||
Dots per inch for figure. If None, use the default rcParam.
|
||||
"""
|
||||
dpi = dpi if dpi is not None else plt.rcParams['figure.dpi']
|
||||
kwargs.setdefault('interpolation', 'nearest')
|
||||
kwargs.setdefault('cmap', 'gray')
|
||||
|
||||
h, w, d = np.atleast_3d(image).shape
|
||||
figsize = np.array((w, h), dtype=float) / dpi * scale
|
||||
|
||||
fig, ax = plt.subplots(figsize=figsize, dpi=dpi)
|
||||
fig.subplots_adjust(left=0, bottom=0, right=1, top=1)
|
||||
|
||||
ax.set_axis_off()
|
||||
ax.imshow(image, **kwargs)
|
||||
return fig, ax
|
||||
|
||||
|
||||
class LinearColormap(LinearSegmentedColormap):
|
||||
"""LinearSegmentedColormap in which color varies smoothly.
|
||||
|
||||
@@ -124,14 +95,88 @@ class ClearColormap(LinearColormap):
|
||||
LinearColormap.__init__(self, name, cg_speq)
|
||||
|
||||
|
||||
class MatplotlibCanvas(FigureCanvasQTAgg):
|
||||
class FigureCanvas(FigureCanvasQTAgg):
|
||||
"""Canvas for displaying images."""
|
||||
def __init__(self, parent, figure, **kwargs):
|
||||
def __init__(self, figure, **kwargs):
|
||||
self.fig = figure
|
||||
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)
|
||||
|
||||
#TODO: Consider overriding Matplotlib key-event handling
|
||||
# def keyPressEvent(self, event):
|
||||
# # Override key events defined by Matplotlib
|
||||
# event.ignore()
|
||||
|
||||
# def keyReleaseEvent(self, event):
|
||||
# # Override key events defined by Matplotlib
|
||||
# event.ignore()
|
||||
|
||||
|
||||
def new_canvas(*args, **kwargs):
|
||||
"""Return a new figure canvas."""
|
||||
allnums = _pylab_helpers.Gcf.figs.keys()
|
||||
num = max(allnums) + 1 if allnums else 1
|
||||
|
||||
FigureClass = kwargs.pop('FigureClass', Figure)
|
||||
figure = FigureClass(*args, **kwargs)
|
||||
canvas = FigureCanvas(figure)
|
||||
fig_manager = FigureManagerQT(canvas, num)
|
||||
return fig_manager.canvas
|
||||
|
||||
|
||||
def new_plot(parent=None, subplot_kw=None, **fig_kw):
|
||||
"""Return new figure and axes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
parent : QtWidget
|
||||
Qt widget that displays the plot objects. If None, you must manually
|
||||
call ``canvas.setParent`` and pass the parent widget.
|
||||
subplot_kw : dict
|
||||
Keyword arguments passed ``matplotlib.figure.Figure.add_subplot``.
|
||||
fig_kw : dict
|
||||
Keyword arguments passed ``matplotlib.figure.Figure``.
|
||||
"""
|
||||
if subplot_kw is None:
|
||||
subplot_kw = {}
|
||||
canvas = new_canvas(**fig_kw)
|
||||
canvas.setParent(parent)
|
||||
|
||||
fig = canvas.figure
|
||||
ax = fig.add_subplot(1, 1, 1, **subplot_kw)
|
||||
return fig, ax
|
||||
|
||||
|
||||
def figimage(image, scale=1, dpi=None, **kwargs):
|
||||
"""Return figure and axes with figure tightly surrounding image.
|
||||
|
||||
Unlike pyplot.figimage, this actually plots onto an axes object, which
|
||||
fills the figure. Plotting the image onto an axes allows for subsequent
|
||||
overlays of axes artists.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : array
|
||||
image to plot
|
||||
scale : float
|
||||
If scale is 1, the figure and axes have the same dimension as the
|
||||
image. Smaller values of `scale` will shrink the figure.
|
||||
dpi : int
|
||||
Dots per inch for figure. If None, use the default rcParam.
|
||||
"""
|
||||
dpi = dpi if dpi is not None else mpl.rcParams['figure.dpi']
|
||||
kwargs.setdefault('interpolation', 'nearest')
|
||||
kwargs.setdefault('cmap', 'gray')
|
||||
|
||||
h, w, d = np.atleast_3d(image).shape
|
||||
figsize = np.array((w, h), dtype=float) / dpi * scale
|
||||
|
||||
fig, ax = new_plot(figsize=figsize, dpi=dpi)
|
||||
fig.subplots_adjust(left=0, bottom=0, right=1, top=1)
|
||||
|
||||
ax.set_axis_off()
|
||||
ax.imshow(image, **kwargs)
|
||||
return fig, ax
|
||||
|
||||
@@ -16,13 +16,6 @@ from ..widgets import Slider
|
||||
__all__ = ['ImageViewer', 'CollectionViewer']
|
||||
|
||||
|
||||
class ImageCanvas(utils.MatplotlibCanvas):
|
||||
"""Canvas for displaying images."""
|
||||
def __init__(self, parent, image, **kwargs):
|
||||
self.fig, self.ax = utils.figimage(image, **kwargs)
|
||||
super(ImageCanvas, self).__init__(parent, self.fig, **kwargs)
|
||||
|
||||
|
||||
class ImageViewer(QMainWindow):
|
||||
"""Viewer for displaying images.
|
||||
|
||||
@@ -72,9 +65,10 @@ class ImageViewer(QMainWindow):
|
||||
self.main_widget = QtGui.QWidget()
|
||||
self.setCentralWidget(self.main_widget)
|
||||
|
||||
self.canvas = ImageCanvas(self.main_widget, image)
|
||||
self.fig = self.canvas.fig
|
||||
self.ax = self.canvas.ax
|
||||
self.fig, self.ax = utils.figimage(image)
|
||||
self.canvas = self.fig.canvas
|
||||
self.canvas.setParent(self)
|
||||
|
||||
self.ax.autoscale(enable=False)
|
||||
|
||||
self._image_plot = self.ax.images[0]
|
||||
@@ -274,6 +268,8 @@ class CollectionViewer(ImageViewer):
|
||||
if 48 <= key < 58:
|
||||
index = 0.1 * int(key - 48) * self.num_images
|
||||
self.update_index('', index)
|
||||
event.accept()
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
Reference in New Issue
Block a user