Skip to content

imshow with LogNorm crashes with certain inputs #18415

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

Closed
LevN0 opened this issue Sep 6, 2020 · 2 comments · Fixed by #18458
Closed

imshow with LogNorm crashes with certain inputs #18415

LevN0 opened this issue Sep 6, 2020 · 2 comments · Fixed by #18458
Assignees
Milestone

Comments

@LevN0
Copy link
Contributor

LevN0 commented Sep 6, 2020

Bug report

Bug summary

Due to changes introduced in 3dea5c7, trying to display some images with LogNorm will crash because vmin gets auto-adjusted to 0 (which is invalid for LogNorm).

Code for reproduction

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm

data = np.full((500, 500), -1, dtype=np.float64)
data[0:250, :] = 1E20

fig, ax = plt.subplots()
im = ax.imshow(data, norm=LogNorm(vmin=100, vmax=data.max()))

plt.show()

Actual outcome

  File "C:\Python38\lib\site-packages\matplotlib\image.py", line 922, in make_image
    return self._make_image(self._A, bbox, transformed_bbox, clip,
  File "C:\Python38\lib\site-packages\matplotlib\image.py", line 541, in _make_image
    output = self.norm(resampled_masked)
  File "C:\Python38\lib\site-packages\matplotlib\colors.py", line 1193, in __call__
    self._check_vmin_vmax()
  File "C:\Python38\lib\site-packages\matplotlib\colors.py", line 1182, in _check_vmin_vmax
    raise ValueError("minvalue must be positive")
ValueError: minvalue must be positive

Expected outcome

Showed a plot in MPL 3.1 (and I believe every version until 3.3). The crash is coming from _make_image transforming vmin to be zero per changes added in 3dea5c7. I guess perhaps the solution is "then don't try to plot that, use a vmin closer to your vmax" but kind of inconvenient for code that previously worked fine.

Matplotlib version: 3.3.1

@QuLogic QuLogic added this to the v3.3.2 milestone Sep 9, 2020
@QuLogic QuLogic assigned QuLogic and tacaswell and unassigned QuLogic Sep 9, 2020
@tacaswell
Copy link
Member

Yikes, sorry about that. This is not the first issue we have had with the limitations of float precision / range...

@tacaswell
Copy link
Member

in #16910 the issue is the in the round-tripping of rescaling the data (but not the limits) we were bouncing values exactly equal to the limit across the edge and erroneously marking them as over/under. The theory of #17636 is that by transforming both the limits and the data together we would preserve the relative ordering of vmin / vmax and the data under all cases (which I still think is correct). The issue is that now we have the vmin is bouncing across the valid values for vmin for the log norm.

We don't do any validation when setting vmin / vmax (they are normal attributes) so we don't have a good way to hook this on the norm side (and up-converting to properties is not good enough because in other cases we if the user sets the limits to be out of range we would want to fail instead of silently clipping.

We could hard code a special case for LogNorm and cilp the vmin to 0+eps before sending it in. It is pragmatic and would not be the first time that we have isinstance checks for LogNorm around.

We could add (optional) public or private API to the norm to class to allow it to express what its valid range is (either a class-level limits or a class level "clip to valid" function).

I don't think there is any path to trying to "guess" what the right thing to do here is as if there was also data at 100 it would have the same problem and be pushed across the edge to "invalid".

I'm leaning towards doing the "hard-coded-fix" for 3.3.2 and a more extendable fix for 3.4.

tacaswell added a commit to tacaswell/matplotlib that referenced this issue Sep 11, 2020
closes matplotlib#18415

We need to special case when rescaling the user input for
interpolation with LogNorm.  The issue is that due to the inherent
precision limits of floating point math we can end up with errors on
the order if 1e-18 of the overall data range when rescaling.  If the
bottom vlim is close to 0 and the top is order 10e20 than this error
can result in the rescaled vmin being negative which then fails when
we (temporarily) change the vmin/vmax on the norm.

We started adjusting the vmin/vmax to work around the same issue with
float precision in matplotlib#17636 / 3dea5c7 to make sure that values exactly
equal to the limits did not move across the boundary and get
erroneously mapped is over/under.

Long term we may want to add the ability for the norms to suggest to
their clients what the constraints on the vmin/vmax are, but
hard-coding a special case for LogNorm is the pragmatic solution.
@tacaswell tacaswell mentioned this issue Sep 11, 2020
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants