Source code for straditize.magnifier

# -*- coding: utf-8 -*-
"""Magnifier class for an image

**Disclaimer**

Copyright (C) 2018-2019  Philipp S. Sommer

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>."""
import numpy as np
from matplotlib.widgets import Slider
import matplotlib.colorbar as mcbar
from matplotlib.axes import SubplotBase


[docs]class Magnifier(object): """A magnification of a matplotlib axes It zooms into the region where the mouse pointer is, when it enters the source axes. The appearance of the plot is defined by the :meth:`make_plot` method.""" @property def dx(self): val = self.slider.val ret = np.abs(np.diff(self.ax_src.get_xlim())) * (100 - val) / 200. return -ret if self.ax.xaxis_inverted() else ret @property def dy(self): val = self.slider.val ret = np.abs(np.diff(self.ax_src.get_ylim())) * (100 - val) / 200. return -ret if self.ax.yaxis_inverted() else ret cid_enter = None cid_motion = None cid_leave = None ax = None def __init__(self, ax_src, ax=None, *args, **kwargs): self.ax_src = ax_src if ax is None: import matplotlib.pyplot as plt fig, ax = plt.subplots() fig.canvas.set_window_title( 'Figure %i: Zoom of figure %i' % (fig.number, ax_src.figure.number)) self.ax = ax self.point = ax.plot( [np.mean(ax.get_xlim())], [np.mean(ax.get_ylim())], 'ro', visible=False, zorder=10)[0] self.make_plot(*args, **kwargs) self.enable_zoom() if isinstance(ax, SubplotBase): slider_ax, kw = mcbar.make_axes_gridspec( ax, orientation='horizontal', location='bottom') else: slider_ax, kw = mcbar.make_axes( ax, position='bottom', orientation='horizontal') slider_ax.set_aspect('auto') slider_ax._hold = True self.slider = Slider(slider_ax, 'Zoom', 0, 99.5, valfmt='%1.2g %%') self.slider.set_val(90) self.slider.on_changed(self.adjust_limits) self.adjust_limits(90)
[docs] def adjust_limits(self, zoom_val): x = np.mean(self.ax.get_xlim()) y = np.mean(self.ax.get_ylim()) dx = self.dx dy = self.dy self.ax.set_xlim(x - dx, x + dx) self.ax.set_ylim(y - dy, y + dy) self.ax.figure.canvas.draw()
[docs] def make_plot(self, image, *args, **kwargs): self.plot_image = self.ax.imshow(image, *args, **kwargs)
[docs] def onmotion(self, event): if event.inaxes != self.ax_src or self.ax is None: return x, y = event.xdata, event.ydata dx = self.dx dy = self.dy ax = self.ax xmin, xmax = x - dx, x + dx ymin, ymax = y - dy, y + dy ax.set_xlim(xmin, xmax) ax.set_ylim(ymin, ymax) self.point.set_xdata([x]) self.point.set_ydata([y]) self.point.set_visible(True) ax.figure.canvas.draw()
[docs] def onenter(self, event): if event.inaxes != self.ax_src or self.ax is None: return canvas = self.ax_src.figure.canvas canvas.mpl_disconnect(self.cid_enter) self.cid_leave = canvas.mpl_connect('axes_leave_event', self.onleave) self.cid_motion = canvas.mpl_connect('motion_notify_event', self.onmotion)
[docs] def close(self): """Close the magnifier and the associated plots""" import matplotlib.pyplot as plt try: self.plot_image.remove() except (AttributeError, ValueError): pass try: self.point.remove() except (AttributeError, ValueError): pass self.disconnect() fig = self.ax.figure fig.delaxes(self.ax) self.slider.disconnect_events() fig.delaxes(self.slider.ax) plt.close(self.ax.figure) del self.plot_image, self.ax, self.ax_src, self.slider
[docs] def onleave(self, event): canvas = self.ax_src.figure.canvas canvas.mpl_disconnect(self.cid_leave) canvas.mpl_disconnect(self.cid_motion) self.enable_zoom() self.point.set_visible(False) if self.ax is not None: self.ax.figure.canvas.draw()
[docs] def enable_zoom(self): self.cid_enter = self.ax_src.figure.canvas.mpl_connect( 'axes_enter_event', self.onenter)
[docs] def disconnect(self): canvas = self.ax_src.figure.canvas for cid in [self.cid_enter, self.cid_leave, self.cid_motion]: if cid is not None: canvas.mpl_disconnect(cid)