Skip to content

Commit 7125492

Browse files
authored
Merge pull request #17218 from anntzer/doctransformop
Document `Transform.__add__` and `.__sub__`.
2 parents a769d64 + cf2fe2d commit 7125492

File tree

2 files changed

+25
-13
lines changed

2 files changed

+25
-13
lines changed

doc/api/transformations.rst

+1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@
1414
BboxTransformFrom, ScaledTranslation, TransformedPath, nonsingular,
1515
interval_contains, interval_contains_open
1616
:show-inheritance:
17+
:special-members:
1718

lib/matplotlib/transforms.py

+24-13
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,9 @@ def __init_subclass__(cls):
12661266
def __add__(self, other):
12671267
"""
12681268
Compose two transforms together so that *self* is followed by *other*.
1269+
1270+
``A + B`` returns a transform ``C`` so that
1271+
``C.transform(x) == B.transform(A.transform(x))``.
12691272
"""
12701273
return (composite_transform_factory(self, other)
12711274
if isinstance(other, Transform) else
@@ -1340,24 +1343,32 @@ def contains_branch_seperately(self, other_transform):
13401343

13411344
def __sub__(self, other):
13421345
"""
1343-
Return a transform stack which goes all the way down self's transform
1344-
stack, and then ascends back up other's stack. If it can, this is
1345-
optimised::
1346+
Compose *self* with the inverse of *other*, cancelling identical terms
1347+
if any::
13461348
1347-
# normally
1348-
A - B == a + b.inverted()
1349+
# In general:
1350+
A - B == A + B.inverted()
1351+
# (but see note regarding frozen transforms below).
13491352
1350-
# sometimes, when A contains the tree B there is no need to
1351-
# descend all the way down to the base of A (via B), instead we
1352-
# can just stop at B.
1353+
# If A "ends with" B (i.e. A == A' + B for some A') we can cancel
1354+
# out B:
1355+
(A' + B) - B == A'
13531356
1354-
(A + B) - (B)^-1 == A
1357+
# Likewise, if B "starts with" A (B = A + B'), we can cancel out A:
1358+
A - (A + B') == B'.inverted() == B'^-1
13551359
1356-
# similarly, when B contains tree A, we can avoid descending A at
1357-
# all, basically:
1358-
A - (A + B) == ((B + A) - A).inverted() or B^-1
1360+
Cancellation (rather than naively returning ``A + B.inverted()``) is
1361+
important for multiple reasons:
13591362
1360-
For clarity, the result of ``(A + B) - B + B == (A + B)``.
1363+
- It avoids floating-point inaccuracies when computing the inverse of
1364+
B: ``B - B`` is guaranteed to cancel out exactly (resulting in the
1365+
identity transform), whereas ``B + B.inverted()`` may differ by a
1366+
small epsilon.
1367+
- ``B.inverted()`` always returns a frozen transform: if one computes
1368+
``A + B + B.inverted()`` and later mutates ``B``, then
1369+
``B.inverted()`` won't be updated and the last two terms won't cancel
1370+
out anymore; on the other hand, ``A + B - B`` will always be equal to
1371+
``A`` even if ``B`` is mutated.
13611372
"""
13621373
# we only know how to do this operation if other is a Transform.
13631374
if not isinstance(other, Transform):

0 commit comments

Comments
 (0)