From 73e79201592b861328f6aee75dcd17c7278d0fa7 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sun, 15 Oct 2017 15:29:52 -0700 Subject: [PATCH 1/7] Improve reprs of transforms. This patch should make debugging the transform a bit stack easier, by changing, for example, the repr of the transform of a line created with `plot([1, 2])` from CompositeGenericTransform(TransformWrapper(BlendedAffine2D(IdentityTransform(),IdentityTransform())), CompositeGenericTransform(BboxTransformFrom(TransformedBbox(Bbox([[-0.05, 0.95], [1.05, 2.05]]), TransformWrapper(BlendedAffine2D(IdentityTransform(),IdentityTransform())))), BboxTransformTo(TransformedBbox(Bbox([[0.125, 0.10999999999999999], [0.9, 0.88]]), BboxTransformTo(TransformedBbox(Bbox([[0.0, 0.0], [6.4, 4.8]]), Affine2D(array([[ 100., 0., 0.], [ 0., 100., 0.], [ 0., 0., 1.]])))))))) to CompositeGenericTransform( TransformWrapper( BlendedAffine2D( IdentityTransform(), IdentityTransform())), CompositeGenericTransform( BboxTransformFrom( TransformedBbox( Bbox(x0=-0.05, y0=0.95, x1=1.05, y1=2.05), TransformWrapper( BlendedAffine2D( IdentityTransform(), IdentityTransform())))), BboxTransformTo( TransformedBbox( Bbox(x0=0.125, y0=0.10999999999999999, x1=0.9, y1=0.88), BboxTransformTo( TransformedBbox( Bbox(x0=0.0, y0=0.0, x1=6.4, y1=4.8), Affine2D( [[ 100. 0. 0.] [ 0. 100. 0.] [ 0. 0. 1.]]))))))) This will, of course, invalidate code that relied on the exact strs, but what can you do. --- lib/matplotlib/transforms.py | 148 +++++++++++++++++++++++++---------- 1 file changed, 107 insertions(+), 41 deletions(-) diff --git a/lib/matplotlib/transforms.py b/lib/matplotlib/transforms.py index 2269c9e40276..f4ba74ceacac 100644 --- a/lib/matplotlib/transforms.py +++ b/lib/matplotlib/transforms.py @@ -43,6 +43,7 @@ update_path_extents) from numpy.linalg import inv +import re import weakref import warnings @@ -52,6 +53,10 @@ DEBUG = False +def _indent_str(obj): # textwrap.indent(str(obj), 4) on Py3. + return re.sub("(^|\n)", r"\1 ", str(obj)) + + class TransformNode(object): """ :class:`TransformNode` is the base class for anything that @@ -1053,8 +1058,15 @@ def __init__(self, bbox, transform, **kwargs): self.set_children(bbox, transform) self._points = None - def __repr__(self): - return "TransformedBbox(%r, %r)" % (self._bbox, self._transform) + def __str__(self): + return ("{}(\n" + "{},\n" + "{})" + .format(type(self).__name__, + _indent_str(self._bbox), + _indent_str(self._transform))) + + __repr__ = __str__ def get_points(self): if self._invalid: @@ -1134,8 +1146,15 @@ def __init__(self, bbox, x0=None, y0=None, x1=None, y1=None, **kwargs): self._locked_points = np.ma.array(fp, np.float_, mask=mask).reshape((2, 2)) - def __repr__(self): - return "LockableBbox(%r, %r)" % (self._bbox, self._locked_points) + def __str__(self): + return ("{}(\n" + "{},\n" + "{})" + .format(type(self).__name__, + _indent_str(self._bbox), + _indent_str(self._locked_points))) + + __repr__ = __str__ def get_points(self): if self._invalid: @@ -1661,11 +1680,6 @@ def _init(self, child): def __eq__(self, other): return self._child.__eq__(other) - if DEBUG: - - def __str__(self): - return str(self._child) - # NOTE: Transform.__[gs]etstate__ should be sufficient when using only # Python 3.4+. def __getstate__(self): @@ -1690,8 +1704,13 @@ def __setstate__(self, state): self._parents = dict((k, weakref.ref(v)) for (k, v) in six.iteritems(state['parents']) if v is not None) - def __repr__(self): - return "TransformWrapper(%r)" % self._child + def __str__(self): + return ("{}(\n" + "{})" + .format(type(self).__name__, + _indent_str(self._child))) + + __repr__ = __str__ def frozen(self): return self._child.frozen() @@ -1918,8 +1937,13 @@ def __init__(self, matrix=None, **kwargs): self._mtx = matrix self._invalid = 0 - def __repr__(self): - return "Affine2D(%s)" % repr(self._mtx) + def __str__(self): + return ("{}(\n" + "{})" + .format(type(self).__name__, + _indent_str(self._mtx))) + + __repr__ = __str__ @staticmethod def from_values(a, b, c, d, e, f): @@ -2123,8 +2147,11 @@ def frozen(self): return self frozen.__doc__ = Affine2DBase.frozen.__doc__ - def __repr__(self): - return "IdentityTransform()" + def __str__(self): + return ("{}()" + .format(type(self).__name__)) + + __repr__ = __str__ def get_matrix(self): return self._mtx @@ -2223,8 +2250,15 @@ def frozen(self): return blended_transform_factory(self._x.frozen(), self._y.frozen()) frozen.__doc__ = Transform.frozen.__doc__ - def __repr__(self): - return "BlendedGenericTransform(%s,%s)" % (self._x, self._y) + def __str__(self): + return ("{}(\n" + "{},\n" + "{})" + .format(type(self).__name__, + _indent_str(self._x), + _indent_str(self._y))) + + __repr__ = __str__ def transform_non_affine(self, points): if self._x.is_affine and self._y.is_affine: @@ -2328,8 +2362,15 @@ def contains_branch_seperately(self, transform): # Note, this is an exact copy of BlendedTransform.contains_branch_seperately return self._x.contains_branch(transform), self._y.contains_branch(transform) - def __repr__(self): - return "BlendedAffine2D(%s,%s)" % (self._x, self._y) + def __str__(self): + return ("{}(\n" + "{},\n" + "{})" + .format(type(self).__name__, + _indent_str(self._x), + _indent_str(self._y))) + + __repr__ = __str__ def get_matrix(self): if self._invalid: @@ -2443,12 +2484,15 @@ def _get_is_separable(self): return self._a.is_separable and self._b.is_separable is_separable = property(_get_is_separable) - if DEBUG: - def __str__(self): - return '(%s, %s)' % (self._a, self._b) + def __str__(self): + return ("{}(\n" + "{},\n" + "{})" + .format(type(self).__name__, + _indent_str(self._a), + _indent_str(self._b))) - def __repr__(self): - return "CompositeGenericTransform(%r, %r)" % (self._a, self._b) + __repr__ = __str__ def transform_affine(self, points): return self.get_affine().transform(points) @@ -2525,10 +2569,6 @@ def __init__(self, a, b, **kwargs): self.set_children(a, b) self._mtx = None - if DEBUG: - def __str__(self): - return '(%s, %s)' % (self._a, self._b) - @property def depth(self): return self._a.depth + self._b.depth @@ -2539,8 +2579,15 @@ def _iter_break_from_left_to_right(self): for lh_compliment, rh_compliment in self._b._iter_break_from_left_to_right(): yield self._a + lh_compliment, rh_compliment - def __repr__(self): - return "CompositeAffine2D(%r, %r)" % (self._a, self._b) + def __str__(self): + return ("{}(\n" + "{},\n" + "{})" + .format(type(self).__name__, + _indent_str(self._a), + _indent_str(self._b))) + + __repr__ = __str__ def get_matrix(self): if self._invalid: @@ -2603,8 +2650,15 @@ def __init__(self, boxin, boxout, **kwargs): self._mtx = None self._inverted = None - def __repr__(self): - return "BboxTransform(%r, %r)" % (self._boxin, self._boxout) + def __str__(self): + return ("{}(\n" + "{},\n" + "{})" + .format(type(self).__name__, + _indent_str(self._boxin), + _indent_str(self._boxout))) + + __repr__ = __str__ def get_matrix(self): if self._invalid: @@ -2646,8 +2700,13 @@ def __init__(self, boxout, **kwargs): self._mtx = None self._inverted = None - def __repr__(self): - return "BboxTransformTo(%r)" % (self._boxout) + def __str__(self): + return ("{}(\n" + "{})" + .format(type(self).__name__, + _indent_str(self._boxout))) + + __repr__ = __str__ def get_matrix(self): if self._invalid: @@ -2670,9 +2729,6 @@ class BboxTransformToMaxOnly(BboxTransformTo): transforms points from the unit bounding box to a given :class:`Bbox` with a fixed upper left of (0, 0). """ - def __repr__(self): - return "BboxTransformToMaxOnly(%r)" % (self._boxout) - def get_matrix(self): if self._invalid: xmax, ymax = self._boxout.max @@ -2705,8 +2761,13 @@ def __init__(self, boxin, **kwargs): self._mtx = None self._inverted = None - def __repr__(self): - return "BboxTransformFrom(%r)" % (self._boxin) + def __str__(self): + return ("{}(\n" + "{})" + .format(type(self).__name__, + _indent_str(self._boxin))) + + __repr__ = __str__ def get_matrix(self): if self._invalid: @@ -2738,8 +2799,13 @@ def __init__(self, xt, yt, scale_trans, **kwargs): self._mtx = None self._inverted = None - def __repr__(self): - return "ScaledTranslation(%r)" % (self._t,) + def __str__(self): + return ("{}(\n" + "{})" + .format(type(self).__name__, + _indent_str(self._t))) + + __repr__ = __str__ def get_matrix(self): if self._invalid: From 862909c90ff103a35fdeeaccce4ba15103ecf7f4 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 27 Oct 2017 19:30:59 -0400 Subject: [PATCH 2/7] Add fancy repr to Polar transforms. --- lib/matplotlib/projections/polar.py | 60 +++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/projections/polar.py b/lib/matplotlib/projections/polar.py index 6c519a01a1a6..3d1a170cc1e7 100644 --- a/lib/matplotlib/projections/polar.py +++ b/lib/matplotlib/projections/polar.py @@ -39,6 +39,18 @@ def __init__(self, axis=None, use_rmin=True, self._use_rmin = use_rmin self._apply_theta_transforms = _apply_theta_transforms + def __str__(self): + return ("{}(\n" + "{},\n" + " use_rmin={},\n" + " _apply_theta_transforms={})" + .format(type(self).__name__, + mtransforms._indent_str(self._axis), + self._use_rmin, + self._apply_theta_transforms)) + + __repr__ = __str__ + def transform_non_affine(self, tr): xy = np.empty(tr.shape, float) @@ -95,6 +107,16 @@ def __init__(self, scale_transform, limits): self.set_children(scale_transform, limits) self._mtx = None + def __str__(self): + return ("{}(\n" + "{},\n" + "{})" + .format(type(self).__name__, + mtransforms._indent_str(self._scale_transform), + mtransforms._indent_str(self._limits))) + + __repr__ = __str__ + def get_matrix(self): if self._invalid: limits_scaled = self._limits.transformed(self._scale_transform) @@ -125,6 +147,18 @@ def __init__(self, axis=None, use_rmin=True, self._use_rmin = use_rmin self._apply_theta_transforms = _apply_theta_transforms + def __str__(self): + return ("{}(\n" + "{},\n" + " use_rmin={},\n" + " _apply_theta_transforms={})" + .format(type(self).__name__, + mtransforms._indent_str(self._axis), + self._use_rmin, + self._apply_theta_transforms)) + + __repr__ = __str__ + def transform_non_affine(self, xy): x = xy[:, 0:1] y = xy[:, 1:] @@ -459,6 +493,18 @@ def __init__(self, axes, pad, mode): self.mode = mode self.pad = pad + def __str__(self): + return ("{}(\n" + "{},\n" + "{},\n" + "{})" + .format(type(self).__name__, + mtransforms._indent_str(self.axes), + mtransforms._indent_str(self.pad), + mtransforms._indent_str(repr(self.mode)))) + + __repr__ = __str__ + def get_matrix(self): if self._invalid: if self.mode == 'rlabel': @@ -697,9 +743,17 @@ def __init__(self, center, viewLim, originLim, **kwargs): self._originLim = originLim self.set_children(viewLim, originLim) - def __repr__(self): - return "_WedgeBbox(%r, %r, %r)" % (self._center, self._viewLim, - self._originLim) + def __str__(self): + return ("{}(\n" + "{},\n" + "{},\n" + "{})" + .format(type(self).__name__, + mtransforms._indent_str(self._center), + mtransforms._indent_str(self._viewLim), + mtransforms._indent_str(self._originLim))) + + __repr__ = __str__ def get_points(self): if self._invalid: From 66c46c749be232c686db234940e9276be5321857 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 27 Oct 2017 22:00:11 -0400 Subject: [PATCH 3/7] Add fancy repr to geographic transforms. --- lib/matplotlib/projections/geo.py | 43 +++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/projections/geo.py b/lib/matplotlib/projections/geo.py index 926a22fa5de5..4e961782b668 100644 --- a/lib/matplotlib/projections/geo.py +++ b/lib/matplotlib/projections/geo.py @@ -17,8 +17,7 @@ import matplotlib.spines as mspines import matplotlib.axis as maxis from matplotlib.ticker import Formatter, Locator, NullLocator, FixedLocator, NullFormatter -from matplotlib.transforms import Affine2D, Affine2DBase, Bbox, \ - BboxTransformTo, IdentityTransform, Transform, TransformWrapper +from matplotlib.transforms import Affine2D, BboxTransformTo, Transform class GeoAxes(Axes): """ @@ -268,6 +267,11 @@ def __init__(self, resolution): Transform.__init__(self) self._resolution = resolution + def __str__(self): + return "{}({})".format(type(self).__name__, self._resolution) + + __repr__ = __str__ + def transform_non_affine(self, ll): longitude = ll[:, 0:1] latitude = ll[:, 1:2] @@ -308,6 +312,11 @@ def __init__(self, resolution): Transform.__init__(self) self._resolution = resolution + def __str__(self): + return "{}({})".format(type(self).__name__, self._resolution) + + __repr__ = __str__ + def transform_non_affine(self, xy): # MGDTODO: Math is hard ;( return xy @@ -347,6 +356,11 @@ def __init__(self, resolution): Transform.__init__(self) self._resolution = resolution + def __str__(self): + return "{}({})".format(type(self).__name__, self._resolution) + + __repr__ = __str__ + def transform_non_affine(self, ll): longitude = ll[:, 0:1] latitude = ll[:, 1:2] @@ -381,6 +395,11 @@ def __init__(self, resolution): Transform.__init__(self) self._resolution = resolution + def __str__(self): + return "{}({})".format(type(self).__name__, self._resolution) + + __repr__ = __str__ + def transform_non_affine(self, xy): x, y = xy.T z = np.sqrt(1 - (x / 4) ** 2 - (y / 2) ** 2) @@ -423,6 +442,11 @@ def __init__(self, resolution): Transform.__init__(self) self._resolution = resolution + def __str__(self): + return "{}({})".format(type(self).__name__, self._resolution) + + __repr__ = __str__ + def transform_non_affine(self, ll): def d(theta): delta = -(theta + np.sin(theta) - pi_sin_l) / (1 + np.cos(theta)) @@ -476,6 +500,11 @@ def __init__(self, resolution): Transform.__init__(self) self._resolution = resolution + def __str__(self): + return "{}({})".format(type(self).__name__, self._resolution) + + __repr__ = __str__ + def transform_non_affine(self, xy): x = xy[:, 0:1] y = xy[:, 1:2] @@ -525,6 +554,11 @@ def __init__(self, center_longitude, center_latitude, resolution): self._center_longitude = center_longitude self._center_latitude = center_latitude + def __str__(self): + return "{}({})".format(type(self).__name__, self._resolution) + + __repr__ = __str__ + def transform_non_affine(self, ll): longitude = ll[:, 0:1] latitude = ll[:, 1:2] @@ -572,6 +606,11 @@ def __init__(self, center_longitude, center_latitude, resolution): self._center_longitude = center_longitude self._center_latitude = center_latitude + def __str__(self): + return "{}({})".format(type(self).__name__, self._resolution) + + __repr__ = __str__ + def transform_non_affine(self, xy): x = xy[:, 0:1] y = xy[:, 1:2] From fa690018ae5e9d69c9d54877d1e47a9ca3bcc68c Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sun, 19 Nov 2017 06:09:08 -0800 Subject: [PATCH 4/7] Whitespace fixes. --- lib/matplotlib/projections/polar.py | 8 ++++---- lib/matplotlib/transforms.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/projections/polar.py b/lib/matplotlib/projections/polar.py index 3d1a170cc1e7..79a4bb01cbb9 100644 --- a/lib/matplotlib/projections/polar.py +++ b/lib/matplotlib/projections/polar.py @@ -42,8 +42,8 @@ def __init__(self, axis=None, use_rmin=True, def __str__(self): return ("{}(\n" "{},\n" - " use_rmin={},\n" - " _apply_theta_transforms={})" + " use_rmin={},\n" + " _apply_theta_transforms={})" .format(type(self).__name__, mtransforms._indent_str(self._axis), self._use_rmin, @@ -150,8 +150,8 @@ def __init__(self, axis=None, use_rmin=True, def __str__(self): return ("{}(\n" "{},\n" - " use_rmin={},\n" - " _apply_theta_transforms={})" + " use_rmin={},\n" + " _apply_theta_transforms={})" .format(type(self).__name__, mtransforms._indent_str(self._axis), self._use_rmin, diff --git a/lib/matplotlib/transforms.py b/lib/matplotlib/transforms.py index f4ba74ceacac..b1b79221500c 100644 --- a/lib/matplotlib/transforms.py +++ b/lib/matplotlib/transforms.py @@ -122,7 +122,7 @@ def __setstate__(self, data_dict): def __copy__(self, *args): raise NotImplementedError( - "TransformNode instances can not be copied. " + + "TransformNode instances can not be copied. " "Consider using frozen() instead.") __deepcopy__ = __copy__ From a8721cd2599760a9674abb75a54d8731a4c50db7 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sun, 19 Nov 2017 06:22:16 -0800 Subject: [PATCH 5/7] Move Transform.__repr__ = __str__ to base class. --- lib/matplotlib/projections/geo.py | 16 ---------------- lib/matplotlib/projections/polar.py | 10 ---------- lib/matplotlib/transforms.py | 25 +++---------------------- 3 files changed, 3 insertions(+), 48 deletions(-) diff --git a/lib/matplotlib/projections/geo.py b/lib/matplotlib/projections/geo.py index 4e961782b668..66fc179a9794 100644 --- a/lib/matplotlib/projections/geo.py +++ b/lib/matplotlib/projections/geo.py @@ -270,8 +270,6 @@ def __init__(self, resolution): def __str__(self): return "{}({})".format(type(self).__name__, self._resolution) - __repr__ = __str__ - def transform_non_affine(self, ll): longitude = ll[:, 0:1] latitude = ll[:, 1:2] @@ -315,8 +313,6 @@ def __init__(self, resolution): def __str__(self): return "{}({})".format(type(self).__name__, self._resolution) - __repr__ = __str__ - def transform_non_affine(self, xy): # MGDTODO: Math is hard ;( return xy @@ -359,8 +355,6 @@ def __init__(self, resolution): def __str__(self): return "{}({})".format(type(self).__name__, self._resolution) - __repr__ = __str__ - def transform_non_affine(self, ll): longitude = ll[:, 0:1] latitude = ll[:, 1:2] @@ -398,8 +392,6 @@ def __init__(self, resolution): def __str__(self): return "{}({})".format(type(self).__name__, self._resolution) - __repr__ = __str__ - def transform_non_affine(self, xy): x, y = xy.T z = np.sqrt(1 - (x / 4) ** 2 - (y / 2) ** 2) @@ -445,8 +437,6 @@ def __init__(self, resolution): def __str__(self): return "{}({})".format(type(self).__name__, self._resolution) - __repr__ = __str__ - def transform_non_affine(self, ll): def d(theta): delta = -(theta + np.sin(theta) - pi_sin_l) / (1 + np.cos(theta)) @@ -503,8 +493,6 @@ def __init__(self, resolution): def __str__(self): return "{}({})".format(type(self).__name__, self._resolution) - __repr__ = __str__ - def transform_non_affine(self, xy): x = xy[:, 0:1] y = xy[:, 1:2] @@ -557,8 +545,6 @@ def __init__(self, center_longitude, center_latitude, resolution): def __str__(self): return "{}({})".format(type(self).__name__, self._resolution) - __repr__ = __str__ - def transform_non_affine(self, ll): longitude = ll[:, 0:1] latitude = ll[:, 1:2] @@ -609,8 +595,6 @@ def __init__(self, center_longitude, center_latitude, resolution): def __str__(self): return "{}({})".format(type(self).__name__, self._resolution) - __repr__ = __str__ - def transform_non_affine(self, xy): x = xy[:, 0:1] y = xy[:, 1:2] diff --git a/lib/matplotlib/projections/polar.py b/lib/matplotlib/projections/polar.py index 79a4bb01cbb9..243e1be02371 100644 --- a/lib/matplotlib/projections/polar.py +++ b/lib/matplotlib/projections/polar.py @@ -49,8 +49,6 @@ def __str__(self): self._use_rmin, self._apply_theta_transforms)) - __repr__ = __str__ - def transform_non_affine(self, tr): xy = np.empty(tr.shape, float) @@ -115,8 +113,6 @@ def __str__(self): mtransforms._indent_str(self._scale_transform), mtransforms._indent_str(self._limits))) - __repr__ = __str__ - def get_matrix(self): if self._invalid: limits_scaled = self._limits.transformed(self._scale_transform) @@ -157,8 +153,6 @@ def __str__(self): self._use_rmin, self._apply_theta_transforms)) - __repr__ = __str__ - def transform_non_affine(self, xy): x = xy[:, 0:1] y = xy[:, 1:] @@ -503,8 +497,6 @@ def __str__(self): mtransforms._indent_str(self.pad), mtransforms._indent_str(repr(self.mode)))) - __repr__ = __str__ - def get_matrix(self): if self._invalid: if self.mode == 'rlabel': @@ -753,8 +745,6 @@ def __str__(self): mtransforms._indent_str(self._viewLim), mtransforms._indent_str(self._originLim))) - __repr__ = __str__ - def get_points(self): if self._invalid: points = self._viewLim.get_points().copy() diff --git a/lib/matplotlib/transforms.py b/lib/matplotlib/transforms.py index b1b79221500c..3676b278e512 100644 --- a/lib/matplotlib/transforms.py +++ b/lib/matplotlib/transforms.py @@ -1641,6 +1641,9 @@ def inverted(self): """ raise NotImplementedError() + def __repr__(self): + return str(self) + class TransformWrapper(Transform): """ @@ -1710,8 +1713,6 @@ def __str__(self): .format(type(self).__name__, _indent_str(self._child))) - __repr__ = __str__ - def frozen(self): return self._child.frozen() frozen.__doc__ = Transform.frozen.__doc__ @@ -1943,8 +1944,6 @@ def __str__(self): .format(type(self).__name__, _indent_str(self._mtx))) - __repr__ = __str__ - @staticmethod def from_values(a, b, c, d, e, f): """ @@ -2151,8 +2150,6 @@ def __str__(self): return ("{}()" .format(type(self).__name__)) - __repr__ = __str__ - def get_matrix(self): return self._mtx get_matrix.__doc__ = Affine2DBase.get_matrix.__doc__ @@ -2258,8 +2255,6 @@ def __str__(self): _indent_str(self._x), _indent_str(self._y))) - __repr__ = __str__ - def transform_non_affine(self, points): if self._x.is_affine and self._y.is_affine: return points @@ -2370,8 +2365,6 @@ def __str__(self): _indent_str(self._x), _indent_str(self._y))) - __repr__ = __str__ - def get_matrix(self): if self._invalid: if self._x == self._y: @@ -2492,8 +2485,6 @@ def __str__(self): _indent_str(self._a), _indent_str(self._b))) - __repr__ = __str__ - def transform_affine(self, points): return self.get_affine().transform(points) transform_affine.__doc__ = Transform.transform_affine.__doc__ @@ -2587,8 +2578,6 @@ def __str__(self): _indent_str(self._a), _indent_str(self._b))) - __repr__ = __str__ - def get_matrix(self): if self._invalid: self._mtx = np.dot( @@ -2658,8 +2647,6 @@ def __str__(self): _indent_str(self._boxin), _indent_str(self._boxout))) - __repr__ = __str__ - def get_matrix(self): if self._invalid: inl, inb, inw, inh = self._boxin.bounds @@ -2706,8 +2693,6 @@ def __str__(self): .format(type(self).__name__, _indent_str(self._boxout))) - __repr__ = __str__ - def get_matrix(self): if self._invalid: outl, outb, outw, outh = self._boxout.bounds @@ -2767,8 +2752,6 @@ def __str__(self): .format(type(self).__name__, _indent_str(self._boxin))) - __repr__ = __str__ - def get_matrix(self): if self._invalid: inl, inb, inw, inh = self._boxin.bounds @@ -2805,8 +2788,6 @@ def __str__(self): .format(type(self).__name__, _indent_str(self._t))) - __repr__ = __str__ - def get_matrix(self): if self._invalid: xt, yt = self._scale_trans.transform_point(self._t) From cbb72b14b2efab453f7a45b1dacc37fc0578540a Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sun, 19 Nov 2017 06:35:23 -0800 Subject: [PATCH 6/7] Factor out common _GeoTransform code. --- lib/matplotlib/projections/geo.py | 176 +++++++----------------------- 1 file changed, 40 insertions(+), 136 deletions(-) diff --git a/lib/matplotlib/projections/geo.py b/lib/matplotlib/projections/geo.py index 66fc179a9794..0696ce5882e1 100644 --- a/lib/matplotlib/projections/geo.py +++ b/lib/matplotlib/projections/geo.py @@ -19,10 +19,9 @@ from matplotlib.ticker import Formatter, Locator, NullLocator, FixedLocator, NullFormatter from matplotlib.transforms import Affine2D, BboxTransformTo, Transform + class GeoAxes(Axes): - """ - An abstract base class for geographic projections - """ + """An abstract base class for geographic projections.""" class ThetaFormatter(Formatter): """ Used to format the theta tick labels. Converts the native @@ -247,28 +246,37 @@ def drag_pan(self, button, key, x, y): pass -class AitoffAxes(GeoAxes): - name = 'aitoff' +class _GeoTransform(Transform): + # Factoring out some common functionality. + input_dims = 2 + output_dims = 2 + is_separable = False - class AitoffTransform(Transform): + def __init__(self, resolution): """ - The base Aitoff transform. + Create a new geographical transform. + + Resolution is the number of steps to interpolate between each input + line segment to approximate its path in curved space. """ - input_dims = 2 - output_dims = 2 - is_separable = False + Transform.__init__(self) + self._resolution = resolution - def __init__(self, resolution): - """ - Create a new Aitoff transform. Resolution is the number of steps - to interpolate between each input line segment to approximate its - path in curved Aitoff space. - """ - Transform.__init__(self) - self._resolution = resolution + def __str__(self): + return "{}({})".format(type(self).__name__, self._resolution) + + def transform_path_non_affine(self, path): + vertices = path.vertices + ipath = path.interpolated(self._resolution) + return Path(self.transform(ipath.vertices), ipath.codes) + transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ + + +class AitoffAxes(GeoAxes): + name = 'aitoff' - def __str__(self): - return "{}({})".format(type(self).__name__, self._resolution) + class AitoffTransform(_GeoTransform): + """The base Aitoff transform.""" def transform_non_affine(self, ll): longitude = ll[:, 0:1] @@ -291,27 +299,11 @@ def transform_non_affine(self, ll): return np.concatenate((x.filled(0), y.filled(0)), 1) transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ - def transform_path_non_affine(self, path): - vertices = path.vertices - ipath = path.interpolated(self._resolution) - return Path(self.transform(ipath.vertices), ipath.codes) - transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ - def inverted(self): return AitoffAxes.InvertedAitoffTransform(self._resolution) inverted.__doc__ = Transform.inverted.__doc__ - class InvertedAitoffTransform(Transform): - input_dims = 2 - output_dims = 2 - is_separable = False - - def __init__(self, resolution): - Transform.__init__(self) - self._resolution = resolution - - def __str__(self): - return "{}({})".format(type(self).__name__, self._resolution) + class InvertedAitoffTransform(_GeoTransform): def transform_non_affine(self, xy): # MGDTODO: Math is hard ;( @@ -335,25 +327,8 @@ def _get_core_transform(self, resolution): class HammerAxes(GeoAxes): name = 'hammer' - class HammerTransform(Transform): - """ - The base Hammer transform. - """ - input_dims = 2 - output_dims = 2 - is_separable = False - - def __init__(self, resolution): - """ - Create a new Hammer transform. Resolution is the number of steps - to interpolate between each input line segment to approximate its - path in curved Hammer space. - """ - Transform.__init__(self) - self._resolution = resolution - - def __str__(self): - return "{}({})".format(type(self).__name__, self._resolution) + class HammerTransform(_GeoTransform): + """The base Hammer transform.""" def transform_non_affine(self, ll): longitude = ll[:, 0:1] @@ -370,27 +345,11 @@ def transform_non_affine(self, ll): return np.concatenate((x, y), 1) transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ - def transform_path_non_affine(self, path): - vertices = path.vertices - ipath = path.interpolated(self._resolution) - return Path(self.transform(ipath.vertices), ipath.codes) - transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ - def inverted(self): return HammerAxes.InvertedHammerTransform(self._resolution) inverted.__doc__ = Transform.inverted.__doc__ - class InvertedHammerTransform(Transform): - input_dims = 2 - output_dims = 2 - is_separable = False - - def __init__(self, resolution): - Transform.__init__(self) - self._resolution = resolution - - def __str__(self): - return "{}({})".format(type(self).__name__, self._resolution) + class InvertedHammerTransform(_GeoTransform): def transform_non_affine(self, xy): x, y = xy.T @@ -417,25 +376,8 @@ def _get_core_transform(self, resolution): class MollweideAxes(GeoAxes): name = 'mollweide' - class MollweideTransform(Transform): - """ - The base Mollweide transform. - """ - input_dims = 2 - output_dims = 2 - is_separable = False - - def __init__(self, resolution): - """ - Create a new Mollweide transform. Resolution is the number of steps - to interpolate between each input line segment to approximate its - path in curved Mollweide space. - """ - Transform.__init__(self) - self._resolution = resolution - - def __str__(self): - return "{}({})".format(type(self).__name__, self._resolution) + class MollweideTransform(_GeoTransform): + """The base Mollweide transform.""" def transform_non_affine(self, ll): def d(theta): @@ -471,27 +413,11 @@ def d(theta): return xy transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ - def transform_path_non_affine(self, path): - vertices = path.vertices - ipath = path.interpolated(self._resolution) - return Path(self.transform(ipath.vertices), ipath.codes) - transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ - def inverted(self): return MollweideAxes.InvertedMollweideTransform(self._resolution) inverted.__doc__ = Transform.inverted.__doc__ - class InvertedMollweideTransform(Transform): - input_dims = 2 - output_dims = 2 - is_separable = False - - def __init__(self, resolution): - Transform.__init__(self) - self._resolution = resolution - - def __str__(self): - return "{}({})".format(type(self).__name__, self._resolution) + class InvertedMollweideTransform(_GeoTransform): def transform_non_affine(self, xy): x = xy[:, 0:1] @@ -523,13 +449,8 @@ def _get_core_transform(self, resolution): class LambertAxes(GeoAxes): name = 'lambert' - class LambertTransform(Transform): - """ - The base Lambert transform. - """ - input_dims = 2 - output_dims = 2 - is_separable = False + class LambertTransform(_GeoTransform): + """The base Lambert transform.""" def __init__(self, center_longitude, center_latitude, resolution): """ @@ -537,14 +458,10 @@ def __init__(self, center_longitude, center_latitude, resolution): to interpolate between each input line segment to approximate its path in curved Lambert space. """ - Transform.__init__(self) - self._resolution = resolution + _GeoTransform.__init__(self, resolution) self._center_longitude = center_longitude self._center_latitude = center_latitude - def __str__(self): - return "{}({})".format(type(self).__name__, self._resolution) - def transform_non_affine(self, ll): longitude = ll[:, 0:1] latitude = ll[:, 1:2] @@ -568,12 +485,6 @@ def transform_non_affine(self, ll): return np.concatenate((x, y), 1) transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ - def transform_path_non_affine(self, path): - vertices = path.vertices - ipath = path.interpolated(self._resolution) - return Path(self.transform(ipath.vertices), ipath.codes) - transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ - def inverted(self): return LambertAxes.InvertedLambertTransform( self._center_longitude, @@ -581,20 +492,13 @@ def inverted(self): self._resolution) inverted.__doc__ = Transform.inverted.__doc__ - class InvertedLambertTransform(Transform): - input_dims = 2 - output_dims = 2 - is_separable = False + class InvertedLambertTransform(_GeoTransform): def __init__(self, center_longitude, center_latitude, resolution): - Transform.__init__(self) - self._resolution = resolution + _GeoTransform.__init__(self, resolution) self._center_longitude = center_longitude self._center_latitude = center_latitude - def __str__(self): - return "{}({})".format(type(self).__name__, self._resolution) - def transform_non_affine(self, xy): x = xy[:, 0:1] y = xy[:, 1:2] From dbefd2739e4dee7f5bfe93890416e6e0a60994ad Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sun, 19 Nov 2017 10:05:33 -0800 Subject: [PATCH 7/7] Add whatsnew entry. --- .../20171119-transforms-repr.rst | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 doc/users/next_whats_new/20171119-transforms-repr.rst diff --git a/doc/users/next_whats_new/20171119-transforms-repr.rst b/doc/users/next_whats_new/20171119-transforms-repr.rst new file mode 100644 index 000000000000..2389141b6492 --- /dev/null +++ b/doc/users/next_whats_new/20171119-transforms-repr.rst @@ -0,0 +1,32 @@ +Improved `repr` for `Transform`\s +--------------------------------- + +`Transform`\s now indent their `repr`\s in a more legible manner: + +.. code-block:: ipython + + In [1]: l, = plt.plot([]); l.get_transform() + Out[1]: + CompositeGenericTransform( + TransformWrapper( + BlendedAffine2D( + IdentityTransform(), + IdentityTransform())), + CompositeGenericTransform( + BboxTransformFrom( + TransformedBbox( + Bbox(x0=-0.05500000000000001, y0=-0.05500000000000001, x1=0.05500000000000001, y1=0.05500000000000001), + TransformWrapper( + BlendedAffine2D( + IdentityTransform(), + IdentityTransform())))), + BboxTransformTo( + TransformedBbox( + Bbox(x0=0.125, y0=0.10999999999999999, x1=0.9, y1=0.88), + BboxTransformTo( + TransformedBbox( + Bbox(x0=0.0, y0=0.0, x1=6.4, y1=4.8), + Affine2D( + [[ 100. 0. 0.] + [ 0. 100. 0.] + [ 0. 0. 1.]])))))))