Skip to content

Commit 303f957

Browse files
author
Johann Krauter
committed
added get_vertices and get_co_vertices methods the Ellipse
1 parent e12a72a commit 303f957

File tree

3 files changed

+106
-65
lines changed

3 files changed

+106
-65
lines changed

galleries/examples/shapes_and_collections/ellipse_arrow.py

Lines changed: 60 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
22
===================================
3-
Ellipse with orientation arrow Demo
3+
Ellipse with orientation arrow demo
44
===================================
55
66
This demo shows how to draw an ellipse with
@@ -9,98 +9,93 @@
99
</gallery/shapes_and_collections/ellipse_collection>`.
1010
"""
1111

12-
from typing import Tuple
13-
1412
import matplotlib.pyplot as plt
15-
import numpy as np
16-
1713
from matplotlib.markers import MarkerStyle
1814
from matplotlib.patches import Ellipse
1915
from matplotlib.transforms import Affine2D
2016

21-
# %%
22-
#
23-
# A method to calculate the end points of the ellipse major, minor axis
24-
# """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
25-
#
26-
# Calculates the minor axis and major axis end points of the ellipse.
27-
# It needs the ellipse parameter like width, height, angle.
28-
# The output are 2 lists of 2 xy coordinates
29-
# (minor((x0, y0), (x1, y1)), major((x0, y0), (x1, y1))).
30-
31-
32-
def getMinorMajor(ellipse: Ellipse) -> Tuple[list, list]:
33-
"""
34-
Calculates the end points of minor and major axis of an ellipse.
35-
36-
Parameters
37-
----------
38-
ellipse : ~matplotlib.patches.Ellipse
39-
Ellipse patch.
40-
41-
Returns
42-
-------
43-
~typing.Tuple[list, list]
44-
"""
45-
# Calculate the endpoints of the minor axis
46-
x0_minor = ellipse.center[0] - ellipse.height / 2 * np.sin(
47-
np.deg2rad(ellipse.angle)
48-
)
49-
y0_minor = ellipse.center[1] + ellipse.height / 2 * np.cos(
50-
np.deg2rad(ellipse.angle)
51-
)
52-
x1_minor = ellipse.center[0] + ellipse.height / 2 * np.sin(
53-
np.deg2rad(ellipse.angle)
54-
)
55-
y1_minor = ellipse.center[1] - ellipse.height / 2 * np.cos(
56-
np.deg2rad(ellipse.angle)
57-
)
58-
59-
# Calculate the endpoints of the major axis
60-
x0_major = ellipse.center[0] - ellipse.width / 2 * np.cos(np.deg2rad(ellipse.angle))
61-
y0_major = ellipse.center[1] - ellipse.width / 2 * np.sin(np.deg2rad(ellipse.angle))
62-
x1_major = ellipse.center[0] + ellipse.width / 2 * np.cos(np.deg2rad(ellipse.angle))
63-
y1_major = ellipse.center[1] + ellipse.width / 2 * np.sin(np.deg2rad(ellipse.angle))
64-
return [(x0_minor, y0_minor), (x1_minor, y1_minor)], [
65-
(x0_major, y0_major),
66-
(x1_major, y1_major),
67-
]
68-
69-
70-
# Define the ellipse
17+
18+
# Create a figure and axis
19+
fig, ax = plt.subplots(1, 1, subplot_kw={"aspect": "equal"})
20+
21+
# Define an ellipse clockwise
7122
center = (2, 4)
7223
width = 30
7324
height = 20
7425
angle = 35
75-
ellipse = Ellipse(
26+
ellipse_clockwise = Ellipse(
7627
xy=center,
7728
width=width,
7829
height=height,
7930
angle=angle,
8031
facecolor="none",
8132
edgecolor="b",
33+
label="clockwise"
8234
)
8335

84-
minor, major = getMinorMajor(ellipse)
85-
86-
# Create a figure and axis
87-
fig, ax = plt.subplots(1, 1, subplot_kw={"aspect": "equal"})
36+
# Get position of vertex for arrow marker
37+
vertices = ellipse_clockwise.get_co_vertices()
8838

8939
# Add the ellipse patch to the axis
90-
ax.add_patch(ellipse)
40+
ax.add_patch(ellipse_clockwise)
9141

9242
# Plot a arrow marker at the end point of minor axis
93-
t = Affine2D().rotate_deg(angle)
43+
t = Affine2D().rotate_deg(ellipse_clockwise.angle)
9444
ax.plot(
95-
minor[0][0],
96-
minor[0][1],
45+
vertices[0][0],
46+
vertices[0][1],
9747
color="b",
9848
marker=MarkerStyle(">", "full", t),
99-
markersize=10,
49+
markersize=10
10050
)
10151

52+
# Define an second ellipse counterclockwise
53+
center = (2, 4)
54+
width = 30
55+
height = 15
56+
angle = -20
57+
ellipse_counterclockwise = Ellipse(
58+
xy=center,
59+
width=width,
60+
height=height,
61+
angle=angle,
62+
facecolor="none",
63+
edgecolor="g",
64+
label="counterclockwise"
65+
)
66+
67+
# Add the ellipse patch to the axis
68+
ax.add_patch(ellipse_counterclockwise)
69+
70+
# Get position of vertex for arrow marker
71+
vertices = ellipse_counterclockwise.get_co_vertices()
72+
73+
# Plot a arrow marker at the end point of minor axis
74+
t = Affine2D().rotate_deg(ellipse_counterclockwise.angle)
75+
ax.plot(
76+
vertices[0][0],
77+
vertices[0][1],
78+
color="g",
79+
marker=MarkerStyle("<", "full", t),
80+
markersize=10
81+
)
82+
83+
84+
plt.legend()
10285
plt.show()
10386

87+
center = (2, 4)
88+
width = 30
89+
height = 20
90+
angle = 35
91+
ellipse = Ellipse(
92+
xy=center,
93+
width=width,
94+
height=height,
95+
angle=angle
96+
)
97+
print(ellipse.get_vertices())
98+
print(ellipse.get_co_vertices())
10499

105100
# %%
106101
#

lib/matplotlib/patches.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,6 +1654,30 @@ def get_corners(self):
16541654
return self.get_patch_transform().transform(
16551655
[(-1, -1), (1, -1), (1, 1), (-1, 1)])
16561656

1657+
def get_vertices(self):
1658+
"""
1659+
Return the left and right vertex coordinates of the ellipse.
1660+
1661+
The definition can be found `here<https://en.wikipedia.org/wiki/Ellipse>`_
1662+
"""
1663+
x0 = self._center[0] - self._width / 2 * np.cos(np.deg2rad(self._angle))
1664+
y0 = self._center[1] - self._width / 2 * np.sin(np.deg2rad(self._angle))
1665+
x1 = self._center[0] + self._width / 2 * np.cos(np.deg2rad(self._angle))
1666+
y1 = self._center[1] + self._width / 2 * np.sin(np.deg2rad(self._angle))
1667+
return [(x0, y0), (x1, y1)]
1668+
1669+
def get_co_vertices(self):
1670+
"""
1671+
Return the left and right co-vertex coordinates of the ellipse.
1672+
1673+
The definition can be found `here<https://en.wikipedia.org/wiki/Ellipse>`_
1674+
"""
1675+
x0 = self._center[0] - self._height / 2 * np.sin(np.deg2rad(self._angle))
1676+
y0 = self._center[1] + self._height / 2 * np.cos(np.deg2rad(self._angle))
1677+
x1 = self._center[0] + self._height / 2 * np.sin(np.deg2rad(self._angle))
1678+
y1 = self._center[1] - self._height / 2 * np.cos(np.deg2rad(self._angle))
1679+
return [(x0, y0), (x1, y1)]
1680+
16571681

16581682
class Annulus(Patch):
16591683
"""

lib/matplotlib/tests/test_patches.py

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

106106

107+
def test_ellipse_vertices():
108+
center = (2, 4)
109+
width = 30
110+
height = 20
111+
angle = 35
112+
ellipse = Ellipse(xy=center, width=width, height=height, angle=angle)
113+
assert_almost_equal(
114+
ellipse.get_vertices(),
115+
[
116+
(-10.287280664334878, -4.60364654526569),
117+
(14.287280664334878, 12.60364654526569),
118+
],
119+
)
120+
assert_almost_equal(
121+
ellipse.get_co_vertices(),
122+
[
123+
(-3.7357643635104605, 12.191520442889917),
124+
(7.7357643635104605, -4.191520442889917),
125+
],
126+
)
127+
128+
107129
def test_rotate_rect():
108130
loc = np.asarray([1.0, 2.0])
109131
width = 2

0 commit comments

Comments
 (0)