diff --git a/doc/users/next_whats_new/get_vertices_co_vertices.rst b/doc/users/next_whats_new/get_vertices_co_vertices.rst new file mode 100644 index 000000000000..98254a82ce63 --- /dev/null +++ b/doc/users/next_whats_new/get_vertices_co_vertices.rst @@ -0,0 +1,7 @@ +``Ellipse.get_vertices()``, ``Ellipse.get_co_vertices()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These methods return the coordinates of ellipse vertices of +major and minor axis. Additionally, an example gallery demo is added which +shows how to add an arrow to an ellipse showing a clockwise or counter-clockwise +rotation of the ellipse. To place the arrow exactly on the ellipse, +the coordinates of the vertices are used. diff --git a/galleries/examples/shapes_and_collections/ellipse_arrow.py b/galleries/examples/shapes_and_collections/ellipse_arrow.py new file mode 100644 index 000000000000..4bcdc016faa6 --- /dev/null +++ b/galleries/examples/shapes_and_collections/ellipse_arrow.py @@ -0,0 +1,53 @@ +""" +=================================== +Ellipse with orientation arrow demo +=================================== + +This demo shows how to draw an ellipse with +an orientation arrow (clockwise or counterclockwise). +Compare this to the :doc:`Ellipse collection example +`. +""" + +import matplotlib.pyplot as plt + +from matplotlib.markers import MarkerStyle +from matplotlib.patches import Ellipse +from matplotlib.transforms import Affine2D + +# Create a figure and axis +fig, ax = plt.subplots(subplot_kw={"aspect": "equal"}) + +ellipse = Ellipse( + xy=(2, 4), + width=30, + height=20, + angle=35, + facecolor="none", + edgecolor="b" +) +ax.add_patch(ellipse) + +# Plot an arrow marker at the end point of minor axis +vertices = ellipse.get_co_vertices() +t = Affine2D().rotate_deg(ellipse.angle) +ax.plot( + vertices[0][0], + vertices[0][1], + color="b", + marker=MarkerStyle(">", "full", t), + markersize=10 +) +# Note: To reverse the orientation arrow, switch the marker type from > to <. + +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.patches` +# - `matplotlib.patches.Ellipse` diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 245bb7b777c8..ecf03ca4051b 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -1654,6 +1654,37 @@ def get_corners(self): return self.get_patch_transform().transform( [(-1, -1), (1, -1), (1, 1), (-1, 1)]) + def _calculate_length_between_points(self, x0, y0, x1, y1): + return np.sqrt((x1 - x0)**2 + (y1 - y0)**2) + + def get_vertices(self): + """ + Return the vertices coordinates of the ellipse. + + The definition can be found `here `_ + + .. versionadded:: 3.8 + """ + if self.width < self.height: + ret = self.get_patch_transform().transform([(0, 1), (0, -1)]) + else: + ret = self.get_patch_transform().transform([(1, 0), (-1, 0)]) + return [tuple(x) for x in ret] + + def get_co_vertices(self): + """ + Return the co-vertices coordinates of the ellipse. + + The definition can be found `here `_ + + .. versionadded:: 3.8 + """ + if self.width < self.height: + ret = self.get_patch_transform().transform([(1, 0), (-1, 0)]) + else: + ret = self.get_patch_transform().transform([(0, 1), (0, -1)]) + return [tuple(x) for x in ret] + class Annulus(Patch): """ diff --git a/lib/matplotlib/patches.pyi b/lib/matplotlib/patches.pyi index 1e70a1efc3be..e9302563083c 100644 --- a/lib/matplotlib/patches.pyi +++ b/lib/matplotlib/patches.pyi @@ -259,6 +259,10 @@ class Ellipse(Patch): def get_corners(self) -> np.ndarray: ... + def get_vertices(self) -> list[tuple[float, float]]: ... + def get_co_vertices(self) -> list[tuple[float, float]]: ... + + class Annulus(Patch): a: float b: float diff --git a/lib/matplotlib/tests/test_patches.py b/lib/matplotlib/tests/test_patches.py index b9e1db32d419..fd872bac98d4 100644 --- a/lib/matplotlib/tests/test_patches.py +++ b/lib/matplotlib/tests/test_patches.py @@ -104,6 +104,57 @@ def test_corner_center(): assert_almost_equal(ellipse.get_corners(), corners_rot) +def test_ellipse_vertices(): + # expect 0 for 0 ellipse width, height + ellipse = Ellipse(xy=(0, 0), width=0, height=0, angle=0) + assert_almost_equal( + ellipse.get_vertices(), + [(0.0, 0.0), (0.0, 0.0)], + ) + assert_almost_equal( + ellipse.get_co_vertices(), + [(0.0, 0.0), (0.0, 0.0)], + ) + + ellipse = Ellipse(xy=(0, 0), width=2, height=1, angle=30) + assert_almost_equal( + ellipse.get_vertices(), + [ + ( + ellipse.center[0] + ellipse.width / 4 * np.sqrt(3), + ellipse.center[1] + ellipse.width / 4, + ), + ( + ellipse.center[0] - ellipse.width / 4 * np.sqrt(3), + ellipse.center[1] - ellipse.width / 4, + ), + ], + ) + assert_almost_equal( + ellipse.get_co_vertices(), + [ + ( + ellipse.center[0] - ellipse.height / 4, + ellipse.center[1] + ellipse.height / 4 * np.sqrt(3), + ), + ( + ellipse.center[0] + ellipse.height / 4, + ellipse.center[1] - ellipse.height / 4 * np.sqrt(3), + ), + ], + ) + v1, v2 = np.array(ellipse.get_vertices()) + np.testing.assert_almost_equal((v1 + v2) / 2, ellipse.center) + v1, v2 = np.array(ellipse.get_co_vertices()) + np.testing.assert_almost_equal((v1 + v2) / 2, ellipse.center) + + ellipse = Ellipse(xy=(2.252, -10.859), width=2.265, height=1.98, angle=68.78) + v1, v2 = np.array(ellipse.get_vertices()) + np.testing.assert_almost_equal((v1 + v2) / 2, ellipse.center) + v1, v2 = np.array(ellipse.get_co_vertices()) + np.testing.assert_almost_equal((v1 + v2) / 2, ellipse.center) + + def test_rotate_rect(): loc = np.asarray([1.0, 2.0]) width = 2 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy