Skip to content

Commit bd87ec8

Browse files
authored
Merge pull request #16507 from anntzer/transformstr
Factor out common parts of `__str__` for Transform subclasses.
2 parents d1e4b3f + e7e6c8c commit bd87ec8

File tree

3 files changed

+116
-116
lines changed

3 files changed

+116
-116
lines changed

lib/matplotlib/projections/polar.py

+11-43
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,10 @@ def __init__(self, axis=None, use_rmin=True,
3232
self._use_rmin = use_rmin
3333
self._apply_theta_transforms = _apply_theta_transforms
3434

35-
def __str__(self):
36-
return ("{}(\n"
37-
"{},\n"
38-
" use_rmin={},\n"
39-
" _apply_theta_transforms={})"
40-
.format(type(self).__name__,
41-
mtransforms._indent_str(self._axis),
42-
self._use_rmin,
43-
self._apply_theta_transforms))
35+
__str__ = mtransforms._make_str_method(
36+
"_axis",
37+
use_rmin="_use_rmin",
38+
_apply_theta_transforms="_apply_theta_transforms")
4439

4540
def transform_non_affine(self, tr):
4641
# docstring inherited
@@ -86,13 +81,7 @@ def __init__(self, scale_transform, limits):
8681
self.set_children(scale_transform, limits)
8782
self._mtx = None
8883

89-
def __str__(self):
90-
return ("{}(\n"
91-
"{},\n"
92-
"{})"
93-
.format(type(self).__name__,
94-
mtransforms._indent_str(self._scale_transform),
95-
mtransforms._indent_str(self._limits)))
84+
__str__ = mtransforms._make_str_method("_scale_transform", "_limits")
9685

9786
def get_matrix(self):
9887
# docstring inherited
@@ -124,15 +113,10 @@ def __init__(self, axis=None, use_rmin=True,
124113
self._use_rmin = use_rmin
125114
self._apply_theta_transforms = _apply_theta_transforms
126115

127-
def __str__(self):
128-
return ("{}(\n"
129-
"{},\n"
130-
" use_rmin={},\n"
131-
" _apply_theta_transforms={})"
132-
.format(type(self).__name__,
133-
mtransforms._indent_str(self._axis),
134-
self._use_rmin,
135-
self._apply_theta_transforms))
116+
__str__ = mtransforms._make_str_method(
117+
"_axis",
118+
use_rmin="_use_rmin",
119+
_apply_theta_transforms="_apply_theta_transforms")
136120

137121
def transform_non_affine(self, xy):
138122
# docstring inherited
@@ -454,15 +438,7 @@ def __init__(self, axes, pad, mode):
454438
self.mode = mode
455439
self.pad = pad
456440

457-
def __str__(self):
458-
return ("{}(\n"
459-
"{},\n"
460-
"{},\n"
461-
"{})"
462-
.format(type(self).__name__,
463-
mtransforms._indent_str(self.axes),
464-
mtransforms._indent_str(self.pad),
465-
mtransforms._indent_str(repr(self.mode))))
441+
__str__ = mtransforms._make_str_method("axes", "pad", "mode")
466442

467443
def get_matrix(self):
468444
if self._invalid:
@@ -714,15 +690,7 @@ def __init__(self, center, viewLim, originLim, **kwargs):
714690
self._originLim = originLim
715691
self.set_children(viewLim, originLim)
716692

717-
def __str__(self):
718-
return ("{}(\n"
719-
"{},\n"
720-
"{},\n"
721-
"{})"
722-
.format(type(self).__name__,
723-
mtransforms._indent_str(self._center),
724-
mtransforms._indent_str(self._viewLim),
725-
mtransforms._indent_str(self._originLim)))
693+
__str__ = mtransforms._make_str_method("_center", "_viewLim", "_originLim")
726694

727695
def get_points(self):
728696
# docstring inherited

lib/matplotlib/tests/test_transforms.py

+65
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,71 @@ def test_bbox_as_strings():
492492
assert eval(format(getattr(b, k), fmt)) == v
493493

494494

495+
def test_str_transform():
496+
# The str here should not be considered as "absolutely stable", and may be
497+
# reformatted later; this is just a smoketest for __str__.
498+
assert str(plt.subplot(projection="polar").transData) == """\
499+
CompositeGenericTransform(
500+
CompositeGenericTransform(
501+
CompositeGenericTransform(
502+
TransformWrapper(
503+
BlendedAffine2D(
504+
IdentityTransform(),
505+
IdentityTransform())),
506+
CompositeAffine2D(
507+
Affine2D(
508+
[[1. 0. 0.]
509+
[0. 1. 0.]
510+
[0. 0. 1.]]),
511+
Affine2D(
512+
[[1. 0. 0.]
513+
[0. 1. 0.]
514+
[0. 0. 1.]]))),
515+
PolarTransform(
516+
PolarAxesSubplot(0.125,0.1;0.775x0.8),
517+
use_rmin=True,
518+
_apply_theta_transforms=False)),
519+
CompositeGenericTransform(
520+
CompositeGenericTransform(
521+
PolarAffine(
522+
TransformWrapper(
523+
BlendedAffine2D(
524+
IdentityTransform(),
525+
IdentityTransform())),
526+
LockableBbox(
527+
Bbox(x0=0.0, y0=0.0, x1=6.283185307179586, y1=1.0),
528+
[[-- --]
529+
[-- --]])),
530+
BboxTransformFrom(
531+
_WedgeBbox(
532+
(0.5, 0.5),
533+
TransformedBbox(
534+
Bbox(x0=0.0, y0=0.0, x1=6.283185307179586, y1=1.0),
535+
CompositeAffine2D(
536+
Affine2D(
537+
[[1. 0. 0.]
538+
[0. 1. 0.]
539+
[0. 0. 1.]]),
540+
Affine2D(
541+
[[1. 0. 0.]
542+
[0. 1. 0.]
543+
[0. 0. 1.]]))),
544+
LockableBbox(
545+
Bbox(x0=0.0, y0=0.0, x1=6.283185307179586, y1=1.0),
546+
[[-- --]
547+
[-- --]])))),
548+
BboxTransformTo(
549+
TransformedBbox(
550+
Bbox(x0=0.125, y0=0.09999999999999998, x1=0.9, y1=0.9),
551+
BboxTransformTo(
552+
TransformedBbox(
553+
Bbox(x0=0.0, y0=0.0, x1=8.0, y1=6.0),
554+
Affine2D(
555+
[[80. 0. 0.]
556+
[ 0. 80. 0.]
557+
[ 0. 0. 1.]])))))))"""
558+
559+
495560
def test_transform_single_point():
496561
t = mtransforms.Affine2D()
497562
r = t.transform_affine((1, 1))

lib/matplotlib/transforms.py

+40-73
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
# `np.minimum` instead of the builtin `min`, and likewise for `max`. This is
3434
# done so that `nan`s are propagated, instead of being silently dropped.
3535

36-
import re
36+
import functools
37+
import textwrap
3738
import weakref
3839

3940
import numpy as np
@@ -47,8 +48,32 @@
4748
DEBUG = False
4849

4950

50-
def _indent_str(obj): # textwrap.indent(str(obj), 4) on Py3.
51-
return re.sub("(^|\n)", r"\1 ", str(obj))
51+
def _make_str_method(*args, **kwargs):
52+
"""
53+
Generate a ``__str__`` method for a `.Transform` subclass.
54+
55+
After ::
56+
57+
class T:
58+
__str__ = _make_str_method("attr", key="other")
59+
60+
``str(T(...))`` will be
61+
62+
.. code-block:: text
63+
64+
{type(T).__name__}(
65+
{self.attr},
66+
key={self.other})
67+
"""
68+
indent = functools.partial(textwrap.indent, prefix=" " * 4)
69+
def strrepr(x): return repr(x) if isinstance(x, str) else str(x)
70+
return lambda self: (
71+
type(self).__name__ + "("
72+
+ ",".join([*(indent("\n" + strrepr(getattr(self, arg)))
73+
for arg in args),
74+
*(indent("\n" + k + "=" + strrepr(getattr(self, arg)))
75+
for k, arg in kwargs.items())])
76+
+ ")")
5277

5378

5479
class TransformNode:
@@ -1001,13 +1026,7 @@ def __init__(self, bbox, transform, **kwargs):
10011026
self.set_children(bbox, transform)
10021027
self._points = None
10031028

1004-
def __str__(self):
1005-
return ("{}(\n"
1006-
"{},\n"
1007-
"{})"
1008-
.format(type(self).__name__,
1009-
_indent_str(self._bbox),
1010-
_indent_str(self._transform)))
1029+
__str__ = _make_str_method("_bbox", "_transform")
10111030

10121031
def get_points(self):
10131032
# docstring inherited
@@ -1086,13 +1105,7 @@ def __init__(self, bbox, x0=None, y0=None, x1=None, y1=None, **kwargs):
10861105
mask = [val is None for val in fp]
10871106
self._locked_points = np.ma.array(fp, float, mask=mask).reshape((2, 2))
10881107

1089-
def __str__(self):
1090-
return ("{}(\n"
1091-
"{},\n"
1092-
"{})"
1093-
.format(type(self).__name__,
1094-
_indent_str(self._bbox),
1095-
_indent_str(self._locked_points)))
1108+
__str__ = _make_str_method("_bbox", "_locked_points")
10961109

10971110
def get_points(self):
10981111
# docstring inherited
@@ -1625,11 +1638,7 @@ def _init(self, child):
16251638
def __eq__(self, other):
16261639
return self._child.__eq__(other)
16271640

1628-
def __str__(self):
1629-
return ("{}(\n"
1630-
"{})"
1631-
.format(type(self).__name__,
1632-
_indent_str(self._child)))
1641+
__str__ = _make_str_method("_child")
16331642

16341643
def frozen(self):
16351644
# docstring inherited
@@ -1831,11 +1840,7 @@ def __init__(self, matrix=None, **kwargs):
18311840
self._mtx = matrix
18321841
self._invalid = 0
18331842

1834-
def __str__(self):
1835-
return ("{}(\n"
1836-
"{})"
1837-
.format(type(self).__name__,
1838-
_indent_str(self._mtx)))
1843+
__str__ = _make_str_method("_mtx")
18391844

18401845
@staticmethod
18411846
def from_values(a, b, c, d, e, f):
@@ -2032,9 +2037,7 @@ def frozen(self):
20322037
# docstring inherited
20332038
return self
20342039

2035-
def __str__(self):
2036-
return ("{}()"
2037-
.format(type(self).__name__))
2040+
__str__ = _make_str_method()
20382041

20392042
def get_matrix(self):
20402043
# docstring inherited
@@ -2088,13 +2091,7 @@ def contains_branch_seperately(self, transform):
20882091
return (self._x.contains_branch(transform),
20892092
self._y.contains_branch(transform))
20902093

2091-
def __str__(self):
2092-
return ("{}(\n"
2093-
"{},\n"
2094-
"{})"
2095-
.format(type(self).__name__,
2096-
_indent_str(self._x),
2097-
_indent_str(self._y)))
2094+
__str__ = _make_str_method("_x", "_y")
20982095

20992096

21002097
class BlendedGenericTransform(_BlendedMixin, Transform):
@@ -2333,13 +2330,7 @@ def _iter_break_from_left_to_right(self):
23332330
has_inverse = property(
23342331
lambda self: self._a.has_inverse and self._b.has_inverse)
23352332

2336-
def __str__(self):
2337-
return ("{}(\n"
2338-
"{},\n"
2339-
"{})"
2340-
.format(type(self).__name__,
2341-
_indent_str(self._a),
2342-
_indent_str(self._b)))
2333+
__str__ = _make_str_method("_a", "_b")
23432334

23442335
def transform_affine(self, points):
23452336
# docstring inherited
@@ -2419,13 +2410,7 @@ def _iter_break_from_left_to_right(self):
24192410
for left, right in self._b._iter_break_from_left_to_right():
24202411
yield self._a + left, right
24212412

2422-
def __str__(self):
2423-
return ("{}(\n"
2424-
"{},\n"
2425-
"{})"
2426-
.format(type(self).__name__,
2427-
_indent_str(self._a),
2428-
_indent_str(self._b)))
2413+
__str__ = _make_str_method("_a", "_b")
24292414

24302415
def get_matrix(self):
24312416
# docstring inherited
@@ -2486,13 +2471,7 @@ def __init__(self, boxin, boxout, **kwargs):
24862471
self._mtx = None
24872472
self._inverted = None
24882473

2489-
def __str__(self):
2490-
return ("{}(\n"
2491-
"{},\n"
2492-
"{})"
2493-
.format(type(self).__name__,
2494-
_indent_str(self._boxin),
2495-
_indent_str(self._boxout)))
2474+
__str__ = _make_str_method("_boxin", "_boxout")
24962475

24972476
def get_matrix(self):
24982477
# docstring inherited
@@ -2534,11 +2513,7 @@ def __init__(self, boxout, **kwargs):
25342513
self._mtx = None
25352514
self._inverted = None
25362515

2537-
def __str__(self):
2538-
return ("{}(\n"
2539-
"{})"
2540-
.format(type(self).__name__,
2541-
_indent_str(self._boxout)))
2516+
__str__ = _make_str_method("_boxout")
25422517

25432518
def get_matrix(self):
25442519
# docstring inherited
@@ -2592,11 +2567,7 @@ def __init__(self, boxin, **kwargs):
25922567
self._mtx = None
25932568
self._inverted = None
25942569

2595-
def __str__(self):
2596-
return ("{}(\n"
2597-
"{})"
2598-
.format(type(self).__name__,
2599-
_indent_str(self._boxin)))
2570+
__str__ = _make_str_method("_boxin")
26002571

26012572
def get_matrix(self):
26022573
# docstring inherited
@@ -2628,11 +2599,7 @@ def __init__(self, xt, yt, scale_trans, **kwargs):
26282599
self._mtx = None
26292600
self._inverted = None
26302601

2631-
def __str__(self):
2632-
return ("{}(\n"
2633-
"{})"
2634-
.format(type(self).__name__,
2635-
_indent_str(self._t)))
2602+
__str__ = _make_str_method("_t")
26362603

26372604
def get_matrix(self):
26382605
# docstring inherited

0 commit comments

Comments
 (0)