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

Skip to content

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

Merged
merged 1 commit into from
Jun 18, 2021
Merged

Merge Colorbar and ColorbarBase. #20354

merged 1 commit into from
Jun 18, 2021

Conversation

anntzer
Copy link
Contributor

@anntzer anntzer commented Jun 3, 2021

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.

(See also #17189.)

PR Summary

PR Checklist

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (run flake8 on changed files to check).
  • New features are documented, with examples if plot related.
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).
  • Conforms to Matplotlib style conventions (install flake8-docstrings and run flake8 --docstring-convention=all).
  • New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).

@jklymak
Copy link
Member

jklymak commented Jun 3, 2021

I'll put as draft until at least #20327 gets in.

@jklymak jklymak marked this pull request as draft June 3, 2021 14:30
@anntzer
Copy link
Contributor Author

anntzer commented Jun 3, 2021

Yup, no hurries.

@anntzer anntzer marked this pull request as ready for review June 10, 2021 19:43
@jklymak jklymak assigned jklymak and unassigned jklymak Jun 10, 2021
@jklymak jklymak self-requested a review June 10, 2021 19:54

norm = colors.Normalize(clip=False)

To show the colors versus index instead of on a 0-1 scale, use::
Copy link
Member

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

Copy link
Contributor Author

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*
Copy link
Member

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?

Copy link
Contributor Author

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).

@@ -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
Copy link
Member

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?

Copy link
Contributor Author

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.

lambda self, CS, erase=True: (self, CS, erase))(
self, *args, **kwargs)
except TypeError:
self, levels, colors, linewidths, erase = (
Copy link
Member

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?

Copy link
Contributor Author

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.)

Copy link
Contributor

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

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'm not really sure add_lines should be public, but deprecating it is not the point of this PR.

Copy link
Member

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.

Copy link
Contributor Author

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:
Copy link
Member

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?

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 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.

Copy link
Contributor

@greglucas greglucas left a 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

lambda self, CS, erase=True: (self, CS, erase))(
self, *args, **kwargs)
except TypeError:
self, levels, colors, linewidths, erase = (
Copy link
Contributor

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

@anntzer
Copy link
Contributor Author

anntzer commented Jun 11, 2021

The refs should be fixed now.

@anntzer
Copy link
Contributor Author

anntzer commented Jun 18, 2021

Modified to use #20420.

Copy link
Member

@jklymak jklymak left a 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()
Copy link
Contributor

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?

Copy link
Member

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....

Copy link
Contributor Author

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.
Copy link
Contributor

@greglucas greglucas left a 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.

@greglucas greglucas merged commit b71ee62 into matplotlib:master Jun 18, 2021
@QuLogic QuLogic added this to the v3.5.0 milestone Jun 19, 2021
@anntzer anntzer deleted the cbb branch June 19, 2021 09:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants