Skip to content

Commit aa78da9

Browse files
committed
Autodetect some transform properties.
- 1d transforms are always separable, no need to repeat `is_separable = True` again and again. - If a subclass overrides `inverted()` then it is most likely invertible (though not always), no need to repeat `has_inverse = True` again and again (but subclasses can always override to `has_inverse = False`).
1 parent d511ab8 commit aa78da9

File tree

3 files changed

+31
-51
lines changed

3 files changed

+31
-51
lines changed

examples/scales/custom_scale.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,7 @@ class MercatorLatitudeTransform(mtransforms.Transform):
114114
# being connected together. When defining transforms for a
115115
# scale, which are, by definition, separable and have only one
116116
# dimension, these members should always be set to 1.
117-
input_dims = 1
118-
output_dims = 1
119-
is_separable = True
120-
has_inverse = True
117+
input_dims = output_dims = 1
121118

122119
def __init__(self, thresh):
123120
mtransforms.Transform.__init__(self)
@@ -150,10 +147,7 @@ def inverted(self):
150147
self.thresh)
151148

152149
class InvertedMercatorLatitudeTransform(mtransforms.Transform):
153-
input_dims = 1
154-
output_dims = 1
155-
is_separable = True
156-
has_inverse = True
150+
input_dims = output_dims = 1
157151

158152
def __init__(self, thresh):
159153
mtransforms.Transform.__init__(self)
@@ -165,6 +159,7 @@ def transform_non_affine(self, a):
165159
def inverted(self):
166160
return MercatorLatitudeScale.MercatorLatitudeTransform(self.thresh)
167161

162+
168163
# Now that the Scale class has been defined, it must be registered so
169164
# that ``matplotlib`` can find it.
170165
mscale.register_scale(MercatorLatitudeScale)

lib/matplotlib/scale.py

Lines changed: 9 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,7 @@ class FuncTransform(Transform):
128128
forward and inverse transform.
129129
"""
130130

131-
input_dims = 1
132-
output_dims = 1
133-
is_separable = True
134-
has_inverse = True
131+
input_dims = output_dims = 1
135132

136133
def __init__(self, forward, inverse):
137134
"""
@@ -205,10 +202,7 @@ def set_default_locators_and_formatters(self, axis):
205202

206203
@cbook.deprecated("3.1", alternative="LogTransform")
207204
class LogTransformBase(Transform):
208-
input_dims = 1
209-
output_dims = 1
210-
is_separable = True
211-
has_inverse = True
205+
input_dims = output_dims = 1
212206

213207
def __init__(self, nonpos='clip'):
214208
Transform.__init__(self)
@@ -224,10 +218,7 @@ def __str__(self):
224218

225219
@cbook.deprecated("3.1", alternative="InvertedLogTransform")
226220
class InvertedLogTransformBase(Transform):
227-
input_dims = 1
228-
output_dims = 1
229-
is_separable = True
230-
has_inverse = True
221+
input_dims = output_dims = 1
231222

232223
def transform_non_affine(self, a):
233224
return ma.power(self.base, a)
@@ -285,10 +276,7 @@ def inverted(self):
285276

286277

287278
class LogTransform(Transform):
288-
input_dims = 1
289-
output_dims = 1
290-
is_separable = True
291-
has_inverse = True
279+
input_dims = output_dims = 1
292280

293281
def __init__(self, base, nonpos='clip'):
294282
Transform.__init__(self)
@@ -326,10 +314,7 @@ def inverted(self):
326314

327315

328316
class InvertedLogTransform(InvertedLogTransformBase):
329-
input_dims = 1
330-
output_dims = 1
331-
is_separable = True
332-
has_inverse = True
317+
input_dims = output_dims = 1
333318

334319
def __init__(self, base):
335320
Transform.__init__(self)
@@ -466,10 +451,7 @@ def get_transform(self):
466451

467452

468453
class SymmetricalLogTransform(Transform):
469-
input_dims = 1
470-
output_dims = 1
471-
is_separable = True
472-
has_inverse = True
454+
input_dims = output_dims = 1
473455

474456
def __init__(self, base, linthresh, linscale):
475457
Transform.__init__(self)
@@ -495,10 +477,7 @@ def inverted(self):
495477

496478

497479
class InvertedSymmetricalLogTransform(Transform):
498-
input_dims = 1
499-
output_dims = 1
500-
is_separable = True
501-
has_inverse = True
480+
input_dims = output_dims = 1
502481

503482
def __init__(self, base, linthresh, linscale):
504483
Transform.__init__(self)
@@ -610,10 +589,7 @@ def get_transform(self):
610589

611590

612591
class LogitTransform(Transform):
613-
input_dims = 1
614-
output_dims = 1
615-
is_separable = True
616-
has_inverse = True
592+
input_dims = output_dims = 1
617593

618594
def __init__(self, nonpos='mask'):
619595
Transform.__init__(self)
@@ -638,10 +614,7 @@ def __str__(self):
638614

639615

640616
class LogisticTransform(Transform):
641-
input_dims = 1
642-
output_dims = 1
643-
is_separable = True
644-
has_inverse = True
617+
input_dims = output_dims = 1
645618

646619
def __init__(self, nonpos='mask'):
647620
Transform.__init__(self)

lib/matplotlib/transforms.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,9 +1191,9 @@ class Transform(TransformNode):
11911191
- :attr:`input_dims`
11921192
- :attr:`output_dims`
11931193
- :meth:`transform`
1194-
- :attr:`is_separable`
1195-
- :attr:`has_inverse`
1196-
- :meth:`inverted` (if :attr:`has_inverse` is True)
1194+
- :attr:`is_separable` (defaults to True for 1d -> 1d transforms)
1195+
- :meth:`inverted` (if an inverse exists)
1196+
- :attr:`has_inverse` (defaults to True if :meth:`inverted` is overridden)
11971197
11981198
If the transform needs to do something non-standard with
11991199
:class:`matplotlib.path.Path` objects, such as adding curves
@@ -1213,11 +1213,25 @@ class Transform(TransformNode):
12131213
Must be overridden (with integers) in the subclass.
12141214
"""
12151215

1216+
is_separable = False
1217+
"""True if this transform is separable in the x- and y- dimensions."""
1218+
12161219
has_inverse = False
12171220
"""True if this transform has a corresponding inverse transform."""
12181221

1219-
is_separable = False
1220-
"""True if this transform is separable in the x- and y- dimensions."""
1222+
def __init_subclass__(cls):
1223+
# 1d transforms are always separable; we assume higher-dimensional ones
1224+
# are not but subclasses can also directly set is_separable.
1225+
if ("is_separable" not in vars(cls) # Was it overridden explicitly?
1226+
and cls.input_dims == cls.output_dims == 1):
1227+
cls.is_separable = True
1228+
# Transform.inverted raises NotImplementedError; we assume that if this
1229+
# is overridden then the transform is invertible but subclass can also
1230+
# directly set has_inverse.
1231+
if ("has_inverse" not in vars(cls) # Was it overridden explicitly?
1232+
and hasattr(cls, "inverted")
1233+
and cls.inverted is not Transform.inverted):
1234+
cls.has_inverse = True
12211235

12221236
def __add__(self, other):
12231237
"""
@@ -1733,8 +1747,6 @@ class Affine2DBase(AffineBase):
17331747
Subclasses of this class will generally only need to override a
17341748
constructor and :meth:`get_matrix` that generates a custom 3x3 matrix.
17351749
"""
1736-
has_inverse = True
1737-
17381750
input_dims = 2
17391751
output_dims = 2
17401752

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy