Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c3a2794

Browse files
authored
Merge pull request #25779 from photoniker/add_Ellipse_Arrow_Example
Adding ellipse_arrow.py example and closes #25477
2 parents 5f29763 + 896a775 commit c3a2794

File tree

5 files changed

+146
-0
lines changed

5 files changed

+146
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
``Ellipse.get_vertices()``, ``Ellipse.get_co_vertices()``
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
These methods return the coordinates of ellipse vertices of
4+
major and minor axis. Additionally, an example gallery demo is added which
5+
shows how to add an arrow to an ellipse showing a clockwise or counter-clockwise
6+
rotation of the ellipse. To place the arrow exactly on the ellipse,
7+
the coordinates of the vertices are used.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""
2+
===================================
3+
Ellipse with orientation arrow demo
4+
===================================
5+
6+
This demo shows how to draw an ellipse with
7+
an orientation arrow (clockwise or counterclockwise).
8+
Compare this to the :doc:`Ellipse collection example
9+
</gallery/shapes_and_collections/ellipse_collection>`.
10+
"""
11+
12+
import matplotlib.pyplot as plt
13+
14+
from matplotlib.markers import MarkerStyle
15+
from matplotlib.patches import Ellipse
16+
from matplotlib.transforms import Affine2D
17+
18+
# Create a figure and axis
19+
fig, ax = plt.subplots(subplot_kw={"aspect": "equal"})
20+
21+
ellipse = Ellipse(
22+
xy=(2, 4),
23+
width=30,
24+
height=20,
25+
angle=35,
26+
facecolor="none",
27+
edgecolor="b"
28+
)
29+
ax.add_patch(ellipse)
30+
31+
# Plot an arrow marker at the end point of minor axis
32+
vertices = ellipse.get_co_vertices()
33+
t = Affine2D().rotate_deg(ellipse.angle)
34+
ax.plot(
35+
vertices[0][0],
36+
vertices[0][1],
37+
color="b",
38+
marker=MarkerStyle(">", "full", t),
39+
markersize=10
40+
)
41+
# Note: To reverse the orientation arrow, switch the marker type from > to <.
42+
43+
plt.show()
44+
45+
# %%
46+
#
47+
# .. admonition:: References
48+
#
49+
# The use of the following functions, methods, classes and modules is shown
50+
# in this example:
51+
#
52+
# - `matplotlib.patches`
53+
# - `matplotlib.patches.Ellipse`

lib/matplotlib/patches.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1662,6 +1662,37 @@ def get_corners(self):
16621662
return self.get_patch_transform().transform(
16631663
[(-1, -1), (1, -1), (1, 1), (-1, 1)])
16641664

1665+
def _calculate_length_between_points(self, x0, y0, x1, y1):
1666+
return np.sqrt((x1 - x0)**2 + (y1 - y0)**2)
1667+
1668+
def get_vertices(self):
1669+
"""
1670+
Return the vertices coordinates of the ellipse.
1671+
1672+
The definition can be found `here <https://en.wikipedia.org/wiki/Ellipse>`_
1673+
1674+
.. versionadded:: 3.8
1675+
"""
1676+
if self.width < self.height:
1677+
ret = self.get_patch_transform().transform([(0, 1), (0, -1)])
1678+
else:
1679+
ret = self.get_patch_transform().transform([(1, 0), (-1, 0)])
1680+
return [tuple(x) for x in ret]
1681+
1682+
def get_co_vertices(self):
1683+
"""
1684+
Return the co-vertices coordinates of the ellipse.
1685+
1686+
The definition can be found `here <https://en.wikipedia.org/wiki/Ellipse>`_
1687+
1688+
.. versionadded:: 3.8
1689+
"""
1690+
if self.width < self.height:
1691+
ret = self.get_patch_transform().transform([(1, 0), (-1, 0)])
1692+
else:
1693+
ret = self.get_patch_transform().transform([(0, 1), (0, -1)])
1694+
return [tuple(x) for x in ret]
1695+
16651696

16661697
class Annulus(Patch):
16671698
"""

lib/matplotlib/patches.pyi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ class Ellipse(Patch):
249249

250250
def get_corners(self) -> np.ndarray: ...
251251

252+
def get_vertices(self) -> list[tuple[float, float]]: ...
253+
def get_co_vertices(self) -> list[tuple[float, float]]: ...
254+
255+
252256
class Annulus(Patch):
253257
a: float
254258
b: float

lib/matplotlib/tests/test_patches.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,57 @@ def test_corner_center():
104104
assert_almost_equal(ellipse.get_corners(), corners_rot)
105105

106106

107+
def test_ellipse_vertices():
108+
# expect 0 for 0 ellipse width, height
109+
ellipse = Ellipse(xy=(0, 0), width=0, height=0, angle=0)
110+
assert_almost_equal(
111+
ellipse.get_vertices(),
112+
[(0.0, 0.0), (0.0, 0.0)],
113+
)
114+
assert_almost_equal(
115+
ellipse.get_co_vertices(),
116+
[(0.0, 0.0), (0.0, 0.0)],
117+
)
118+
119+
ellipse = Ellipse(xy=(0, 0), width=2, height=1, angle=30)
120+
assert_almost_equal(
121+
ellipse.get_vertices(),
122+
[
123+
(
124+
ellipse.center[0] + ellipse.width / 4 * np.sqrt(3),
125+
ellipse.center[1] + ellipse.width / 4,
126+
),
127+
(
128+
ellipse.center[0] - ellipse.width / 4 * np.sqrt(3),
129+
ellipse.center[1] - ellipse.width / 4,
130+
),
131+
],
132+
)
133+
assert_almost_equal(
134+
ellipse.get_co_vertices(),
135+
[
136+
(
137+
ellipse.center[0] - ellipse.height / 4,
138+
ellipse.center[1] + ellipse.height / 4 * np.sqrt(3),
139+
),
140+
(
141+
ellipse.center[0] + ellipse.height / 4,
142+
ellipse.center[1] - ellipse.height / 4 * np.sqrt(3),
143+
),
144+
],
145+
)
146+
v1, v2 = np.array(ellipse.get_vertices())
147+
np.testing.assert_almost_equal((v1 + v2) / 2, ellipse.center)
148+
v1, v2 = np.array(ellipse.get_co_vertices())
149+
np.testing.assert_almost_equal((v1 + v2) / 2, ellipse.center)
150+
151+
ellipse = Ellipse(xy=(2.252, -10.859), width=2.265, height=1.98, angle=68.78)
152+
v1, v2 = np.array(ellipse.get_vertices())
153+
np.testing.assert_almost_equal((v1 + v2) / 2, ellipse.center)
154+
v1, v2 = np.array(ellipse.get_co_vertices())
155+
np.testing.assert_almost_equal((v1 + v2) / 2, ellipse.center)
156+
157+
107158
def test_rotate_rect():
108159
loc = np.asarray([1.0, 2.0])
109160
width = 2

0 commit comments

Comments
 (0)