Skip to content

Adding ellipse_arrow.py example and closes #25477 #25779

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
eeed6fc
Adding ellipse_arrow.py example and fix #25477
Apr 27, 2023
e16c81d
adapt the = lines to fix docu build test
Apr 27, 2023
f8dc66f
use plt.subplot()
Apr 27, 2023
4ae516e
Now the patches.Ellipse is used for the plot and a marker ">" at the …
Apr 29, 2023
0005c7e
changed function docstring to numpy style
Apr 29, 2023
944a513
fix flake8 build fail
Apr 29, 2023
8acae1e
Update ellipse_arrow.py
photoniker Apr 29, 2023
74c4480
Update ellipse_arrow.py
photoniker Apr 29, 2023
02865ef
Update ellipse_arrow.py
photoniker Apr 30, 2023
15a84c1
Update ellipse_arrow.py
photoniker Apr 30, 2023
f9fd868
Update ellipse_arrow.py
photoniker Apr 30, 2023
e3ad826
Update ellipse_arrow.py
photoniker Apr 30, 2023
e12a72a
Update ellipse_arrow.py
photoniker Apr 30, 2023
303f957
added get_vertices and get_co_vertices methods the Ellipse
Apr 30, 2023
3df0bbb
deleted blank lines
Apr 30, 2023
bbf76e7
sorry, some more whitespaces in blank line
Apr 30, 2023
f074713
added entries in stubs, resolve docu issues
May 1, 2023
2578cd9
resolve flake8
May 1, 2023
0b492d1
resolve return values
May 1, 2023
0386925
Update patches.pyi
photoniker May 1, 2023
f23854d
overseen some whitespaces, sorry
May 1, 2023
86fbf90
Merge branch 'add_Ellipse_Arrow_Example' of https://github.com/photon…
May 1, 2023
135d7cb
soved isort fail. How to solve the subs fail?
May 1, 2023
9776379
added some more unittest, just in case...
May 1, 2023
801031f
adapted unittest
May 2, 2023
3a4ee04
adapted stubs file
May 2, 2023
46898de
resolve pre-commit codespell
May 2, 2023
28437f1
Update galleries/examples/shapes_and_collections/ellipse_arrow.py
photoniker May 8, 2023
3bbe33f
Some correction :lipstick: ellipse_arrow.py
photoniker May 8, 2023
9cbe4ef
added get_vertices_co_vertices.rst to next_whats_new folder
May 10, 2023
49d89d1
Update patches.py by .. versionadded:: 3.8
photoniker May 13, 2023
501436f
get_vertices and get_co_vertices returns now the coordinates of the m…
May 13, 2023
cf6e95a
Changed get_vertices and get_co_vertices using get_patch_transform().…
May 16, 2023
896a775
fix in unittest due to different ordering of vertices return values
May 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/users/next_whats_new/get_vertices_co_vertices.rst
Original file line number Diff line number Diff line change
@@ -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.
53 changes: 53 additions & 0 deletions galleries/examples/shapes_and_collections/ellipse_arrow.py
Original file line number Diff line number Diff line change
@@ -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
</gallery/shapes_and_collections/ellipse_collection>`.
"""

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`
31 changes: 31 additions & 0 deletions lib/matplotlib/patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 <https://en.wikipedia.org/wiki/Ellipse>`_

.. 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 <https://en.wikipedia.org/wiki/Ellipse>`_

.. 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):
"""
Expand Down
4 changes: 4 additions & 0 deletions lib/matplotlib/patches.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
51 changes: 51 additions & 0 deletions lib/matplotlib/tests/test_patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down