Skip to content

Commit e41198d

Browse files
committed
Switch to mpl #20839 rotation implementation
1 parent a96ef32 commit e41198d

File tree

5 files changed

+60
-69
lines changed

5 files changed

+60
-69
lines changed

regions/shapes/ellipse.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -210,20 +210,20 @@ def as_artist(self, origin=(0, 0), **kwargs):
210210
**mpl_kwargs)
211211

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

218218
self.center = PixCoord(*self._mpl_selector.center)
219-
if hasattr(self._mpl_selector, '_rotation'):
220-
x0, y0, self.width, self.height, rotation = self._mpl_selector._rect_properties
219+
xmin, xmax, ymin, ymax = self._mpl_selector.extents
220+
self.width = 2 * (self.center.x - xmin)
221+
self.height = 2 * (self.center.y - ymin)
222+
if hasattr(self._mpl_selector, 'rotation'):
223+
rotation = self._mpl_selector.rotation
221224
else:
222-
xmin, xmax, ymin, ymax = self._mpl_selector.extents
223-
self.width = 2 * (self.center.x - xmin)
224-
self.height = 2 * (self.center.y - ymin)
225225
rotation = 0
226-
self.angle = rotation * u.radian
226+
self.angle = rotation * u.deg
227227

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

271272
if hasattr(self, '_mpl_selector'):
272-
raise Exception('Cannot attach more than one selector to a '
273-
'region.')
273+
raise Exception('Cannot attach more than one selector to a region.')
274274

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

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

295296
if self.angle.value != 0:
296-
self._mpl_selector._set_corner_width_rotation(xy0, self.width, self.height,
297-
self.angle.to_value('radian'))
297+
self._mpl_selector.rotation = self.angle.to_value('deg')
298298

299299
self._mpl_selector.set_active(active)
300300
self._mpl_selector_callback = callback

regions/shapes/rectangle.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -203,20 +203,20 @@ def as_artist(self, origin=(0, 0), **kwargs):
203203
angle=angle, **mpl_kwargs)
204204

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

211211
self.center = PixCoord(*self._mpl_selector.center)
212-
if hasattr(self._mpl_selector, '_rotation'):
213-
x0, y0, self.width, self.height, rotation = self._mpl_selector._rect_properties
212+
xmin, xmax, ymin, ymax = self._mpl_selector.extents
213+
self.width = 2 * (self.center.x - xmin)
214+
self.height = 2 * (self.center.y - ymin)
215+
if hasattr(self._mpl_selector, 'rotation'):
216+
rotation = self._mpl_selector.rotation
214217
else:
215-
xmin, xmax, ymin, ymax = self._mpl_selector.extents
216-
self.width = 2 * (self.center.x - xmin)
217-
self.height = 2 * (self.center.y - ymin)
218218
rotation = 0
219-
self.angle = rotation * u.radian
219+
self.angle = rotation * u.deg
220220

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

264265
if hasattr(self, '_mpl_selector'):
265-
raise Exception('Cannot attach more than one selector to a '
266-
'region.')
266+
raise Exception('Cannot attach more than one selector to a region.')
267267

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

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

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

288289
if self.angle.value != 0:
289-
self._mpl_selector._set_corner_width_rotation(xy0, self.width, self.height,
290-
self.angle.to_value('radian'))
290+
self._mpl_selector.rotation = self.angle.to_value('deg')
291291

292292
self._mpl_selector.set_active(active)
293293
self._mpl_selector_callback = callback

regions/shapes/tests/test_ellipse.py

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,17 @@ def update_mask(reg):
117117
# copy() below.
118118
if not MATPLOTLIB_HAS_ROTATING_SELECTORS:
119119
with pytest.raises(NotImplementedError,
120-
match=('Cannot create matplotlib selector for rotated ellipse.')):
120+
match='Creating selectors for rotated shapes is not yet supported'):
121121
self.reg.as_mpl_selector(ax)
122122

123123
angle = 0 * u.deg
124+
expected = [8.3, 4.9, 2.0, 1.0]
124125
else:
125126
angle = self.reg.angle
127+
expected = [8.339773, 4.810942, 2.079545, 0.8218832]
128+
129+
if not sync:
130+
expected = [3, 4, 4, 3]
126131

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

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

