8000 MNT: Remove cmap_d colormap access by greglucas · Pull Request #22298 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

MNT: Remove cmap_d colormap access #22298

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 2 commits into from
May 6, 2022
Merged

Conversation

greglucas
Copy link
Contributor

PR Summary

This is the removal of the deprecated mpl.cm.cmap_d dictionary. This is related to #20853, but does not close that as none of the mpl.cm globals are deprecated here.

Note that rather than adding pop() to the Registry, I went with the unregister() that was already on cm.unregister_cmap(). I'm not sure if we'd rather it behave like a dictionary with item access/removal that way, or with the register/unregister methods. I don't have a major preference one way or the other.

PR Checklist

Tests and Styling

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (install flake8-docstrings and run flake8 --docstring-convention=all).

Documentation

  • New features are documented, with examples if plot related.
  • 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).
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).

@greglucas greglucas force-pushed the rm-cmapd branch 3 times, most recently from ecb5c08 to fce605e Compare January 24, 2022 15:08
@tacaswell tacaswell added this to the v3.6.0 milestone Jan 24, 2022
if not force and name in self._builtin_cmaps:
msg = f"Trying to re-register the builtin cmap {name!r}."
raise ValueError(msg)
elif not force:
raise ValueError(
f'A colormap named "{name}" is already registered.')
else:
_api.warn_external(f"Trying to register the cmap {name!r} "
"which already exists.")
Copy link
Member

Choose a reason for hiding this comment

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

Would reorder to

Suggested change
if not force and name in self._builtin_cmaps:
msg = f"Trying to re-register the builtin cmap {name!r}."
raise ValueError(msg)
elif not force:
raise ValueError(
f'A colormap named "{name}" is already registered.')
else:
_api.warn_external(f"Trying to register the cmap {name!r} "
"which already exists.")
if force:
_api.warn_external(f"Trying to register the cmap {name!r} "
"which already exists.")
else:
raise ValueError(
f"Trying to re-register the builtin cmap {name!r}."
if name in self._builtin_cmaps else
f'A colormap named "{name}" is already registered.')

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! This feels a bit awkward to me in general... I'm actually wondering if want to outright refuse to override a builtin? Right now we could use force=True and replace the builtin, but in unregister we don't allow that removal.

Copy link
Member

Choose a reason for hiding this comment

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

Good point. I was just cleaning up the structure, not considering something else. But I agree: We should not allow overriding builtins. Please change.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, I forgot to look at our current function. Unfortunately cm.register_cmap() doesn't use force, it uses override_builtin, even more explicitly allowing this behavior. So, I'm not sure how we want to handle this. I really don't think people should be changing a colormap in their underlying library and then re-registering it as the same name, but apparently there are a few (~2) cases that do that :(
https://github.com/search?q=override_builtin&type=issues

Copy link
Member

Choose a reason for hiding this comment

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

We have override_builtin for compatibility (#18503 (comment)) and at least for now cannot get rid of it. However, I don't want to have that in the new ColormapRegistry API. Since we're here switching to having the registry as the underlying structure, we have to feed that parameter in privately. Either using a private parameter

def register_cmap(...):
    ...
    _colormaps.register(cmap, name=name, force=True, _override_builtin=override_builtin)

or using a private flag (with uglier code, but slight peference since it does not show up in the docs):

def register_cmap(...):
    ...
    _colormaps._allow_override_builtin = override_builtin
    _colormaps.register(cmap, name=name, force=True)
    _colormaps._allow_override_builtin = False

@timhoffm
Copy link
Member
timhoffm commented Jan 26, 2022

Note that rather than adding pop() to the Registry, I went with the unregister() that was already on cm.unregister_cmap(). I'm not sure if we'd rather it behave like a dictionary with item access/removal that way, or with the register/unregister methods. I don't have a major preference one way or the other.

👍 unregister() is the better approach. Colormaps does intentionally not take on the full MutableMapping API. Register/unregister are similar to insertion/deletion but follow special rules, so we don't want to extend the mapping analogy to the modification API.

@greglucas greglucas force-pushed the rm-cmapd branch 4 times, most recently from d009a4b to 432c355 Compare January 28, 2022 14:36
cmap._global = True
_cmap_registry[name] = cmap
return
# override_builtin is allowed here for backward compatbility
Copy link
Member

Choose a reason for hiding this comment

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

IMHO we should deprecate overwriting builtin colormaps. But that can be a separate PR.

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 agree with deprecating that functionality and saving it for a separate PR :)

@greglucas
Copy link
Contributor Author

Ping for a second review on this deprecation removal.

Copy link
Member
@tacaswell tacaswell left a comment

Choose a reason for hiding this comment

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

I pushed an additional commit with a new test. @greglucas or anyone can merge on CI green, but would like if at least one more person looked at the test I added.

greglucas and others added 2 commits May 5, 2022 18:44
The existing test bounced on an earlier code path.  This restores missing
coverage.
@greglucas greglucas merged commit cb28f3a into matplotlib:main May 6, 2022
@greglucas greglucas deleted the rm-cmapd branch May 6, 2022 02:22
@neutrinoceros
Copy link
Contributor
neutrinoceros commented May 6, 2022

Hi ! This breaks yt since it is using cmap_d internally. I see that it was considered deprecated but we never caught that despite trying to treat warnings as errors in CI. I'm not asking for it to be reverted, I just wanted to raise awareness that maybe the deprecation warning wasn't working as intended.

edit: Nevermind, I just found that we had internal knowledge of this deprecation, just a somewhat improper workaround. Carry on !

@timhoffm
Copy link
Member
timhoffm commented May 6, 2022

Thanks for the report. For the deprecation period cmap_d has been a proxy to the original dict, which should warn upon access. Maybe we forgot to issue a warning for one case? How are you using cmap_d?

@neutrinoceros
Copy link
Contributor

For reference this is the current state of yt
https://github.com/yt-project/yt/blob/6270f345039f39d25eff8db3cbda7739dbb99f3a/yt/visualization/color_maps.py#L90-L93

I think this was written as a quick workaround when cmap_d was deprecated, but it doesn't follow the recommended alternative, so this is definitely on us.

@timhoffm
Copy link
Member
timhoffm commented May 6, 2022

Ah, you have gated against the new version, but are trying to get the registry via a private attribute (which we have changed here).

https://github.com/yt-project/yt/blob/6270f345039f39d25eff8db3cbda7739dbb99f3a/yt/visualization/color_maps.py#L91

You should instead use matplotlib.colormaps or pyplot.colormaps.

Note also, that you use plt.colormaps() in that module twice, which returns a list of colormaps. This is continued to be supported, but the recommended way is to simply use plt.colormaps here as well, since plt.colormaps is now the registry/container.

@neutrinoceros
Copy link
Contributor

Thanks @timhoffm, that's gold ! you're welcome to review my fix for this if you want to yt-project/yt#3912
and I suggest we move the discussion there if needed. Apologies for the noise everyone !

@greglucas
Copy link
Contributor Author

Thanks for testing the upcoming changes so fast, @neutrinoceros! Also an FYI since it looks like you're building from MPL and numpy source, we do upload main-branch wheels to: https://anaconda.org/scipy-wheels-nightly if it would be helpful to install from the binary instead.

QuLogic added a commit to QuLogic/matplotlib that referenced this pull request Aug 23, 2022
This was put into effect in matplotlib#22298, but was not given an API note.
QuLogic added a commit to QuLogic/matplotlib that referenced this pull request Aug 23, 2022
This was put into effect in matplotlib#22298, but was not given an API note.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants
0