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

  1. Clip data to a small positive floor: ax.tricontour(tri, np.maximum(z, 1e-12), norm=LogNorm())
  2. Mask or drop the non-positive points and their triangles from the triangulation
  3. Use a norm that accepts non-positive data: SymmetricalLogNorm for signed data, or plain linear Normalize
  4. 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

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


AI-assisted analysis of matplotlib/matplotlib@b379c1b69e (2026-08-21). Data as JSON: /api/errors/798a64ed13a9c005. Report an issue: GitHub.