-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
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
Conversation
The extension of AFFINE_ONLY invalidations into FULL invalidations in CompositeGenericTransform._invalidate_internal was too generous; it is only needed in case (b) , not in case (a). This is actually the argument made by Phil Elson (in https://discourse.matplotlib.org/t/16538/2, starting at "If the invalid part is a1...") when he first introduced the _invalidate_internal API, but for some reason his implementation further added case (a). Remove that case.
I suppose we could confirm with @pelson, though I don't know if he'd remember a post from 10 years ago. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logically, I agree. I don't remember the details though, naturally.
Seems strange that I didn't try to avoid unnecessarily invalidating the left-hand non-affine component. I suspect it is because in cartopy at least, there is only one non-affine path transformation in the stack, and it doesn't have an affine part to it, so never really came up.
(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: |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?)
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.)
There was a problem hiding this comment.
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.
The extension of AFFINE_ONLY invalidations into FULL invalidations in CompositeGenericTransform._invalidate_internal was too generous; it is only needed in case (b) , not in case (a). This is actually the argument made by Phil Elson (in
https://discourse.matplotlib.org/t/16538/2, starting at "If the invalid part is a1...") when he first introduced the _invalidate_internal API, but for some reason his implementation further added case (a). Remove that case.
PR Summary
PR Checklist
Documentation and Tests
pytest
passes)Release Notes
.. versionadded::
directive in the docstring and documented indoc/users/next_whats_new/
.. versionchanged::
directive in the docstring and documented indoc/api/next_api_changes/
next_whats_new/README.rst
ornext_api_changes/README.rst