-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Optimize imshow #26335
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
Optimize imshow #26335
Conversation
@@ -735,5 +735,5 @@ def _ensure_cmap(cmap): | |||
cmap_name = cmap if cmap is not None else mpl.rcParams["image.cmap"] | |||
# use check_in_list to ensure type stability of the exception raised by | |||
# the internal usage of this (ValueError vs KeyError) | |||
_api.check_in_list(sorted(_colormaps), cmap=cmap_name) |
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 matters for the printed error message when the colormap is invalid. (We could instead ensure that _colormaps is always sorted by sorting it whenever a new item is added, though.)
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 see. We could ensure the ordering of _colormaps
by adding c._cmaps = {k: c._cmaps[k] for k in sorted(c._cmaps)}
at the end of ColormapRegistry.register
. Under the assumption that number of colormaps added is reasonable, this will not have any other negative performance impact.
Another option is to replace the code with
if not cmap_name in _colormaps:
_api.check_in_list(sorted(_colormaps), cmap=cmap_name)
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.
Making sure that __iter__
on ColormapRegistry
is always sorted is probably the best option (rather than mucking with dictionary order we can keep a self._sorted_keys = sorted(self._cmap)
attribute and iterate over that in __iter__
.
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.
but the if not in...
is also fine (as I see you already pushed that).
if A.mask is False or not A.mask.shape: | ||
A = A.data |
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.
Another way of testing:
if A.mask is False or not A.mask.shape: | |
A = A.data | |
try: | |
no_mask = not bool(A.mask) | |
except ValueError: | |
no_mask = False | |
if no_mask: | |
A = A.data |
Numpy generated a ValueError
when testing an array for truth value.
Coverage was complaining because the number of lines of code was reduced. I added a few simple tests for |
Is Some of the codecov failures sort them selves out when all of the CI jobs upload their results and are processed (as some of the tests are platform specific) |
The |
Maybe directly testing EDIT: overall I think it's OK for codecov to decrease percentage in a PR if its due to code removal. It seems confusing to add an unrelated test just to make our tool happy. Maybe consider moving the test improvements to a separate PR? |
PR summary
In this PR we apply some micro optimizations to improve the imshow performance. Benchmark:
Notes:
MaskedArray
in case the mask isFalse
(e.g. images without a NaN or Inf value)np.ma.masked_invalid
undoes theshrink_mask
fromnp.ma.masked_where
, but matplotlib applies it again. So it is faster to callnp.ma.masked_where
directlyNormalize.autoscale_None
. There both the setting ofvmin
andvmax
triggers_changed
. It is faster to first set vmin and vmax (without triggering _changed) and then calling _changed. This would require a new methodset_vmin_vmax
or some other mechanism to avoid triggering_changed
twice.Benchmark script:
PR checklist