-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Diverging norm #5054
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
Diverging norm #5054
Conversation
Borrows heavily from @Tillsen's solution found on StackOverflow here: http://goo.gl/RPXMYB Used with his permission dicussesd on Github here: https://github.com/matplotlib/matplotlib/pull/3858`
This will allow the ticks of colors to be spaced as desired. Also simplified the math per the brilliant @joferkington http://stackoverflow.com/a/20146989/1552748
couldn't actually run the test suite b/c python iesn't installed as a framework.
Need to allow it in __call__ since colorbar can pass a value for clip.
To make it more similar to the other norms Also remove misleading comment about returning scalars
Since possibly some earlier versions of numpy returned a scalar, wrap the value in atleast_1d before indexing.
np.interp handles the case vmin == vcenter, we have to add a special case to make the last test case pass
assert_array_almost_equal(normed_vals, self.expected) | ||
|
||
def test_inverse(self): | ||
if self.test_inverse: |
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 am a bit confused about how I expect this to behave...
I am a bit concerned about the inverse tests: In [14]: nn = mc.DivergingNorm(0, 1, 10)
In [15]: nn.inverse(nn(np.arange(10))) == np.arange(10)
Out[15]:
masked_array(data = [ True False False False False False False False False False],
mask = False,
fill_value = True) |
If I add the inverse function back in the color bar does not work correctly even with import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
x = np.linspace(-2, 7)
y = np.linspace(-1*np.pi, np.pi)
X, Y = np.meshgrid(x, y)
Z = x * np.sin(Y)**2
fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, figsize=(9, 3))
cmap = plt.cm.coolwarm
norm = mcolors.DivergingNorm(vmin=-2, vcenter=0, vmax=7)
img1 = ax1.imshow(Z, cmap=cmap, norm=None)
cbar1 = fig.colorbar(img1, ax=ax1)
img2 = ax2.imshow(Z, cmap=cmap, norm=norm)
cbar2 = fig.colorbar(img2, ax=ax2)
img3 = ax3.imshow(Z, cmap=cmap, norm=norm)
cbar3 = fig.colorbar(img3, ax=ax3, spacing='proportional') attn @efiring def inverse(self, value):
result, is_scalar = self.process_value(value)
self.autoscale_None(result)
vmin, vcenter, vmax = self.vmin, self.vcenter, self.vmax
if vmin == vmax == vcenter:
result.fill(0)
elif not vmin <= vcenter <= vmax:
raise ValueError("minvalue must be less than or equal to "
"centervalue which must be less than or "
"equal to maxvalue")
else:
vmin = float(vmin)
vcenter = float(vcenter)
vmax = float(vmax)
# in degenerate cases, prefer the center value to the extremes
degen = (result == vcenter) if vcenter == vmax else None
x, y = [vmin, vcenter, vmax], [0, 0.5, 1]
result = ma.masked_array(np.interp(result, y, x),
mask=ma.getmask(result))
if degen is not None:
result[degen] = 0.5
if is_scalar:
result = np.atleast_1d(result)[0]
return result
|
@efiring I have sunk another few hours into trying to understand the color bar code and am still failing 😞 (but I am getting closer!). It looks like |
I think the problem is that for |
@tacaswell, the use of inverse is deliberate; I found I needed it when I added LogNorm. It allows one to find the boundaries in data space corresponding to a linear increase in plot space. This is critical. I'm puzzled as to why the inverse inherited from Normalize seems to be giving a reasonable result. Please give me a little time to figure this out. I agree that the colorbar code is very hard to follow, even for me, who wrote most of it many years ago. |
Looking at #5061, I think I understand: the picture you are showing is with the inverse, and #5061 is showing the picture without the inverse. Well, the picture with the inverse is correct in the sense that it is consistent with colorbar's logic--it just isn't what you expect or want. Consider the case of a more extreme norm, the LogNorm: if you were to put in linearly-selected tick values, they would be all bunched together at one end. |
Hmm, yes, colorbar code, I took a look at it last night when working on the @efiring @tacaswell you should feel happy to note that I have a plan on refactoring the colorbar. While the code still lay clear in my mind of the parts of colorbar that I looked at (the last |
I am starting to think that getting this in for 1.5 is a bigger can of worms than anticipated. |
Due to the issues with the inverse and the colorbar, punting this to the next release. |
On 2015/09/14 5:50 AM, Thomas A Caswell wrote:
Good move. I don't see it as urgent. |
Okay, I now understand the inverse thing in So the solution lies into seperating this conflation of scales into the two distinct scales, something I had planned for MEP29, but didn't realise until now just how significantly this refactor plays into this issue. |
This seems to have died an untimely death. Does anyone want to champion? |
How about making such thing a wishlist item or something similar, to make it something that can get picked up, but doesn't count as a blocker for release. |
Moved to #12419.... |
Renamed and rebased version of #4666