Skip to content

Commit 6a74631

Browse files
authored
Merge pull request matplotlib#21977 from dstansby/patch-helpers
Add corner coordinate helper methods to Ellipse/Rectangle
2 parents 37c9b04 + 2f334c8 commit 6a74631

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

lib/matplotlib/patches.py

+22
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,18 @@ def get_xy(self):
802802
"""Return the left and bottom coords of the rectangle as a tuple."""
803803
return self._x0, self._y0
804804

805+
def get_corners(self):
806+
"""
807+
Return the corners of the rectangle, moving anti-clockwise from
808+
(x0, y0).
809+
"""
810+
return self.get_patch_transform().transform(
811+
[(0, 0), (1, 0), (1, 1), (0, 1)])
812+
813+
def get_center(self):
814+
"""Return the centre of the rectangle."""
815+
return self.get_patch_transform().transform((0.5, 0.5))
816+
805817
def get_width(self):
806818
"""Return the width of the rectangle."""
807819
return self._width
@@ -1653,6 +1665,16 @@ def get_angle(self):
16531665

16541666
angle = property(get_angle, set_angle)
16551667

1668+
def get_corners(self):
1669+
"""
1670+
Return the corners of the ellipse bounding box.
1671+
1672+
The bounding box orientation is moving anti-clockwise from the
1673+
lower left corner defined before rotation.
1674+
"""
1675+
return self.get_patch_transform().transform(
1676+
[(-1, -1), (1, -1), (1, 1), (-1, 1)])
1677+
16561678

16571679
class Annulus(Patch):
16581680
"""

lib/matplotlib/tests/test_patches.py

+49-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import pytest
77

88
import matplotlib as mpl
9-
from matplotlib.patches import (Annulus, Patch, Polygon, Rectangle,
9+
from matplotlib.patches import (Annulus, Ellipse, Patch, Polygon, Rectangle,
1010
FancyArrowPatch)
1111
from matplotlib.testing.decorators import image_comparison, check_figures_equal
1212
from matplotlib.transforms import Bbox
@@ -54,6 +54,54 @@ def test_Polygon_close():
5454
assert_array_equal(p.get_xy(), xyclosed)
5555

5656

57+
def test_corner_center():
58+
loc = [10, 20]
59+
width = 1
60+
height = 2
61+
62+
# Rectangle
63+
# No rotation
64+
corners = ((10, 20), (11, 20), (11, 22), (10, 22))
65+
rect = Rectangle(loc, width, height)
66+
assert_array_equal(rect.get_corners(), corners)
67+
assert_array_equal(rect.get_center(), (10.5, 21))
68+
69+
# 90 deg rotation
70+
corners_rot = ((10, 20), (10, 21), (8, 21), (8, 20))
71+
rect.set_angle(90)
72+
assert_array_equal(rect.get_corners(), corners_rot)
73+
assert_array_equal(rect.get_center(), (9, 20.5))
74+
75+
# Rotation not a multiple of 90 deg
76+
theta = 33
77+
t = mtransforms.Affine2D().rotate_around(*loc, np.deg2rad(theta))
78+
corners_rot = t.transform(corners)
79+
rect.set_angle(theta)
80+
assert_almost_equal(rect.get_corners(), corners_rot)
81+
82+
# Ellipse
83+
loc = [loc[0] + width / 2,
84+
loc[1] + height / 2]
85+
ellipse = Ellipse(loc, width, height)
86+
87+
# No rotation
88+
assert_array_equal(ellipse.get_corners(), corners)
89+
90+
# 90 deg rotation
91+
corners_rot = ((11.5, 20.5), (11.5, 21.5), (9.5, 21.5), (9.5, 20.5))
92+
ellipse.set_angle(90)
93+
assert_array_equal(ellipse.get_corners(), corners_rot)
94+
# Rotation shouldn't change ellipse center
95+
assert_array_equal(ellipse.get_center(), loc)
96+
97+
# Rotation not a multiple of 90 deg
98+
theta = 33
99+
t = mtransforms.Affine2D().rotate_around(*loc, np.deg2rad(theta))
100+
corners_rot = t.transform(corners)
101+
ellipse.set_angle(theta)
102+
assert_almost_equal(ellipse.get_corners(), corners_rot)
103+
104+
57105
def test_rotate_rect():
58106
loc = np.asarray([1.0, 2.0])
59107
width = 2

0 commit comments

Comments
 (0)