Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Limit full-invalidation of CompositeGenericTransforms. #25291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 26, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions lib/matplotlib/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2368,14 +2368,9 @@ def frozen(self):
return frozen

def _invalidate_internal(self, level, invalidating_node):
# In some cases for a composite transform, an invalidating call to
# AFFINE_ONLY needs to be extended to invalidate the NON_AFFINE part
# too. These cases are when the right hand transform is non-affine and
# either:
# (a) the left hand transform is non affine
# (b) it is the left hand node which has triggered the invalidation
if (not self._b.is_affine and
(not self._a.is_affine or invalidating_node is self._a)):
# When the left child is invalidated at AFFINE_ONLY level and the right child is
# non-affine, the composite transform is FULLY invalidated.
if invalidating_node is self._a and not self._b.is_affine:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just be invalidating_node is self._a then, no? If _b is non affine, it is a full invalidation needed. If _b is affine, then an affine_only invalidation is the same as full anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so? If _a is non affine but invalidated at affine level, and _b is affine, then we need to invalidate the composite only at affine level and that's not equivalent to a full invalidation.
(Can you confirm?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree. Your example demonstrates an optimisation that I would have lost.

The other optimisation that we lose with the current approach is that we over-invalidate the first composite in that case:

(c1, a1, c2, a2)

Suppose we were effectively invalidating a1 (lhs @ AFFINE_ONLY), then we ideally really only want to invalidate (a1, c2, a2) - c1 is fine, but our current implementation is upgraded to INVALID_FULL. I wonder if we would be better changing the code to:

if invalidating_node is self._a:
    super()._invalidate_internal(Transform._INVALID_FULL, self._b)
super()._invalidate_internal(level, invalidating_node)

I don't know the implications, and whether this is something that would be worse than the current approach, but perhaps interesting to explore?

It would be great if we could test all of this - unfortunately though I didn't introduce unit-tests for these changes when I first did them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the code is currently really architected to support this kind of partial invalidations? (With the patch you propose, I think(?) the super()._invalidate_internal(FULL, self._b) will recurse to the current transform anyways as it's in self._b._parents.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, agreed. Your implementation looks good IMO.

level = Transform._INVALID_FULL
super()._invalidate_internal(level, invalidating_node)

Expand Down