149154
ax.figure.canvas.draw()
150155

151-
if sync:
156+
assert_allclose(region.center.x, expected[0])
157+
assert_allclose(region.center.y, expected[1])
158+
assert_allclose(region.width, expected[2])
159+
assert_allclose(region.height, expected[3])
152160

153-
assert_allclose(region.center.x, 8.3)
154-
assert_allclose(region.center.y, 4.9)
155-
assert_allclose(region.width, 2)
156-
assert_allclose(region.height, 1)
161+
if sync:
157162
assert_quantity_allclose(region.angle, 0 * u.deg)
158-
159-
assert_equal(mask,
160-
region.to_mask(mode='subpixels',
161-
subpixels=10).to_image(data.shape))
162-
163+
assert_equal(mask, region.to_mask(mode='subpixels', subpixels=10).to_image(data.shape))
163164
else:
164-
165-
assert_allclose(region.center.x, 3)
166-
assert_allclose(region.center.y, 4)
167-
assert_allclose(region.width, 4)
168-
assert_allclose(region.height, 3)
169165
assert_quantity_allclose(region.angle, angle)
170-
171166
assert_equal(mask, 0)
172167

173-
with pytest.raises(Exception, match=('Cannot attach more than one '
174-
'selector to a region.')):
168+
with pytest.raises(Exception, match='Cannot attach more than one selector to a region.'):
175169
region.as_mpl_selector(ax)
176170

177171

regions/shapes/tests/test_rectangle.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,17 @@ def update_mask(reg):
120120
# call to copy() below.
121121
if not MATPLOTLIB_HAS_ROTATING_SELECTORS:
122122
with pytest.raises(NotImplementedError,
123-
match=('Cannot create matplotlib selector for rotated rectangle.')):
123+
match='Creating selectors for rotated shapes is not yet supported'):
124124
self.reg.as_mpl_selector(ax)
125125

126126
angle = 0 * u.deg
127+
expected = [8.3, 4.9, 2.0, 1.0]
127128
else:
128129
angle = self.reg.angle
130+
expected = [8.339773, 4.810942, 2.079545, 0.8218832]
131+
132+
if not sync:
133+
expected = [3, 4, 4, 3]
129134

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

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

152157
ax.figure.canvas.draw()
153158

159+
assert_allclose(region.center.x, expected[0])
160+
assert_allclose(region.center.y, expected[1])
161+
assert_allclose(region.width, expected[2])
162+
assert_allclose(region.height, expected[3])
163+
154164
if sync:
155-
assert_allclose(region.center.x, 8.3)
156-
assert_allclose(region.center.y, 4.9)
157-
assert_allclose(region.width, 2)
158-
assert_allclose(region.height, 1)
159165
assert_quantity_allclose(region.angle, 0 * u.deg)
160-
161-
assert_equal(mask, region.to_mask(
162-
mode='subpixels', subpixels=10).to_image(data.shape))
163-
166+
assert_equal(mask, region.to_mask(mode='subpixels', subpixels=10).to_image(data.shape))
164167
else:
165-
assert_allclose(region.center.x, 3)
166-
assert_allclose(region.center.y, 4)
167-
assert_allclose(region.width, 4)
168-
assert_allclose(region.height, 3)
169168
assert_quantity_allclose(region.angle, angle)
170-
171169
assert_equal(mask, 0)
172170

173-
with pytest.raises(Exception, match=('Cannot attach more than one '
174-
'selector to a region.')):
171+
with pytest.raises(Exception, match='Cannot attach more than one selector to a region.'):
175172
region.as_mpl_selector(ax)
176173

177174

regions/shapes/tests/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import matplotlib # noqa
66
HAS_MATPLOTLIB = True
77
import matplotlib.widgets
8-
if hasattr(matplotlib.widgets.EllipseSelector, '_rotation'):
8+
if hasattr(matplotlib.widgets.EllipseSelector, 'rotation'):
99
MATPLOTLIB_HAS_ROTATING_SELECTORS = True
1010
except ImportError:
1111
HAS_MATPLOTLIB = False

0 commit comments

Comments
 (0)