You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Behavior of masked values in colormap plot has changed in 2.2.0 #11039
Something changed the behavior of masked values in colormaps. Before, masked values on a 'jet' colormap would be drawn as white (and could be set to different colors with set_bad). This is no longer the case on matplotlib 2.2.0 - the masked values are being printed out as blue, the same color as valid values, and set_bad has no effect. Verified former behavior to be working on 2.1.1 and 2.0.2.
Not sure this is an issue or expected behavior, but I couldn't find a description of this behavior change anywhere. Please close if this is expected.
Changing interpolation from gaussian to none makes no difference (the sample code was originally used for another bug)
classLogNorm(Normalize):
""" Normalize a given value to the 0-1 range on a log scale """def__call__(self, value, clip=None):
ifclipisNone:
clip=self.clipresult, is_scalar=self.process_value(value)
result=np.ma.masked_less_equal(result, 0, copy=False)
self.autoscale_None(result)
vmin, vmax=self.vmin, self.vmaxifvmin>vmax:
raiseValueError("minvalue must be less than or equal to maxvalue")
elifvmin<=0:
raiseValueError("values must all be positive")
elifvmin==vmax:
result.fill(0)
The problem is coming from the last line above, which is throwing away the mask in the special case where there is only a single valid value in the array. I will submit a PR for it.
The problem is that all the complex rescaling in the resampling code in imshow probably should be skipped for the special case where there is only a single valid value in the array. @tacaswell, sorry, but I think I had better leave the implementation of that special case to you.
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!
I cannot reproduce this problem with the specified versions. However I can reproduce on main, and a bisect points to the backport of #20511 in 3.4.3. That change does modify LogNorm to remove an accidental modification of the internal data. However, at this point in main, the LogNorm is created out of the LogScale and doesn't have a class-specific autoscale_None that can be overridden. But, having written that change, I still think it is correct.
So in the end, I do have to wonder if imshow is applying the norm parameter correctly.
After some further investigation, I think @efiring was on the right track above. With the refactoring of LogNorm into a LogScale+Normalize derivative, the location of the problem has changed a bit, but it's still about the same:
When vmin != vmax, anything outside produces something outside the 0-1 range expected for a norm and negative numbers for LogNorm are masked. But when they're equal, then only zeros are output, due to:
Since a LogNorm will autoscale without the 0, it will tell the image code here that vmin==vmax==40, and then the image code clips to a minimum of 40, losing all the zeros before the norm is even called. I have not tested it, but do also wonder if that means that a norm with vmin/vmax within the array limits will not correctly plot under or over colours.
Is vmin == vmax something we want/need to support? There is ambiguity when calling norm(vmin), should we return 0, 0.5, or 1? It seems like disallowing the case where vmin == vmax would solve a lot of special-casing in other places.
We already apply a nonsingular transform in Colorbar to specifically avoid this case when the norm is on an axis, but I'm wondering if this special-casing should actually be moved upstream to the Normalize class and applied during the autoscaling?
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!
Activity
arthur00 commentedon Apr 12, 2018
From #9961, I tried using LogNorm(vmin=1, vmax=5), and I got:
ln(1) -> 0
ln(.5) -> -0.5306 ...
ln(np.nan) -> nan
ln(0) -> masked
But with LogNorm()
ln(1) -> 0
ln(.5) -> 0
ln(np.nan) -> 0
ln(0) -> masked
Numpy version 1.13
arthur00 commentedon Apr 12, 2018
To recap (some tests were done in #9961): If LogNorm sets vmin != vmax, the graph is plotted correctly:
If the vmin == vmax == None (i.e. LogNorm()), the shown effect of a block of blue with no stripes is seen.
efiring commentedon Jul 2, 2018
The problem is coming from the last line above, which is throwing away the mask in the special case where there is only a single valid value in the array. I will submit a PR for it.
efiring commentedon Jul 2, 2018
Wrong! Investigating...
efiring commentedon Jul 2, 2018
The problem is that all the complex rescaling in the resampling code in imshow probably should be skipped for the special case where there is only a single valid value in the array. @tacaswell, sorry, but I think I had better leave the implementation of that special case to you.
github-actions commentedon May 4, 2023
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!
QuLogic commentedon May 4, 2023
I cannot reproduce this problem with the specified versions. However I can reproduce on
main, and a bisect points to the backport of #20511 in 3.4.3. That change does modifyLogNormto remove an accidental modification of the internal data. However, at this point inmain, theLogNormis created out of theLogScaleand doesn't have a class-specificautoscale_Nonethat can be overridden. But, having written that change, I still think it is correct.So in the end, I do have to wonder if
imshowis applying thenormparameter correctly.QuLogic commentedon May 4, 2023
After some further investigation, I think @efiring was on the right track above. With the refactoring of
LogNorminto aLogScale+Normalizederivative, the location of the problem has changed a bit, but it's still about the same:When
vmin != vmax, anything outside produces something outside the 0-1 range expected for a norm and negative numbers forLogNormare masked. But when they're equal, then only zeros are output, due to:matplotlib/lib/matplotlib/colors.py
Lines 1712 to 1713 in 5a89bdb
This can be fixed by something like:
(though I'm not sure if the last line should be in or out of the
else.)However, fixing that does not fix the image. This appears to be due to this extra clipping applied at:
matplotlib/lib/matplotlib/image.py
Lines 454 to 473 in 5a89bdb
Since a
LogNormwill autoscale without the 0, it will tell the image code here thatvmin==vmax==40, and then the image code clips to a minimum of 40, losing all the zeros before the norm is even called. I have not tested it, but do also wonder if that means that a norm withvmin/vmaxwithin the array limits will not correctly plot under or over colours.greglucas commentedon May 5, 2023
Is
vmin == vmaxsomething we want/need to support? There is ambiguity when callingnorm(vmin), should we return 0, 0.5, or 1? It seems like disallowing the case wherevmin == vmaxwould solve a lot of special-casing in other places.We already apply a nonsingular transform in Colorbar to specifically avoid this case when the norm is on an axis, but I'm wondering if this special-casing should actually be moved upstream to the
Normalizeclass and applied during the autoscaling?github-actions commentedon Jul 12, 2024
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!
timhoffm commentedon Aug 13, 2024
The topic of singular norms (vmin == vmax) is not consistently solved. Not a high priority, but we should come up with a consistent approach. See also
imshowand not using a colorbar produces error #28555