Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Changing get_cmap to return copies of the registered colormaps.#16943

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
greglucas wants to merge2 commits intomatplotlib:masterfromgreglucas:get_cmap_copy

Conversation

greglucas
Copy link
Contributor

This is an alternative proposal compared to making Colormap objects themselves immutable as mentioned in#16296 (comment). I expect this to have some discussion about extensibility and future directions, so I consider this a proposal/idea PR. Previous discussion can be found in issues#16296 and#14645

Note that this isn't really deprecating anything, but it is changing some pretty significant behavior. I wasn't sure if it would need any deprecation/warnings put in somewhere, but figured that could wait until after some discussion as well.

PR Summary

Previously, callingplt.get_cmap() would return a pointer to the object, which would allow you to modify the built-ins unknowingly.

cmap=plt.get_cmap('viridis').set_over('b')

Previously, a second call to get the viridis colormap would return the modified colormap.
cmap == plt.get_cmap('viridis') # True
Now, it will return the original viridis built-in colormap.
cmap == plt.get_cmap('viridis') # False

Implications

  • Accessing colormaps through the pyplot interface could still mess people up since it is a single object still.
cmap=plt.cm.viridiscmap.set_over('b')cmap==plt.cm.viridis# Truecmap==plt.cm.get_cmap('viridis')# False
  • This also means that there are two copies of the colormap objects created initially now (one incmap_d and a second deepcopy that I made forlocals() to use with the pyplot interface.

  • Is there a way to make theplt.cm.viridis object point to the functionplt.get_cmap('viridis')? That may be and even nicer touch, but I couldn't think of anything quick off the top of my head.

  • I had to add an equals method to Colormaps to compare lookup tables rather than object pointers that were done before. This will initialize the lookup table if it wasn't already previously, possibly leading to a little more overhead if people are comparing lots of colormaps.

PR Checklist

  • Has Pytest style unit tests
  • Code isFlake 8 compliant
  • New features are documented, with examples if plot related
  • Documentation is sphinx and numpydoc compliant
  • Added an entry to doc/users/next_whats_new/ if major new feature (follow instructions in README.rst there)
  • Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way

@tacaswelltacaswell added this to thev3.3.0 milestoneMar 28, 2020
@tacaswell
Copy link
Member

I less disruptive approach to this would be to add acopy kwarg toget_cmap(). We could start off with it defaulting toFalse.

I think we need to preserve a way to mutate the global color map is that (for better or worse) we support passing the colormap as a string that we then look up for the user, ex

plt.get_cmap('viridis').set_bad('k')fig,ax=plt.subplots()ax.imshow(data,cmap='viridis')

Ifget_cmap always returned a copy that would be impossible.

@anntzer
Copy link
Contributor

If get_cmap always returned a copy that would be impossible.

I think that would be a good thing.

@tacaswell
Copy link
Member

I think that would be a good thing.

Fair, but that is too big of a change to make without lots (and lots) of warning a lead time. In the scale of things to break vs the gain for breaking them vs the potential cost to users of breaking them I don't think this one is worth it.

@anntzer
Copy link
Contributor

I think this is the kind of changes that can just get a standard deprecation warning (after something like#14645 goes in so that there's a reasonably simple alternative available) and we can even give it an extra release cycle of to give people more time to adapt, and we can always back out the change if too many people complain.
It's not as if this was some vague and obscure misfeature; in my view modifying the global cmap instance is a pretty big foot cannon.

jklymak reacted with thumbs up emoji

@greglucas
Copy link
ContributorAuthor

I think we are all on the same page that this is whatshould happen and just need to figure out the best path to get there.

The issue I see with adding a keyword argument is that it isn't really helping anyone to move in the new direction. How would people learn that they should set the keyword to True and why would I want to use that keyword argument? People who would want to use the argument are probably already copying the objects anyways.

The problem with a warning on everything is that I think the messages would get obnoxious for users who aren't actually modifying the built-ins. Although, now that I think about this a little more, maybe we could add in a_stale attribute in the meantime which is updated to True anytime aset_() is called and then if someone callsget_cmap() and that cmap has an_stale attribute we could warn that a preregistered cmap was modified and that is deprecated functionality in a future release.

My thought is that this is abug not a feature.

plt.get_cmap('viridis').set_bad('k')fig,ax=plt.subplots()ax.imshow(data,cmap='viridis')

If someone wants that functionality they should register the cmap back into the global state. This would be the proper usage of overwriting the built-in if one wants to do that.

plt.register_cmap(cmap=plt.get_cmap('viridis').set_bad('k'))fig,ax=plt.subplots()ax.imshow(data,cmap='viridis')

@greglucas
Copy link
ContributorAuthor

I added in a deprecation warning that I think will work to warn only when being used in the way we want to deprecate.

I wasn't sure how to add in the new state copies without undoing the previous global overriding, so I have left those calls commented in for now where they should go in a future release. I'm not sure how you approach a situation like this? Add a kwarg or new function with a note to remove or something similar?

@timhoffm
Copy link
Member

@greglucas Thanks, this is a reasonable aproach and the deprecation is consistent.

However, we need the discussion if we want to make colormaps immutable (c.f.#16296 (comment)). That would be an alternative approach. While technically orthogonal, it would lead to other deprecations and to other replacement code. We don't want to do both, and thus need a discussion before going one way or the other.

greglucas reacted with thumbs up emoji

@timhoffm
Copy link
Member

I wasn't sure how to add in the new state copies without undoing the previous global overriding, so I have left those calls commented in for now where they should go in a future release. I'm not sure how you approach a situation like this? Add a kwarg or new function with a note to remove or something similar?

We don't have a standard approach for this. Usually, we go through the deprecation warnings and it's rather self-evident what to change when removing them.

Previously, calling ``get_cmap()`` would return
the built-in Colormap. If you made modifications to that colormap, the
changes would be propagated in the global state. This function now
returns a copy of all registered colormaps to keep the built-in
Copy link
Member

Choose a reason for hiding this comment

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

"... copy of the requested colormap..."?

greglucas reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Should this even go into this now if it is a future change and there are not currently any behavior changes?

My thoughts are to actually break these commits up into two separate PRs. One with the deprecation warning/preparation for a future version. Then another one with the proposed copy code in it that could be pushed off for quite a while and discussed for immutability or not.

Copy link
Member

Choose a reason for hiding this comment

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

I personally think the globals should be immutable. If folks are modifying the global to then call again as a named colormap, then I think they were using a misfeature/bug.

I just gave a comment here because I was reading it, and had a quick thought. Please work out w/ Tim Hoffman how to do the rest of the PR, but this seems to be the right direction to be heading.

"colormap in this way has been deprecated. "
"Please register the colormap using "
"plt.register_cmap() before requesting "
"the modified colormap.")
Copy link
Member

@jklymakjklymakMar 29, 2020
edited
Loading

Choose a reason for hiding this comment

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

I understand this, but only because I read the thread. If I was a user who ran

plt.get_cmap('viridis').set_bad('k')fig,ax=plt.subplots()ax.imshow(data,cmap='viridis')

I'd have no idea what I was supposed to do here. I also don't think we should be encouraging any changing of the global state. I'd far rather tell folks that they should deal with the cmap object which is far less arcane than registering the global state:

cmp=plt.get_cmap('viridis').set_bad('k')fig,ax=plt.subplots()ax.imshow(data,cmap=cmp)

To that end, I'd say "Modifying a registered colormap is deprecated; make a new copy via cmp=plt.get_cmap('viridian') and modify the copy." ?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Unfortunately, that won't even work either! (which is why I think this is a bug) You would need to cmp=copy.copy(plt.get_cmap('viridian')) currently to get the desired functionality. The real problem is that further down if you go and request 'viridis' from a plot after doing a bunch of stuff, you will still get the bad colormap.

jklymak reacted with eyes emoji
@QuLogicQuLogic mentioned this pull requestMay 4, 2020
6 tasks
@QuLogicQuLogic modified the milestones:v3.3.0,v3.4.0May 5, 2020
@QuLogicQuLogic modified the milestones:v3.4.0,v3.5.0Jan 22, 2021
@jklymakjklymak marked this pull request as draftMay 11, 2021 15:52
@jklymak
Copy link
Member

Not sure if this is still the way we were planning to go here...

@greglucas
Copy link
ContributorAuthor

I will close this as it was really meant for the 3.3/3.4 timeframe.

We should try to get#18503 (or a similar proposal) across the line sooner rather than later I think. Users (#19609) are confused about the deprecation warnings (partially my fault at not being clear in the messaging). So, getting over the hurdle of back-compat concerns would be beneficial here.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@jklymakjklymakjklymak left review comments

Assignees
No one assigned
Projects
None yet
Milestone
v3.5.0
Development

Successfully merging this pull request may close these issues.

6 participants
@greglucas@tacaswell@anntzer@timhoffm@jklymak@QuLogic

[8]ページ先頭

©2009-2025 Movatter.jp