-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Enh: DivergingNorm Fair #15333
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
Enh: DivergingNorm Fair #15333
Conversation
88ba7cd
to
ef7c088
Compare
I make plots like this all the time, and I just use a linear Norm, and center vmin and vmax around the center, ie for your case with center=0.25, If this does go in, then I think it should be its own norm, not a kwarg of |
For example, if you plot a quantity that cannot be smaller than 0, it doesn't make sense to plot a colorbar with negative values in it. |
Theoretically, I suppose someone could want to do that. Practically, |
It is quite clear that it makes sense to use a DivergingNorm with a Diverging colormap. The usecases are by far not the opposite. |
Like Jody, I'm unclear on why you'd want to use DivirgingNorm rather than LinearNorm with a one hue colormap. Can you please post an example of your usecase. I'm also struggling in understanding the 'fair' kwarg-why are you using that term? |
"fair" is just the best I could come up with, it means that both sides of the center are treated equally - or in a fair fashion. "Symmetic" could be an option as well. Native speakers may come up with a better term. The functionality of
Linear Norm is what @jklymak suggested above, but then you have the problem that you get a useless part of the colorbar which shows the part of the colormap that carries no meaning. Of course one can work around it and create a new colormap for each dataset in use - the idea here is to be able to prevent that. |
43ef737
to
422022e
Compare
What I meant by that is DivergingNorm has two different linear ramps to make the endpoints fit inside the colormap, whereas what you are proposing here has just one linear ramp, and basically just truncates the colormap. I'm not 100% against the idea of this norm, if you really think it will be useful. But I feel it would be far less confusing to have it be its own thing rather than a kwarg of a norm that does something pretty different. |
I'm coming around to the idea of this PR if I'm grokking it correctly. I agree with @ImportanceOfBeingErnest that a truncated but equally spaced around a center color colormap can often be the correct mapping for a DivergingNorm. I think I even have a use case from this summer: mapping errors where they skewed so extreme in one direction that putting both sides on the cmap would end up with a ton of wasted space (it was like a 10 to -1 spread) that would more accurately be conveyed with the proposed cmap. What about 'equally_spaced' as the kwarg? |
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import DivergingNorm
np.random.seed(19680801)
data = np.random.rand(4, 11) - 0.25
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(7, 2.5), constrained_layout=True)
norm1 = DivergingNorm(0.0, vmin=-0.25, vmax=0.75, fair=True)
im = ax1.imshow(data, cmap='RdBu_r', norm=norm1)
cbar = fig.colorbar(im, ax=ax1, orientation="horizontal", aspect=15)
im = ax2.imshow(data, cmap='RdBu_r', vmin=-0.75, vmax=0.75)
cbar = fig.colorbar(im, ax=ax2, orientation="horizontal", aspect=15)
plt.show() I find the second plot far easier to parse. The zero on the colorbar is in the middle, and its clear that a similar conceptual scale has been used on each side of the zero. The "wasted" space in the colorbar doesn't bother me in the least, indeed it makes it crystal clear that the anomaly from zero is much more positive than negative. |
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.
Please make its own Norm subclass.
@@ -1061,11 +1061,11 @@ def scaled(self): | |||
|
|||
|
|||
class DivergingNorm(Normalize): | |||
def __init__(self, vcenter, vmin=None, vmax=None): | |||
def __init__(self, vcenter, vmin=None, vmax=None, fair=False): |
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'll block on this being kwarg. Skptical about the normalization on the whole, but very against it being a kwarg for DivergingNorm
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.
But I think this belongs in DivergingNorm since that's the use case for truncated around a center colormap. Can we pitch this to the call? (which I'm probably going to be late to).
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.
From a user point of view norm1 = OffcenterNorm(0.0, vmin=-0.25, vmax=0.75)
is easier to type, and can get its own section in the docs, rather than making the docs and code for DivergingNorm
have a confusing kwarg that does something quite different from what fair=False
does. I don't understand the desire to make this a kwarg.
The reasons I put this in DivergingNorm are:
|
This ended up being a point of discussion on the call this week, see https://paper.dropbox.com/doc/In-Matplotlib-2019-meeting-agenda--AlZNZ8evWRf18Do4TtHUpBxuAg-aAmENlkgepgsMeDZtlsYu#:h2=PRs The short version is that this is pushing on important functionality, but we are not sure what the correct API. |
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 needs further discussion and possibly an API re-think / extension.
Based on discussion in the Sept. 24, 2019 call, this is a more complicated issue than it appears, and needs some higher-level API design proposals. The consensus is that although aspects of this PR might end up being adopted, the PR as it stands should not be merged. |
as a user, I can definitely vouch for a use case for this kind of norm. I have been using a similar functionality for showing relative sound levels (+- some critical value which is not necessarily zero) across a 2D spatial grid. |
Thats understandable, but why would you want to truncate the colormap to plot that? You can just do: |
I will reason by analogy here... when looking at the usual y vs. x plot, a
fairly common first instinct is to look at the limits of y axis (assuming x
is the independent/controllable variable) to get a handle on the extent of
the y values. Similarly for a colormapped data, a glance at the colorbar
limits gives the reader an idea about what kind of results we are dealing
with.
…On Tue, Sep 24, 2019 at 6:19 PM Jody Klymak ***@***.***> wrote:
as a user, I can definitely vouch for a use case for this kind of norm. I
have been using a similar functionality for showing relative sound levels
(+- some critical value which is not necessarily zero) across a 2D spatial
grid.
Thats understandable, but why would you want to truncate the colormap to
plot that? You can just do: vmin=crit - range vmax = crit+range and
adjust range to suit...
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#15333?email_source=notifications&email_token=ADTY7REJ4L7RQYOP5EWCS4TQLKHAXA5CNFSM4IZV64Q2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD7P7L5Q#issuecomment-534771190>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADTY7RAVFDCHJMAO6H6T7SLQLKHAXANCNFSM4IZV64QQ>
.
|
I think the consensus was that this PR is probably the correct approach (plus or minus) but a) definitely should be its own norm, and b) maybe there is a better way to do this? i.e. change the limits of the colorer directly, or alter the colormap directly. Having a norm that maps vmin to something other than 0 was a stumbling block. |
(Responding from my phone so adding to my previous reply by sending a new
email) this also comes in handy when the colorbar extensions are used along
with diverging data which is not symmetric about the intended “center”.
On Tue, Sep 24, 2019 at 6:26 PM Harshal Prakash Patankar <
pharshalp@gmail.com> wrote:
… I will reason by analogy here... when looking at the usual y vs. x plot, a
fairly common first instinct is to look at the limits of y axis (assuming x
is the independent/controllable variable) to get a handle on the extent of
the y values. Similarly for a colormapped data, a glance at the colorbar
limits gives the reader an idea about what kind of results we are dealing
with.
On Tue, Sep 24, 2019 at 6:19 PM Jody Klymak ***@***.***>
wrote:
> as a user, I can definitely vouch for a use case for this kind of norm. I
> have been using a similar functionality for showing relative sound levels
> (+- some critical value which is not necessarily zero) across a 2D spatial
> grid.
>
> Thats understandable, but why would you want to truncate the colormap to
> plot that? You can just do: vmin=crit - range vmax = crit+range and
> adjust range to suit...
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <#15333?email_source=notifications&email_token=ADTY7REJ4L7RQYOP5EWCS4TQLKHAXA5CNFSM4IZV64Q2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD7P7L5Q#issuecomment-534771190>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/ADTY7RAVFDCHJMAO6H6T7SLQLKHAXANCNFSM4IZV64QQ>
> .
>
|
As is, this isn't behaving quite correctly if the values are outside of vmin/vmax? import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import DivergingNorm
np.random.seed(19680801)
data = np.random.rand(10, 11)*2. - 1
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(7, 2.5), constrained_layout=True)
norm1 = DivergingNorm(0.0, vmin=-0.1, vmax=0.75, fair=True)
im = ax1.imshow(data, cmap='RdBu_r', norm=norm1)
cbar = fig.colorbar(im, ax=ax1, orientation="horizontal", aspect=15, extend='both')
im = ax2.imshow(data, cmap='RdBu_r', vmin=-1, vmax=1)
cbar = fig.colorbar(im, ax=ax2, orientation="horizontal", aspect=15, extend='both') |
I also want to supported this feature: I am working with difference spectra, hence the special value is 0. So far I just set vmin and vmax as proposed, but this leads to a misleading colorbar, since it indicates the occurrence of values outside the observed range. There is also no working way to set the limits of the colorbar. |
Indeed the question I wasn't sure of how to handle is this: Should a norm always map to [0, 1]? Or should it be restricted to a smaller range? |
422022e
to
9d01204
Compare
I fixed the example from above. It would now look like this: meaning everything outside [vmin,vmax] is mapped to the under/over color. This wasn't even the case for
looks like this, where outside values are just mapped to the lowest color from the colormap, not the under/over colors. In the current state of this PR it will now look as follows, as expected. |
Agreed that |
If the |
I think we should leave |
|
Its not a two-slope norm! |
If you really want to change the name I would propose to call it MidpointNorm and add the fair option to it. Because I quite sure that setting the midpoint is what most people want to do. |
|
I do not understand the necessity of renaming But given that there seems to be a consensus among several devs, what are the consquences for this PR: If Consequently, a new name would be needed. The word "fair" also seems to cause misinterpretation, so let's not use it. Possibly In addition, @timhoffm proposed a broader picture of the usecase in https://discourse.matplotlib.org/t/limiting-colormapping/20598. So one might take into account that people would, instead of defining a center point, want to define the two edges of the normalization region. This could in principle be combined into the same normalization instance, with an API like
with all parameters being optional and, if not given, determined by autoscaling to the data. |
I think something like WRT to not making this a kwarg of |
I'm going to close this. I'm not really convinced its a good idea, but if someone wants to take it up they can re-base etc in a new PR. |
PR Summary
Closes #13948
Adds a new argument
fair
to theDiverginNorm
to be able to create off-centered colormapping with equally spaced colors.While doing this, also removes the restriction
vmin <= vcenter <= vmax
inDiverginNorm
and replace it byvmin <= vmax
, such that the center can be outside the interval[vmin, vmax]
. This is useful when wanting to show only a partial colormap.PR Checklist