Skip to content

[Bug]: setting norm for imshow and not using a colorbar produces error #28555

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

Open
rcomer opened this issue Jul 12, 2024 · 6 comments
Open

[Bug]: setting norm for imshow and not using a colorbar produces error #28555

rcomer opened this issue Jul 12, 2024 · 6 comments

Comments

@rcomer
Copy link
Member

rcomer commented Jul 12, 2024

Bug summary

I tried removing the colorbar call from @timhoffm's new example at #28546, and I got an error

Code for reproduction

import matplotlib.pyplot as plt
import numpy as np

from matplotlib import colors

np.random.seed(19680801)

data = np.random.rand(10, 20)

fig, ax = plt.subplots()

norm = colors.Normalize(vmin=np.max(data), vmax=np.min(data))
im = ax.imshow(data, norm=norm)

plt.show()

Actual outcome

With QtAgg:

Traceback (most recent call last):
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/backends/backend_qt.py", line 498, in _draw_idle
    self.draw()
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/backends/backend_agg.py", line 387, in draw
    self.figure.draw(self.renderer)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/artist.py", line 95, in draw_wrapper
    result = draw(artist, renderer, *args, **kwargs)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/figure.py", line 3224, in draw
    mimage._draw_list_compositing_images(
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/image.py", line 132, in _draw_list_compositing_images
    a.draw(renderer)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/axes/_base.py", line 3152, in draw
    mimage._draw_list_compositing_images(
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/image.py", line 132, in _draw_list_compositing_images
    a.draw(renderer)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/image.py", line 651, in draw
    im, l, b, trans = self.make_image(
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/image.py", line 950, in make_image
    return self._make_image(self._A, bbox, transformed_bbox, clip,
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/image.py", line 551, in _make_image
    output = self.norm(resampled_masked)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/colors.py", line 1395, in __call__
    raise ValueError("minvalue must be less than or equal to maxvalue")
ValueError: minvalue must be less than or equal to maxvalue

With TkAgg:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/home/ruth/miniforge3/envs/mpl-dev/lib/python3.9/tkinter/__init__.py", line 1892, in __call__
    return self.func(*args)
  File "/home/ruth/miniforge3/envs/mpl-dev/lib/python3.9/tkinter/__init__.py", line 814, in callit
    func(*args)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/backends/_backend_tk.py", line 271, in idle_draw
    self.draw()
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/backends/backend_tkagg.py", line 10, in draw
    super().draw()
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/backends/backend_agg.py", line 387, in draw
    self.figure.draw(self.renderer)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/artist.py", line 95, in draw_wrapper
    result = draw(artist, renderer, *args, **kwargs)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/figure.py", line 3224, in draw
    mimage._draw_list_compositing_images(
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/image.py", line 132, in _draw_list_compositing_images
    a.draw(renderer)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/axes/_base.py", line 3152, in draw
    mimage._draw_list_compositing_images(
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/image.py", line 132, in _draw_list_compositing_images
    a.draw(renderer)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/image.py", line 651, in draw
    im, l, b, trans = self.make_image(
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/image.py", line 950, in make_image
    return self._make_image(self._A, bbox, transformed_bbox, clip,
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/image.py", line 551, in _make_image
    output = self.norm(resampled_masked)
  File "/home/ruth/git_stuff/matplotlib/lib/matplotlib/colors.py", line 1395, in __call__
    raise ValueError("minvalue must be less than or equal to maxvalue")
ValueError: minvalue must be less than or equal to maxvalue

Expected outcome

No error

Additional information

Everything is fine if I add a colorbar.

Operating system

Ubuntu

Matplotlib Version

main, 3.8.4, 3.6.3

Matplotlib Backend

QtAgg and TkAgg

Python version

3.9.19, 3.12.3, 3.11.6

Jupyter version

N/A

Installation

conda

@jklymak
Copy link
Member

jklymak commented Jul 12, 2024

There was some logic added to colorbar to have the colorbar limits affect the Norm (@greglucas). I suspect that allows the example to work with a colorbar, but break otherwise?

@tacaswell
Copy link
Member

Yeah, I also strongly suspect we are getting saved by the "make-non-singular" logic in the color bar.

Looking at the code setting the min to the max of the data and vica versa looks like a typo?

@greglucas
Copy link
Contributor

There is a typo in the vmin that should be min(data) in the example. Although it is unfortunate that this errors with/without a colorbar.

The colorbar swaps the vmin and vmax for a user through the nonsingular call expansion I think (on mobile and can't verify) which saves this case for the user.

@timhoffm
Copy link
Member

Ops, indeed a typo in min/max. -> Fixed for the example.

Should the norm itself check that vmin < vmax (or <=)?

@jklymak
Copy link
Member

jklymak commented Jul 12, 2024

We allow other limits to be flipped (eg set_ylim(100, 0) will invert the yaxis). Flipping the limits for the norm is not an unreasonable thing to do, so instead of doing cmap='jet_r' one could do imshow(A, vmin=100, vmax=0, cmap='jet')

@timhoffm
Copy link
Member

timhoffm commented Jul 12, 2024

Yes we do this for axis limits. The point is that, we currently do not flip the colorbar, but silently exchange min/max in the background. Changing to vmin=100, vmax=0 with a flipping behavior, is a "silent" behavoir change, which is more problematic compared to not allowing that behavior. But maybe you could sell it as a bug fix.

Note that vmin=100, vmax=0, cmap='jet' is not the same as vmin=0, vmax=100, cmap='jet_r'. Additionally to _r-ing the colormap ``vmin=100, vmax=0should invert the axis direction, i.e. be similar tocolorbar._long_axis().set_inverted(True)`.

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

No branches or pull requests

5 participants