Skip to content

Commit 4b42dbb

Browse files
authored
Merge pull request #26375 from ericpre/add_EllipseCollection_setter
Add `widths`, `heights` and `angles` setter to `EllipseCollection`
2 parents 47dc2c6 + 729467c commit 4b42dbb

File tree

4 files changed

+119
-3
lines changed

4 files changed

+119
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
Add ``widths``, ``heights`` and ``angles`` setter to ``EllipseCollection``
2+
--------------------------------------------------------------------------
3+
4+
The ``widths``, ``heights`` and ``angles`` values of the `~matplotlib.collections.EllipseCollection`
5+
can now be changed after the collection has been created.
6+
7+
.. plot::
8+
:include-source: true
9+
10+
import matplotlib.pyplot as plt
11+
from matplotlib.collections import EllipseCollection
12+
import numpy as np
13+
14+
rng = np.random.default_rng(0)
15+
16+
widths = (2, )
17+
heights = (3, )
18+
angles = (45, )
19+
offsets = rng.random((10, 2)) * 10
20+
21+
fig, ax = plt.subplots()
22+
23+
ec = EllipseCollection(
24+
widths=widths,
25+
heights=heights,
26+
angles=angles,
27+
offsets=offsets,
28+
units='x',
29+
offset_transform=ax.transData,
30+
)
31+
32+
ax.add_collection(ec)
33+
ax.set_xlim(-2, 12)
34+
ax.set_ylim(-2, 12)
35+
36+
new_widths = rng.random((10, 2)) * 2
37+
new_heights = rng.random((10, 2)) * 3
38+
new_angles = rng.random((10, 2)) * 180
39+
40+
ec.set(widths=new_widths, heights=new_heights, angles=new_angles)

lib/matplotlib/collections.py

+30-3
Original file line numberDiff line numberDiff line change
@@ -1745,9 +1745,9 @@ def __init__(self, widths, heights, angles, *, units='points', **kwargs):
17451745
Forwarded to `Collection`.
17461746
"""
17471747
super().__init__(**kwargs)
1748-
self._widths = 0.5 * np.asarray(widths).ravel()
1749-
self._heights = 0.5 * np.asarray(heights).ravel()
1750-
self._angles = np.deg2rad(angles).ravel()
1748+
self.set_widths(widths)
1749+
self.set_heights(heights)
1750+
self.set_angles(angles)
17511751
self._units = units
17521752
self.set_transform(transforms.IdentityTransform())
17531753
self._transforms = np.empty((0, 3, 3))
@@ -1795,6 +1795,33 @@ def _set_transforms(self):
17951795
m[:2, 2:] = 0
17961796
self.set_transform(_affine(m))
17971797

1798+
def set_widths(self, widths):
1799+
"""Set the lengths of the first axes (e.g., major axis)."""
1800+
self._widths = 0.5 * np.asarray(widths).ravel()
1801+
self.stale = True
1802+
1803+
def set_heights(self, heights):
1804+
"""Set the lengths of second axes (e.g., minor axes)."""
1805+
self._heights = 0.5 * np.asarray(heights).ravel()
1806+
self.stale = True
1807+
1808+
def set_angles(self, angles):
1809+
"""Set the angles of the first axes, degrees CCW from the x-axis."""
1810+
self._angles = np.deg2rad(angles).ravel()
1811+
self.stale = True
1812+
1813+
def get_widths(self):
1814+
"""Get the lengths of the first axes (e.g., major axis)."""
1815+
return self._widths * 2
1816+
1817+
def get_heights(self):
1818+
"""Set the lengths of second axes (e.g., minor axes)."""
1819+
return self._heights * 2
1820+
1821+
def get_angles(self):
1822+
"""Get the angles of the first axes, degrees CCW from the x-axis."""
1823+
return np.rad2deg(self._angles)
1824+
17981825
@artist.allow_rasterization
17991826
def draw(self, renderer):
18001827
self._set_transforms()

lib/matplotlib/collections.pyi

+6
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,12 @@ class EllipseCollection(Collection):
180180
] = ...,
181181
**kwargs
182182
) -> None: ...
183+
def set_widths(self, widths: ArrayLike) -> None: ...
184+
def set_heights(self, heights: ArrayLike) -> None: ...
185+
def set_angles(self, angles: ArrayLike) -> None: ...
186+
def get_widths(self) -> ArrayLike: ...
187+
def get_heights(self) -> ArrayLike: ...
188+
def get_angles(self) -> ArrayLike: ...
183189

184190
class PatchCollection(Collection):
185191
def __init__(

lib/matplotlib/tests/test_collections.py

+43
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,49 @@ def test_EllipseCollection():
408408
ax.autoscale_view()
409409

410410

411+
def test_EllipseCollection_setter_getter():
412+
# Test widths, heights and angle setter
413+
rng = np.random.default_rng(0)
414+
415+
widths = (2, )
416+
heights = (3, )
417+
angles = (45, )
418+
offsets = rng.random((10, 2)) * 10
419+
420+
fig, ax = plt.subplots()
421+
422+
ec = mcollections.EllipseCollection(
423+
widths=widths,
424+
heights=heights,
425+
angles=angles,
426+
offsets=offsets,
427+
units='x',
428+
offset_transform=ax.transData,
429+
)
430+
431+
assert_array_almost_equal(ec._widths, np.array(widths).ravel() * 0.5)
432+
assert_array_almost_equal(ec._heights, np.array(heights).ravel() * 0.5)
433+
assert_array_almost_equal(ec._angles, np.deg2rad(angles).ravel())
434+
435+
assert_array_almost_equal(ec.get_widths(), widths)
436+
assert_array_almost_equal(ec.get_heights(), heights)
437+
assert_array_almost_equal(ec.get_angles(), angles)
438+
439+
ax.add_collection(ec)
440+
ax.set_xlim(-2, 12)
441+
ax.set_ylim(-2, 12)
442+
443+
new_widths = rng.random((10, 2)) * 2
444+
new_heights = rng.random((10, 2)) * 3
445+
new_angles = rng.random((10, 2)) * 180
446+
447+
ec.set(widths=new_widths, heights=new_heights, angles=new_angles)
448+
449+
assert_array_almost_equal(ec.get_widths(), new_widths.ravel())
450+
assert_array_almost_equal(ec.get_heights(), new_heights.ravel())
451+
assert_array_almost_equal(ec.get_angles(), new_angles.ravel())
452+
453+
411454
@image_comparison(['polycollection_close.png'], remove_text=True, style='mpl20')
412455
def test_polycollection_close():
413456
from mpl_toolkits.mplot3d import Axes3D # type: ignore

0 commit comments

Comments
 (0)