Skip to content

Commit 0d15d08

Browse files
committed
Add affine transform primitives to markers
Added, translated, scaled, and rotated methods with test.
1 parent 9ef7f6b commit 0d15d08

File tree

2 files changed

+90
-12
lines changed

2 files changed

+90
-12
lines changed

lib/matplotlib/markers.py

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ def get_user_transform(self):
419419
if self._user_transform is not None:
420420
return self._user_transform.frozen()
421421

422-
def transformed(self, transform:Affine2D):
422+
def transformed(self, transform: Affine2D):
423423
"""
424424
Return new marker with combined transformation.
425425
@@ -442,22 +442,65 @@ def rotated(self, deg=None, rad=None):
442442
Parameters
443443
----------
444444
deg : float, default: None
445+
- use this parameter to specify rotation angle in degrees.
445446
446447
rad : float, default: None
448+
- use this parameter to specify rotation angle in radians.
449+
450+
Note: you must specify exactly one of deg or rad.
447451
"""
448452
if not ((deg is None) ^ (rad is None)):
449-
raise Exception("Only one of deg or rad shall be used.")
450-
451-
_transform = self._user_transform or Affine2D()
453+
raise ValueError("Exactly one of deg or rad shall be used.")
454+
455+
new_marker = MarkerStyle(self)
456+
if new_marker._user_transform is None:
457+
new_marker._user_transform = Affine2D()
452458

453-
if deg is not None:
454-
_transform = _transform.rotate_deg(deg)
455-
459+
if deg is not None:
460+
new_marker._user_transform.rotate_deg(deg)
456461
if rad is not None:
457-
_transform = _transform.rotate(rad)
462+
new_marker._user_transform.rotate(rad)
463+
464+
return new_marker
465+
466+
def scaled(self, sx, sy=None):
467+
"""
468+
Return new marker scaled by specified scale factors.
469+
470+
If *sy* is None, the same scale is applied in both the *x*- and
471+
*y*-directions.
472+
473+
Parameters
474+
----------
475+
sx : float
476+
- *x*-direction scaling factor.
477+
478+
sy : float, default: None
479+
- *y*-direction scaling factor.
480+
"""
481+
if sy is None:
482+
sy = sx
483+
484+
new_marker = MarkerStyle(self)
485+
_transform = new_marker._user_transform or Affine2D()
486+
new_marker._user_transform = _transform.scale(sx, sy)
487+
return new_marker
488+
489+
def translated(self, tx, ty):
490+
"""
491+
Return new marker translated by tx and ty.
458492
493+
Parameters
494+
----------
495+
tx : float
496+
497+
ty : float
498+
499+
"""
459500
new_marker = MarkerStyle(self)
460-
new_marker._user_transform = _transform
501+
_transform = new_marker._user_transform or Affine2D()
502+
new_marker._user_transform = _transform.translate(tx, ty)
503+
return new_marker
461504

462505
def _set_nothing(self):
463506
self._filled = False

lib/matplotlib/tests/test_marker.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,47 @@ def test_marker_clipping(fig_ref, fig_test):
206206
ax_ref.axis('off')
207207
ax_test.axis('off')
208208

209+
209210
@pytest.mark.parametrize("marker,transform,expected", [
210-
(markers.MarkerStyle("o"), Affine2D().translate(1,1), Affine2D().translate(1,1)),
211-
(markers.MarkerStyle("o", transform=Affine2D().translate(1,1)), Affine2D().translate(1,1), Affine2D().translate(2,2)),
211+
(markers.MarkerStyle("o"), Affine2D().translate(1, 1),
212+
Affine2D().translate(1, 1)),
213+
(markers.MarkerStyle("o", transform=Affine2D().translate(1, 1)),
214+
Affine2D().translate(1, 1), Affine2D().translate(2, 2)),
215+
# (markers.MarkerStyle("$|||$", transform=Affine2D().translate(1, 1)),
216+
# Affine2D().translate(1, 1), Affine2D().translate(2, 2)),
217+
(markers.MarkerStyle(
218+
markers.TICKLEFT, transform=Affine2D().translate(1, 1)),
219+
Affine2D().translate(1, 1), Affine2D().translate(2, 2)),
212220
])
213221
def test_marker_transformed(marker, transform, expected):
214222
new_marker = marker.transformed(transform)
215223
assert new_marker is not marker
216224
assert new_marker.get_user_transform() == expected
217-
assert marker.get_user_transform() is not new_marker.get_user_transform()
225+
assert marker._user_transform is not new_marker._user_transform
226+
227+
228+
def test_marker_rotated_invalid():
229+
marker = markers.MarkerStyle("o")
230+
with pytest.raises(ValueError):
231+
new_marker = marker.rotated()
232+
new_marker = marker.rotated(deg=10, rad=10)
233+
234+
235+
@pytest.mark.parametrize("marker,deg,rad,expected", [
236+
(markers.MarkerStyle("o"), 10, None, Affine2D().rotate_deg(10)),
237+
(markers.MarkerStyle("o"), None, 0.01, Affine2D().rotate(0.01)),
238+
(markers.MarkerStyle("o", transform=Affine2D().translate(1, 1)),
239+
10, None, Affine2D().translate(1, 1).rotate_deg(10)),
240+
(markers.MarkerStyle("o", transform=Affine2D().translate(1, 1)),
241+
None, 0.01, Affine2D().translate(1, 1).rotate(0.01)),
242+
# (markers.MarkerStyle("$|||$", transform=Affine2D().translate(1, 1)),
243+
# 10, None, Affine2D().translate(1, 1).rotate_deg(10)),
244+
(markers.MarkerStyle(
245+
markers.TICKLEFT, transform=Affine2D().translate(1, 1)),
246+
10, None, Affine2D().translate(1, 1).rotate_deg(10)),
247+
])
248+
def test_marker_rotated_deg(marker, deg, rad, expected):
249+
new_marker = marker.rotated(deg=deg, rad=rad)
250+
assert new_marker is not marker
251+
assert new_marker.get_user_transform() == expected
252+
assert marker._user_transform is not new_marker._user_transform

0 commit comments

Comments
 (0)