Skip to content

imshow with LogNorm crashes with certain inputs #18415

Closed

Description

@LevN0

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

Activity

  1. added this to the v3.3.2 milestone on Sep 9, 2020
  2. tacaswell commented on Sep 9, 2020

    @tacaswell
    Member

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

  3. tacaswell commented on Sep 11, 2020

    @tacaswell
    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.

  4. added a commit that references this issue on Sep 11, 2020
    b23708a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions