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

Skip to content

scatter() should not rescale if norm is given #15769

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
Jan 1, 2020

Conversation

timhoffm
Copy link
Member

@timhoffm timhoffm commented Nov 24, 2019

PR Summary

Fixes #14603.

The brings the behavior in line with the scatter documentation:

vmin and vmax are ignored if you pass a norm instance.

Also, when a norm is given, we shouldn't autoscale.

Update: After discussion, the new behavior in this PR is #15769 (comment). Docs are updated accordingly.

@timhoffm timhoffm added this to the v3.3.0 milestone Nov 24, 2019
@timhoffm timhoffm force-pushed the fix-scatter-vmin-norm branch 2 times, most recently from c61074d to c4b1e02 Compare November 24, 2019 20:01
@anntzer
Copy link
Contributor

anntzer commented Nov 24, 2019

The same piece of code exists in imshow() (with the same doc as for scatter). Does it also need to be fixed there?

@timhoffm timhoffm force-pushed the fix-scatter-vmin-norm branch from c4b1e02 to 90468b0 Compare November 25, 2019 18:45
@anntzer
Copy link
Contributor

anntzer commented Nov 25, 2019

There's a few others which may need the same treatment (haven't fully checked) -- hexbin, pcolor, pcolormesh, pcolorfast. Maybe worth extracting into a separate function?

@timhoffm timhoffm force-pushed the fix-scatter-vmin-norm branch from 90468b0 to f0e007c Compare November 25, 2019 22:23
@timhoffm
Copy link
Member Author

This is now a private method ScalarMappable._scale_norm. While, theoretically, it could be useful for third-parties as well, I'm not 100% sure on the naming and scope of the method. Therefore, I'd leave it private for now.

The whole mappable initialization is a bit of a beast because the data are not part of the constructor and scaling depends on the data. Might be possible to untangle that further but that's for another PR.

