{"record":{"id":"798a64ed13a9c005","repo":"matplotlib/matplotlib","slug":"cannot-func-log-of-negative-values","errorCode":null,"errorMessage":"Cannot {func} log of negative values.","messagePattern":"Cannot (.+?) log of negative values\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/matplotlib/tri/_tricontour.py","lineNumber":77,"sourceCode":"            raise ValueError('z array must have same length as triangulation x'\n                             ' and y arrays')\n\n        # z values must be finite, only need to check points that are included\n        # in the triangulation.\n        z_check = z[np.unique(tri.get_masked_triangles())]\n        if np.ma.is_masked(z_check):\n            raise ValueError('z must not contain masked points within the '\n                             'triangulation')\n        if not np.isfinite(z_check).all():\n            raise ValueError('z array must not contain non-finite values '\n                             'within the triangulation')\n\n        z = np.ma.masked_invalid(z, copy=False)\n        self.zmax = float(z_check.max())\n        self.zmin = float(z_check.min())\n        if self.logscale and self.zmin <= 0:\n            func = 'contourf' if self.filled else 'contour'\n            raise ValueError(f'Cannot {func} log of negative values.')\n        self._process_contour_level_args(args, z.dtype)\n        return (tri, z)\n\n\n_docstring.interpd.register(_tricontour_doc=\"\"\"\nDraw contour %%(type)s on an unstructured triangular grid.\n\nCall signatures::\n\n    %%(func)s(triangulation, z, [levels], ...)\n    %%(func)s(x, y, z, [levels], *, [triangles=triangles], [mask=mask], ...)\n\nThe triangular grid can be specified either by passing a `.Triangulation`\nobject as the first parameter, or by passing the points *x*, *y* and\noptionally the *triangles* and a *mask*. See `.Triangulation` for an\nexplanation of these parameters. If neither of *triangulation* or\n*triangles* are given, the triangulation is calculated on the fly.\n","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/matplotlib/matplotlib/blob/b379c1b69e012b142c0f496a52bcb30513802d72/lib/matplotlib/tri/_tricontour.py#L59-L95","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"import matplotlib.colors as mcolors\n\n# before: z contains 0 or negatives\nax.tricontourf(tri, z, norm=mcolors.LogNorm())\n\n# after: floor the data to a tiny positive value\nzpos = np.where(np.asarray(z) > 0, z, 1e-12)\nax.tricontourf(tri, zpos, norm=mcolors.LogNorm())","handlingStrategy":"validation","validationCode":"import numpy as np\n\npts = np.unique(tri.get_masked_triangles())\nzmin = float(np.asarray(z)[pts].min())\nusing_log = isinstance(norm, matplotlib.colors.LogNorm)\nif using_log and zmin <= 0:\n    z = np.maximum(np.asarray(z), 1e-12)  # or switch to a linear/SymLog norm","typeGuard":null,"tryCatchPattern":"try:\n    ax.tricontour(tri, z, norm=norm)\nexcept ValueError as e:\n    if 'log of negative' in str(e):\n        ax.tricontour(tri, np.maximum(z, 1e-12), norm=norm)\n    else:\n        raise","preventionTips":["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"],"tags":["matplotlib","tricontour","lognorm","negative-values","data-validation"],"backgroundTag":"log-scale-nonpositive-data","analyzedSha":"b379c1b69e012b142c0f496a52bcb30513802d72","analyzedAt":"2026-08-21T23:31:55.468Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}