Bug summary
When Z has no variation (all values are equal), contour and contourf silently
produce multiple identical levels and render empty collections with no warning
to the user. The plot appears blank or broken with no indication of why.
Code for reproduction
import numpy as np
import matplotlib.pyplot as plt
Z = np.ones((10, 10)) * 5.0 # constant Z
fig, (ax1, ax2) = plt.subplots(1, 2)
cs1 = ax1.contour(np.linspace(0, 1, 10), np.linspace(0, 1, 10), Z)
cs2 = ax2.contourf(np.linspace(0, 1, 10), np.linspace(0, 1, 10), Z)
print(f"contour levels: {cs1.levels}") # [5. 5. 5. 5. 5. 5. 5. 5.]
print(f"contourf levels: {cs2.levels}") # [5. 5. 5. 5. 5. 5. 5. 5.]
print(f"contour paths: {cs1.get_paths()}") # all empty
Actual outcome
contour levels: [5. 5. 5. 5. 5. 5. 5. 5.]
contourf levels: [5. 5. 5. 5. 5. 5. 5. 5.]
No UserWarning raised. Plot is blank. User has no indication of why.
Expected outcome
A UserWarning should be raised:
"No contour levels can be computed: Z has no variation (min == max == 5.0)."
Similar to the existing warning "No contour levels were found within the data
range" which fires when user-supplied levels are out of range — but that
warning never fires for the auto-level case when zmin == zmax.
Additional information
Root cause is in contour.py around line 1364-1370. After zmin and zmax are
computed from Z, there is no check for zmin == zmax before _process_contour_level_args
is called. When zmin == zmax, MaxNLocator.tick_values() returns identical values,
the i1 - i0 < 3 fallback at line 1002 triggers, and the full array of identical
levels is returned silently.
The fix is a one-block addition right after line 1365:
if self.zmin == self.zmax:
_api.warn_external(
f"No contour levels can be computed: Z has no variation "
f"(min == max == {self.zmin})."
)
This is consistent with the logscale warning pattern directly below it.
Operating system
Linux
Matplotlib Version
3.10.8
Matplotlib Backend
No response
Python version
No response
Jupyter version
No response
Installation
None
Bug summary
When Z has no variation (all values are equal), contour and contourf silently
produce multiple identical levels and render empty collections with no warning
to the user. The plot appears blank or broken with no indication of why.
Code for reproduction
Actual outcome
contour levels: [5. 5. 5. 5. 5. 5. 5. 5.]
contourf levels: [5. 5. 5. 5. 5. 5. 5. 5.]
No UserWarning raised. Plot is blank. User has no indication of why.
Expected outcome
A UserWarning should be raised:
"No contour levels can be computed: Z has no variation (min == max == 5.0)."
Similar to the existing warning "No contour levels were found within the data
range" which fires when user-supplied levels are out of range — but that
warning never fires for the auto-level case when zmin == zmax.
Additional information
Root cause is in contour.py around line 1364-1370. After zmin and zmax are
computed from Z, there is no check for zmin == zmax before _process_contour_level_args
is called. When zmin == zmax, MaxNLocator.tick_values() returns identical values,
the i1 - i0 < 3 fallback at line 1002 triggers, and the full array of identical
levels is returned silently.
The fix is a one-block addition right after line 1365:
This is consistent with the logscale warning pattern directly below it.
Operating system
Linux
Matplotlib Version
3.10.8
Matplotlib Backend
No response
Python version
No response
Jupyter version
No response
Installation
None