matplotlib/matplotlib · error · ValueError
must be same number of segments as levels
Error message
must be same number of segments as levels
What it means
On the manual-construction path (ContourSet(levels, allsegs, allkinds)), unfilled line contours require exactly one segment list per level: len(allsegs) == len(levels). Unlike the filled case, line contours get a segment list for every level, including levels with no contour lines (represented by an empty list). ValueError is raised on any other count.
Source
Thrown at lib/matplotlib/contour.py:916
Must set self.levels, self.zmin and self.zmax, and update Axes limits.
"""
self.levels = args[0]
allsegs = args[1]
allkinds = args[2] if len(args) > 2 else None
self.zmax = np.max(self.levels)
self.zmin = np.min(self.levels)
if allkinds is None:
allkinds = [[None] * len(segs) for segs in allsegs]
# Check lengths of levels and allsegs.
if self.filled:
if len(allsegs) != len(self.levels) - 1:
raise ValueError('must be one less number of segments as '
'levels')
else:
if len(allsegs) != len(self.levels):
raise ValueError('must be same number of segments as levels')
# Check length of allkinds.
if len(allkinds) != len(allsegs):
raise ValueError('allkinds has different length to allsegs')
# Determine x, y bounds and update axes data limits.
flatseglist = [s for seg in allsegs for s in seg]
points = np.concatenate(flatseglist, axis=0)
self._mins = points.min(axis=0)
self._maxs = points.max(axis=0)
# Each entry in (allsegs, allkinds) is a list of (segs, kinds): segs is a list
# of (N, 2) arrays of xy coordinates, kinds is a list of arrays of corresponding
# pathcodes. However, kinds can also be None; in which case all paths in that
# list are codeless (this case is normalized above). These lists are used to
# construct paths, which then get concatenated.
self._paths = [Path.make_compound_path(*map(Path, segs, kinds))
for segs, kinds in zip(allsegs, allkinds)]View on GitHub (pinned to b379c1b69e)
Solutions
- Supply exactly len(levels) segment lists; keep empty lists [] for levels with no geometry.
- If the geometry was computed for filled bands, regenerate it as lines (contour_generator(...).lines(levels)) or construct with filled=True.
- Recompute rather than hand-trimming: len(allsegs) must equal len(levels) at construction time.
- Add a pre-check: assert len(allsegs) == len(levels) before constructing.
Example fix
# before segs = [s for s in line_segs if s] # accidentally dropped empties ContourSet(ax, levels, segs) # len mismatch -> ValueError # after ContourSet(ax, levels, line_segs) # keep one (possibly empty) list per level
Defensive patterns
Strategy: validation
Validate before calling
assert len(allsegs) == len(levels), \
f'{len(allsegs)} segment lists vs {len(levels)} levels' Try / catch
try:
ContourSet(ax, levels, allsegs)
except ValueError:
allsegs = [allsegs[i] if i < len(allsegs) else [] for i in range(len(levels))]
ContourSet(ax, levels, allsegs) Prevention
- Keep empty [] entries for levels that produced no lines.
- Store levels alongside segment lists so they cannot drift apart.
- Re-derive geometry with gen.lines(levels) rather than editing cached lists.
When it happens
Trigger: Building ContourSet with line-contour geometry that dropped empty levels (e.g. filtered out levels where no line was found); passing band geometry (len(levels)-1 lists, correct only for filled=True) while leaving filled=False; off-by-one errors when slicing cached geometry.
Common situations: Replaying serialized contour geometry; mixing up filled and line geometry conventions when switching between contourf output and contour; trimming 'empty' segment lists during caching to save space.
Related errors
- must be one less number of segments as levels
- Specified levels {levlabs} don't match available levels {sel
- allkinds has different length to allsegs
- Contour levels must be increasing
- If given, 'extent' must be None or (x0, x1, y0, y1)
AI-assisted analysis of matplotlib/matplotlib@b379c1b69e (2026-08-21).
Data as JSON: /api/errors/1ca1e104b89dd1f5.
Report an issue: GitHub.