Skip to content

Commit

Permalink
Switch to mpl #20839 rotation implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
dhomeier committed Dec 1, 2021
1 parent a96ef32 commit e41198d
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 69 deletions.
30 changes: 15 additions & 15 deletions regions/shapes/ellipse.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,20 +210,20 @@ def as_artist(self, origin=(0, 0), **kwargs):
**mpl_kwargs)

def _update_from_mpl_selector(self, *args, **kwargs):
# _rect_properties replace _rect_bbox in matplotlib#19864
# "Note that if rotation != 0, ``xmin, ymin`` are interpreted as the
# _rect_properties replace _rect_bbox in matplotlib#19864, unchanged in #20839.
# "Note that if rotation != 0, ``xmin, ymin`` are always interpreted as the
# lower corner, and ``xmax, ymax`` are calculated using only width and
# height assuming no rotation."
# height assuming no rotation (as specified for ``selector.extents``)."

self.center = PixCoord(*self._mpl_selector.center)
if hasattr(self._mpl_selector, '_rotation'):
x0, y0, self.width, self.height, rotation = self._mpl_selector._rect_properties
xmin, xmax, ymin, ymax = self._mpl_selector.extents
self.width = 2 * (self.center.x - xmin)
self.height = 2 * (self.center.y - ymin)
if hasattr(self._mpl_selector, 'rotation'):
rotation = self._mpl_selector.rotation
else:
xmin, xmax, ymin, ymax = self._mpl_selector.extents
self.width = 2 * (self.center.x - xmin)
self.height = 2 * (self.center.y - ymin)
rotation = 0
self.angle = rotation * u.radian
self.angle = rotation * u.deg

if getattr(self, '_mpl_selector_callback', None) is not None:
self._mpl_selector_callback(self)
Expand Down Expand Up @@ -267,13 +267,14 @@ def as_mpl_selector(self, ax, active=True, sync=True, callback=None,
``selector.set_active(True)`` or ``selector.set_active(False)``.
"""
from matplotlib.widgets import EllipseSelector
from matplotlib._version import version as _mpl_version

if hasattr(self, '_mpl_selector'):
raise Exception('Cannot attach more than one selector to a '
'region.')
raise Exception('Cannot attach more than one selector to a region.')

if self.angle.value != 0 and not hasattr(EllipseSelector, '_rotation'):
raise NotImplementedError('Cannot create matplotlib selector for rotated ellipse.')
if self.angle.value != 0 and not hasattr(EllipseSelector, 'rotation'):
raise NotImplementedError('Creating selectors for rotated shapes is not '
f'yet supported with matplotlib {_mpl_version}.')

if sync:
sync_callback = self._update_from_mpl_selector
Expand All @@ -293,8 +294,7 @@ def sync_callback(*args, **kwargs):
xy0[1], self.center.y + self.height / 2)

if self.angle.value != 0:
self._mpl_selector._set_corner_width_rotation(xy0, self.width, self.height,
self.angle.to_value('radian'))
self._mpl_selector.rotation = self.angle.to_value('deg')

self._mpl_selector.set_active(active)
self._mpl_selector_callback = callback
Expand Down
36 changes: 18 additions & 18 deletions regions/shapes/rectangle.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,20 +203,20 @@ def as_artist(self, origin=(0, 0), **kwargs):
angle=angle, **mpl_kwargs)

def _update_from_mpl_selector(self, *args, **kwargs):
# _rect_properties replace _rect_bbox in matplotlib#19864
# "Note that if rotation != 0, ``xmin, ymin`` are interpreted as the
# _rect_properties replace _rect_bbox in matplotlib#19864, unchanged in #20839.
# "Note that if rotation != 0, ``xmin, ymin`` are always interpreted as the
# lower corner, and ``xmax, ymax`` are calculated using only width and
# height assuming no rotation."
# height assuming no rotation (as specified for ``selector.extents``)."

self.center = PixCoord(*self._mpl_selector.center)
if hasattr(self._mpl_selector, '_rotation'):
x0, y0, self.width, self.height, rotation = self._mpl_selector._rect_properties
xmin, xmax, ymin, ymax = self._mpl_selector.extents
self.width = 2 * (self.center.x - xmin)
self.height = 2 * (self.center.y - ymin)
if hasattr(self._mpl_selector, 'rotation'):
rotation = self._mpl_selector.rotation
else:
xmin, xmax, ymin, ymax = self._mpl_selector.extents
self.width = 2 * (self.center.x - xmin)
self.height = 2 * (self.center.y - ymin)
rotation = 0
self.angle = rotation * u.radian
self.angle = rotation * u.deg

if getattr(self, '_mpl_selector_callback', None) is not None:
self._mpl_selector_callback(self)
Expand Down Expand Up @@ -260,13 +260,14 @@ def as_mpl_selector(self, ax, active=True, sync=True, callback=None,
``selector.set_active(True)`` or ``selector.set_active(False)``.
"""
from matplotlib.widgets import RectangleSelector
from matplotlib._version import version as _mpl_version

if hasattr(self, '_mpl_selector'):
raise Exception('Cannot attach more than one selector to a '
'region.')
raise Exception('Cannot attach more than one selector to a region.')

if self.angle.value != 0 and not hasattr(RectangleSelector, '_rotation'):
raise NotImplementedError('Cannot create matplotlib selector for rotated rectangle.')
if self.angle.value != 0 and not hasattr(RectangleSelector, 'rotation'):
raise NotImplementedError('Creating selectors for rotated shapes is not '
f'yet supported with matplotlib {_mpl_version}.')

if sync:
sync_callback = self._update_from_mpl_selector
Expand All @@ -281,13 +282,12 @@ def sync_callback(*args, **kwargs):
'linewidth': self.visual.get('linewidth', 1),
'linestyle': self.visual.get('linestyle', 'solid')})

