-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Merge Colorbar and ColorbarBase. #20354
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
I'll put as draft until at least #20327 gets in. |
Yup, no hurries. |
|
||
norm = colors.Normalize(clip=False) | ||
|
||
To show the colors versus index instead of on a 0-1 scale, use:: |
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.
not sure what versus index means here
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.
that's copypasted from the previous docstring, so let's not change that here.
norm=colors.NoNorm() | ||
In order to draw a colorbar not associated with other elements in the | ||
figure, e.g. when showing a colormap by itself, one can create an empty | ||
`.ScalarMappable`, or directly pass *cmap* and *norm* instead of *mappable* |
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.
what happens if for reasons you set everything to none?
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.
You get the usual defaults (cmap from rcParams["image.cmap"]
, linear norm).
lib/matplotlib/colorbar.py
Outdated
@@ -489,6 +503,37 @@ def __init__(self, ax, *, cmap=None, | |||
self.formatter = format # Assume it is a Formatter or None | |||
self.draw_all() | |||
|
|||
if isinstance(mappable, contour.ContourSet) and not mappable.filled: | |||
self.add_lines(mappable) # FIXME |
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.
what needs to be fixed here?
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.
oopsie, nothing anymore, that was from before I implemented the overloading in add_lines.
lib/matplotlib/colorbar.py
Outdated
lambda self, CS, erase=True: (self, CS, erase))( | ||
self, *args, **kwargs) | ||
except TypeError: | ||
self, levels, colors, linewidths, erase = ( |
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 is new, and probably needs a test. I don't actually understand what this lambda does and I find it quite unreadable. Same with the lambda above. You have used this lambda trick elsewhere, is it possible to encapsulate it as an _api
function that has some semantics?
Also, does this need an API change note? I am not clear on what API is even being changed here, but this seems somewhat unrelated to merging these two classes?
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.
Actually this is completely related to the merging of the two classes (and doesn't need an API change: it's here strictly for backcompat).
Previously, ColorbarBase.add_lines() had signature add_lines(self, levels, colors, linewidths, erase=True)
, whereas Colorbar.add_lines() had signature add_lines(self, CS, erase=True)
. Therefore, if we want to merge the two classes while maintaining backcompat, we need to support both calling conventions. In order to do so, we make add_lines()
take *args, **kwargs
, and then parse them using the helper lambdas: if self, *args, **kwargs
can be passed to lambda self, levels, colors, linewidths, erase=True: <thing>
, then the user called it using the ColorbarBase signature; otherwise, the user called it using the Colorbar signature. The helper lambdas then perform two tasks: 1) if the call has a valid parameter list, then assign the right values to levels, colors, etc., and 2), if the call has an invalid parameter list, generate a standard error message, using Python's standard machinery ("expected 4 args but got 2" or "got an unexpected arg 'foo'" or whatnot).
Perhaps that can go into an _api helper, but let's do that another time? (There's only one other use of the pattern in the library now, AFAICT, in QuadMesh.)
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.
Also note, both of these forms are inconsistent with Axes.add_lines :( So there are at least 3 different signatures floating around
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'm not really sure add_lines should be public, but deprecating it is not the point of this PR.
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.
OK, can you at least add a comment explaining what is going on? Again, this trick is very unintuitive to me, and if we are going to have very hard-to-follow code in the codebase, it at least needs comments explaining what the magical wand does.
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.
Actually, perhaps #20420 can go in first and I'll rebase this on top of it...
|
||
try: | ||
ax = self.mappable.axes | ||
except AttributeError: |
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 guess you aren't testing removing an axes with no mappable?
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 guess you meant a mappable with no axes? (there's always a mappable, once this PR goes in) Sure, that seems easy enough to add.
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 think this is a good simplification. I also agree with your final paragraph that some of the signatures should be deprecated in follow-up PRs.
I'm not sure what you typically do for old whats_new broken references.
/home/circleci/project/doc/users/prev_whats_new/whats_new_3.0.rst:63: WARNING: py:obj reference target not found: colorbar.ColorbarBase.minorticks_on
/home/circleci/project/doc/users/prev_whats_new/whats_new_3.0.rst:63: WARNING: py:obj reference target not found: colorbar.ColorbarBase.minorticks_off
/home/circleci/project/doc/users/prev_whats_new/whats_new_3.3.0.rst:287: WARNING: py:obj reference target not found: ColorbarBase.set_label
lib/matplotlib/colorbar.py
Outdated
lambda self, CS, erase=True: (self, CS, erase))( | ||
self, *args, **kwargs) | ||
except TypeError: | ||
self, levels, colors, linewidths, erase = ( |
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.
Also note, both of these forms are inconsistent with Axes.add_lines :( So there are at least 3 different signatures floating around
The refs should be fixed now. |
Modified to use #20420. |
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 seems great to me. I didn't really understand why there was a subclass, and getting rid of it makes life easier...
I guess discouraging ColorbarBase should happen at some point, and probably deserves an API-change note (i.e. ColorbarBase is now just an alias for Colorbar, and ColorbarBase will be removed in future Matplotlib)
colors = [c[0] for c in CS.tcolors] | ||
linewidths = [t[0] for t in CS.tlinewidths] | ||
else: | ||
self, levels, colors, linewidths, erase = params.values() |
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'm a bit confused that this path isn't covered by the tests... Above you say the other one is the deprecated signature, but it appears to be the only one used, so should this path be the deprecated signature instead?
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.
Yeah, good point - if we are gong to have the funky signature matching they should probably be tested....
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.
Good points; I went back to the old approach (of having one of the signatures forward to the other), so coverage should be fine now; and I tweaked the wording to not have to decide which of the signatures (if any) we really prefer. (I also removed the __signature__
patching.) We can always decide on the preferred signature in a followup PR...
ColorbarBase differs from Colorbar in that it is not associated with a ScalarMappable (but constructed from explicit cmap/norm), but we already document in Figure.colorbar that the preferred way to draw colorbars not associated with an existing artist is to create an empty ScalarMappable to provide `norm` and `cmap`. Hence, likewise merge Colorbar and ColorbarBase (creating the ScalarMappable on-the-fly if no mappable is passed to the constructor), which should make the APIs clearer. (Note that we are already discouraging users to directly call either class' constructors, anyways). We could deprecate the backcompat APIs (i.e., the `ColorbarBase` alias, the `cmap` and `norm` kwargs, and the different semantics of `add_lines`), but that can be done later; this PR should be entirely backcompatible.
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 like this consolidation as well.
ColorbarBase differs from Colorbar in that it is not associated with a
ScalarMappable (but constructed from explicit cmap/norm), but we already
document in Figure.colorbar that the preferred way to draw colorbars not
associated with an existing artist is to create an empty ScalarMappable
to provide
norm
andcmap
.Hence, likewise merge Colorbar and ColorbarBase (creating the
ScalarMappable on-the-fly if no mappable is passed to the constructor),
which should make the APIs clearer. (Note that we are already
discouraging users to directly call either class' constructors,
anyways). We could deprecate the backcompat APIs (i.e., the
ColorbarBase
alias, thecmap
andnorm
kwargs, and the differentsemantics of
add_lines
), but that can be done later; this PR should beentirely backcompatible.
(See also #17189.)
PR Summary
PR Checklist
pytest
passes).flake8
on changed files to check).flake8-docstrings
and runflake8 --docstring-convention=all
).doc/users/next_whats_new/
(follow instructions in README.rst there).doc/api/next_api_changes/
(follow instructions in README.rst there).