@@ -6341,10 +6330,9 @@ def pcolorfast(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
self.add_image(im)
ret = im

if vmin is not None or vmax is not None:
ret.set_clim(vmin, vmax)
Copy link
Member Author

Choose a reason for hiding this comment

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

This was actually a bug. it should have been inside the np.dim(C) == 2 because RGB(A) data also do not need a set_clim.

@anntzer
Copy link
Contributor

anntzer commented Nov 25, 2019

Should the change in behavior (even if arguably a bugfix) be documented?

@timhoffm timhoffm force-pushed the fix-scatter-vmin-norm branch from f0e007c to 813e3f1 Compare November 25, 2019 22:49
@timhoffm
Copy link
Member Author

Should the change in behavior (even if arguably a bugfix) be documented?

Not sure. Do we document bugfixes? By their nature they change the behavior. But they are not an API change with respect to the intention. Usually people won't have to change their code because of that. If we want to document still, we should have a seprate bugfixes category.

@anntzer
Copy link
Contributor

anntzer commented Nov 26, 2019

Actually, taking a step back... isn't this going to break people who are e.g. calling imshow(..., norm=LogNorm(), vmin=someval, vmax=someotherval)? Admittedly they could just pass vmin/vmax to the LogNorm constructor (so perhaps breaking them is fine -- with the proper warning yada yada), but I don't think such cases are rare?

@timhoffm
Copy link
Member Author

timhoffm commented Nov 26, 2019

isn't this going to break people who are e.g. calling imshow(..., norm=LogNorm(), vmin=someval, vmax=someotherval)?

Yes. So to be defensive we want:

  • imshow(..., vmin=a, vmax=b) - ok
  • imshow(..., norm=LogNorm()) - ok
  • imshow(..., norm=LogNorm(a, b)) - ok
  • imshow(..., norm=LogNorm(), vmin=a, vmax=b) - deprecated, but scale; use LogNorm(a, b) instead
  • imshow(..., norm=LogNorm(a, b), vmin=c, vmax=d) - deprecated, should we scale because that is the current behavior or not scale because that's what the documentation says? still scale because that's the current actual behavior.

@anntzer
Copy link
Contributor

anntzer commented Nov 26, 2019

Actually, now that I think of it again, it seems a bit gratuitious to forbid norm=LogNorm(), vmin=..., vmax=.... I think the only thing that needs to be warned against is if the norm already has vmin or vmax set and vmin is passed separately as well. (As to the behavior in that case, I think it's better to just keep what the current behavior is (assuming it is indeed consistent across plotting methods...) and adjust the doc accordingly.)

@timhoffm
Copy link
Member Author

I feel a bit different about norm=LogNorm(), vmin=..., vmax=....

My interpretation of a pure vmin=..., vmax=... is that it's a convenience shourtcut for "create Normalize with these limits" without having to explicitly import Normalize. On that background, norm=LogNorm(), vmin=..., vmax=..., feels a bit odd. It does not create a norm but modifies the existing norm (but then again only if that norm has no explicit limits). Stating this correctly in the docstring is cumbersome, and IMHO a hint that it's not a good API. Moreover, it is longer and less clear than norm=LogNorm(vmin=..., vmax=...).

Side remark: vmin, vmax would actually not have been necessary. One could have had a clearer interface that accepts norm=(vmin, vmax) as a shortcut for norm=Normalize(vmin, vmax). This would not have raised this issue that multiple parameters affect the same logic and we have to make sure all combinations of these parameters are handled reasonably. However, I acknowedge that vmin, vmax are common and widely used parameter and thus should stay for the case that norm is not given.

@anntzer
Copy link
Contributor

anntzer commented Nov 27, 2019

I agree norm=(vmin, vmax) would have been nice but that ship has sailed. I guess I'm -0 on deprecating norm=LogNorm(), vmin=..., vmax=... but am not even close to wanting to block it either.

@timhoffm timhoffm force-pushed the fix-scatter-vmin-norm branch 2 times, most recently from d2c7af2 to eb42e75 Compare November 28, 2019 21:16
@timhoffm
Copy link
Member Author

I've decided to move forward with deprecating simultaneous use of norm and vmin/vmax. Let's see what others say.

@timhoffm timhoffm force-pushed the fix-scatter-vmin-norm branch 2 times, most recently from 64685ac to c29df1b Compare November 29, 2019 00:34
@anntzer
Copy link
Contributor

anntzer commented Nov 29, 2019

Actually looking at this again (^2), if we want to go in this direction, perhaps (in a separate PR) we can indeed add support for norm=(vmin, vmax) and "soft-deprecate" vmin=..., vmax=...? (hide it behind kwargs, don't mention them in the main docs but only as an aside to the docs of norm?)

@timhoffm
Copy link
Member Author

timhoffm commented Dec 1, 2019

perhaps (in a separate PR) we can indeed add support for norm=(vmin, vmax) and "soft-deprecate" vmin=..., vmax=...? (hide it behind kwargs, don't mention them in the main docs but only as an aside to the docs of norm?)

I would support that direction, but that's definitively something for another PR. Also the name norm is a bit too technical. If I was to design this anew I would propbably go for something like cscale in resemblance to cmap. It would need more discussion if we see benefit in larger a soft-deprecation to clean up the API.

For this PR, let's just make the existing API behave consistently and match the documentation.

@jklymak
Copy link
Member

jklymak commented Dec 13, 2019

vmin=a, vmax=b is extremely ingrained... I know what a norm is now, but found the concept pretty confusing when I started using matplotlib, not helped by the fact it was almost completely undocumented until I wrote https://matplotlib.org/3.1.1/tutorials/colors/colormapnorms.html. So I think it'd be tough to get vmin and vmax deprecated.

Given that, I'm somewhat skeptical about disallowing norm=LogNorm(), vmin=-3 etc. though I guess thats somewhat more justified.

Copy link
Member

@efiring efiring left a comment

Choose a reason for hiding this comment

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

Deprecations are annoying, but so is an overly complicated API. I think that this cleanup is in the best long-term interest of mpl.

Copy link
Contributor

@anntzer anntzer left a comment

Choose a reason for hiding this comment

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

Approving (modulo one minor nit that can be ignored), but I'll leave a few more days for others to comment (if any) because I'm only 95% sure it's a good idea :)

@timhoffm timhoffm force-pushed the fix-scatter-vmin-norm branch from f5d9116 to 5a1a654 Compare December 21, 2019 15:29
@timhoffm timhoffm force-pushed the fix-scatter-vmin-norm branch from 5a1a654 to 0a2f082 Compare January 1, 2020 13:53
Copy link
Contributor

@anntzer anntzer left a comment

Choose a reason for hiding this comment

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

can selfmerge postci

@timhoffm timhoffm merged commit 981b82e into matplotlib:master Jan 1, 2020
@timhoffm timhoffm deleted the fix-scatter-vmin-norm branch January 1, 2020 15:12
@tacaswell
Copy link
Member

This is a case were we are going to have to be sensitive to any protest from users.

Agree with @jklymak that deprecating vmin and vmax will be a hard lift, and one I am not sure we should try. I have frequently had the use case were I want to set just the min or just the max which the norm=(vmin, vmax) formulation makes awkward.

@timhoffm
Copy link
Member Author

timhoffm commented Jan 2, 2020

Let's see if this deprecation causes user feedback.

I'm not sure either if we finally want to deprecate vmin, vmax. That could be discussed some time in the future. I have no actions planned in that direction so far.

@anntzer
Copy link
Contributor

anntzer commented Jan 2, 2020

FWIW norm=(None, 42) should work? (I'm not claiming it's a great API though.)

@tacaswell
Copy link
Member

@anntzer sure, but that is a bit annoying.

This is one of those application vs library balance discussions (and I'm leaning towards the application side).

@anntzer
Copy link
Contributor

anntzer commented Oct 23, 2020

Actually, one thing I had missed is that there's also already imshow(..., clim=(vmin, vmax)). In particular, imshow(..., clim=(...), norm=LogNorm()) currently doesn't warn. Should it, in fact, emit a warning?

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.

Scatterplot: should vmin/vmax be ignored when a norm is specified?
5 participants