xy0 = [self.center.x - self.width / 2, self.center.y - self.height / 2]
self._mpl_selector.extents = (xy0[0], self.center.x + self.width / 2,
xy0[1], self.center.y + self.height / 2)
dxy = [self.width / 2, self.height / 2]
self._mpl_selector.extents = (self.center.x - dxy[0], self.center.x + dxy[0],
self.center.y - dxy[1], self.center.y + dxy[1])

if self.angle.value != 0:
self._mpl_selector._set_corner_width_rotation(xy0, self.width, self.height,
self.angle.to_value('radian'))
self._mpl_selector.rotation = self.angle.to_value('deg')

self._mpl_selector.set_active(active)
self._mpl_selector_callback = callback
Expand Down
32 changes: 13 additions & 19 deletions regions/shapes/tests/test_ellipse.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,17 @@ def update_mask(reg):
# copy() below.
if not MATPLOTLIB_HAS_ROTATING_SELECTORS:
with pytest.raises(NotImplementedError,
match=('Cannot create matplotlib selector for rotated ellipse.')):
match='Creating selectors for rotated shapes is not yet supported'):
self.reg.as_mpl_selector(ax)

angle = 0 * u.deg
expected = [8.3, 4.9, 2.0, 1.0]
else:
angle = self.reg.angle
expected = [8.339773, 4.810942, 2.079545, 0.8218832]

if not sync:
expected = [3, 4, 4, 3]

region = self.reg.copy(angle=angle)

Expand All @@ -148,30 +153,19 @@ def update_mask(reg):

ax.figure.canvas.draw()

if sync:
assert_allclose(region.center.x, expected[0])
assert_allclose(region.center.y, expected[1])
assert_allclose(region.width, expected[2])
assert_allclose(region.height, expected[3])

assert_allclose(region.center.x, 8.3)
assert_allclose(region.center.y, 4.9)
assert_allclose(region.width, 2)
assert_allclose(region.height, 1)
if sync:
assert_quantity_allclose(region.angle, 0 * u.deg)

assert_equal(mask,
region.to_mask(mode='subpixels',
subpixels=10).to_image(data.shape))

assert_equal(mask, region.to_mask(mode='subpixels', subpixels=10).to_image(data.shape))
else:

assert_allclose(region.center.x, 3)
assert_allclose(region.center.y, 4)
assert_allclose(region.width, 4)
assert_allclose(region.height, 3)
assert_quantity_allclose(region.angle, angle)

assert_equal(mask, 0)

with pytest.raises(Exception, match=('Cannot attach more than one '
'selector to a region.')):
with pytest.raises(Exception, match='Cannot attach more than one selector to a region.'):
region.as_mpl_selector(ax)


Expand Down
29 changes: 13 additions & 16 deletions regions/shapes/tests/test_rectangle.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,17 @@ def update_mask(reg):
# call to copy() below.
if not MATPLOTLIB_HAS_ROTATING_SELECTORS:
with pytest.raises(NotImplementedError,
match=('Cannot create matplotlib selector for rotated rectangle.')):
match='Creating selectors for rotated shapes is not yet supported'):
self.reg.as_mpl_selector(ax)

angle = 0 * u.deg
expected = [8.3, 4.9, 2.0, 1.0]
else:
angle = self.reg.angle
expected = [8.339773, 4.810942, 2.079545, 0.8218832]

if not sync:
expected = [3, 4, 4, 3]

region = self.reg.copy(angle=angle)

Expand All @@ -151,27 +156,19 @@ def update_mask(reg):

ax.figure.canvas.draw()

assert_allclose(region.center.x, expected[0])
assert_allclose(region.center.y, expected[1])
assert_allclose(region.width, expected[2])
assert_allclose(region.height, expected[3])

if sync:
assert_allclose(region.center.x, 8.3)
assert_allclose(region.center.y, 4.9)
assert_allclose(region.width, 2)
assert_allclose(region.height, 1)
assert_quantity_allclose(region.angle, 0 * u.deg)

assert_equal(mask, region.to_mask(
mode='subpixels', subpixels=10).to_image(data.shape))

assert_equal(mask, region.to_mask(mode='subpixels', subpixels=10).to_image(data.shape))
else:
assert_allclose(region.center.x, 3)
assert_allclose(region.center.y, 4)
assert_allclose(region.width, 4)
assert_allclose(region.height, 3)
assert_quantity_allclose(region.angle, angle)

assert_equal(mask, 0)

with pytest.raises(Exception, match=('Cannot attach more than one '
'selector to a region.')):
with pytest.raises(Exception, match='Cannot attach more than one selector to a region.'):
region.as_mpl_selector(ax)


Expand Down
2 changes: 1 addition & 1 deletion regions/shapes/tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import matplotlib # noqa
HAS_MATPLOTLIB = True
import matplotlib.widgets
if hasattr(matplotlib.widgets.EllipseSelector, '_rotation'):
if hasattr(matplotlib.widgets.EllipseSelector, 'rotation'):
MATPLOTLIB_HAS_ROTATING_SELECTORS = True
except ImportError:
HAS_MATPLOTLIB = False

0 comments on commit e41198d

Please sign in to comment.