Repository navigation
Open
Description
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
Metadata
Metadata
Assignees
Labels
No labels
Activity
jklymak commentedon Jul 12, 2024
There was some logic added to
colorbarto have the colorbar limits affect the Norm (@greglucas). I suspect that allows the example to work with a colorbar, but break otherwise?tacaswell commentedon Jul 12, 2024
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 commentedon Jul 12, 2024
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 commentedon Jul 12, 2024
Ops, indeed a typo in min/max. -> Fixed for the example.
Should the norm itself check that
vmin < vmax(or<=)?jklymak commentedon 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 doimshow(A, vmin=100, vmax=0, cmap='jet')timhoffm commentedon 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=0with 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 asvmin=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)`.