matplotlib/matplotlib · error · ValueError
Cannot {func} log of negative values.
Error message
Cannot {func} log of negative values. What it means
Raised by tricontour/tricontourf when a logarithmic scale is in effect (LogNorm or a log contour locator sets TriContourSet.logscale) and the smallest finite z value inside the triangulation is <= 0. Log-scale contours are only defined for strictly positive data, so matplotlib refuses rather than emitting undefined levels. The message interpolates 'contourf' or 'contour' according to the filled flag.
Source
Thrown at lib/matplotlib/tri/_tricontour.py:77
raise ValueError('z array must have same length as triangulation x'
' and y arrays')
# z values must be finite, only need to check points that are included
# in the triangulation.
z_check = z[np.unique(tri.get_masked_triangles())]
if np.ma.is_masked(z_check):
raise ValueError('z must not contain masked points within the '
'triangulation')
if not np.isfinite(z_check).all():
raise ValueError('z array must not contain non-finite values '
'within the triangulation')
z = np.ma.masked_invalid(z, copy=False)
self.zmax = float(z_check.max())
self.zmin = float(z_check.min())
if self.logscale and self.zmin <= 0:
func = 'contourf' if self.filled else 'contour'
raise ValueError(f'Cannot {func} log of negative values.')
self._process_contour_level_args(args, z.dtype)
return (tri, z)
_docstring.interpd.register(_tricontour_doc="""
Draw contour %%(type)s on an unstructured triangular grid.
Call signatures::
%%(func)s(triangulation, z, [levels], ...)
%%(func)s(x, y, z, [levels], *, [triangles=triangles], [mask=mask], ...)
The triangular grid can be specified either by passing a `.Triangulation`
object as the first parameter, or by passing the points *x*, *y* and
optionally the *triangles* and a *mask*. See `.Triangulation` for an
explanation of these parameters. If neither of *triangulation* or
*triangles* are given, the triangulation is calculated on the fly.
View on GitHub (pinned to b379c1b69e)
Solutions
- Clip data to a small positive floor: ax.tricontour(tri, np.maximum(z, 1e-12), norm=LogNorm())
- Mask or drop the non-positive points and their triangles from the triangulation
- Use a norm that accepts non-positive data: SymmetricalLogNorm for signed data, or plain linear Normalize
- If zeros mean 'no data', encode them as NaN/masked and mask the triangles that use them (see error 900)
Example fix
import matplotlib.colors as mcolors # before: z contains 0 or negatives ax.tricontourf(tri, z, norm=mcolors.LogNorm()) # after: floor the data to a tiny positive value zpos = np.where(np.asarray(z) > 0, z, 1e-12) ax.tricontourf(tri, zpos, norm=mcolors.LogNorm())
Defensive patterns
Strategy: validation
Validate before calling
import numpy as np
pts = np.unique(tri.get_masked_triangles())
zmin = float(np.asarray(z)[pts].min())
using_log = isinstance(norm, matplotlib.colors.LogNorm)
if using_log and zmin <= 0:
z = np.maximum(np.asarray(z), 1e-12) # or switch to a linear/SymLog norm Try / catch
try:
ax.tricontour(tri, z, norm=norm)
except ValueError as e:
if 'log of negative' in str(e):
ax.tricontour(tri, np.maximum(z, 1e-12), norm=norm)
else:
raise Prevention
- Check float(z.min()) > 0 before attaching LogNorm
- Prefer SymmetricalLogNorm when data can be zero or negative
- Treat zeros in log-scale data as missing values and mask them, not as real measurements
When it happens
Trigger: ax.tricontour(tri, z, norm=matplotlib.colors.LogNorm()) or ax.tricontourf(tri, z, norm=LogNorm(), ...) where float(z[np.unique(tri.get_masked_triangles())].min()) <= 0, including exact zeros and negative values.
Common situations: Plotting spectra, counts or magnitudes containing exact zeros; invalid values replaced by 0 during preprocessing; dB-scaled data with a clamped floor; switching a working linear-norm contour script to LogNorm without re-checking the data range.
Related errors
- Bad parse: bbox has {len(bbox)} elements, should be 4
- Wedge sizes 'x' must be non negative values
- z array must not contain non-finite values within the triang
- Bad char metrics line: %s
- Wedge sizes must be finite numbers
AI-assisted analysis of matplotlib/matplotlib@b379c1b69e (2026-08-21).
Data as JSON: /api/errors/798a64ed13a9c005.
Report an issue: GitHub.