matplotlib/matplotlib · error · TypeError

Input z must be at least a (2, 2) shaped array, but has shap

Error message

Input z must be at least a (2, 2) shaped array, but has shape {z.shape}

What it means

Beyond being 2D, the height field z must be at least 2x2: contouring computes gradients between adjacent cells, so a single row, single column, or single cell leaves nothing to contour. _check_xyz raises TypeError when z.shape[0] < 2 or z.shape[1] < 2. This fires for shapes like (1, 5), (5, 1), and (1, 1).

Source

Thrown at lib/matplotlib/contour.py:1416

            self.zmin = z.min().astype(float)
        self._process_contour_level_args(args, z.dtype)
        return (x, y, z)

    def _check_xyz(self, x, y, z, kwargs):
        """
        Check that the shapes of the input arrays match; if x and y are 1D,
        convert them to 2D using meshgrid.
        """
        x, y = self.axes._process_unit_info([("x", x), ("y", y)], kwargs)

        x = np.asarray(x, dtype=np.float64)
        y = np.asarray(y, dtype=np.float64)
        z = ma.asarray(z)

        if z.ndim != 2:
            raise TypeError(f"Input z must be 2D, not {z.ndim}D")
        if z.shape[0] < 2 or z.shape[1] < 2:
            raise TypeError(f"Input z must be at least a (2, 2) shaped array, "
                            f"but has shape {z.shape}")
        Ny, Nx = z.shape

        if x.ndim != y.ndim:
            raise TypeError(f"Number of dimensions of x ({x.ndim}) and y "
                            f"({y.ndim}) do not match")
        if x.ndim == 1:
            nx, = x.shape
            ny, = y.shape
            if nx != Nx:
                raise TypeError(f"Length of x ({nx}) must match number of "
                                f"columns in z ({Nx})")
            if ny != Ny:
                raise TypeError(f"Length of y ({ny}) must match number of "
                                f"rows in z ({Ny})")
            x, y = np.meshgrid(x, y)
        elif x.ndim == 2:
            if x.shape != z.shape:

View on GitHub (pinned to b379c1b69e)

Solutions

  1. Supply a z with shape >= (2, 2); check z.shape before calling contour.
  2. Fix slicing bugs: verify the slice keeps both dimensions (z[0:2, 0:2] not z[0, 0:2]).
  3. If the dataset genuinely has one row/column, use ax.plot or ax.scatter instead — contouring is undefined there.
  4. Pad the grid with an extra edge row/column when a boundary slice is unavoidable.

Example fix

# before
z = np.array([[0.0, 1.0, 2.0]])   # shape (1, 3)
ax.contour(z)                      # TypeError

# after
z = np.array([[0.0, 1.0, 2.0],
              [0.5, 1.5, 2.5]])   # shape (2, 3)
ax.contour(z)
Defensive patterns

Strategy: validation

Validate before calling

z = np.asarray(z)
if z.ndim != 2 or min(z.shape) < 2:
    raise ValueError(f'z too small to contour: {z.shape}')

Type guard

def contourable(a):
    a = np.asarray(a)
    return a.ndim == 2 and a.shape[0] >= 2 and a.shape[1] >= 2

Try / catch

try:
    ax.contour(z)
except TypeError:
    ax.plot(z.ravel())  # degenerate grid: fall back to a line plot

Prevention

When it happens

Trigger: ax.contour(np.array([[0, 1, 2]])) (one row); passing a coarse 2-point grid shrunk to one axis by a slicing bug (z[:, 0] instead of z[:, :2]); plotting a 1x1 or degenerate raster extracted from a larger array.

Common situations: Edge-case datasets that reduce to a single row/column after filtering NaNs or subsetting; unit tests using trivially small arrays; GUI zoom/region-selection features that crop z too aggressively.

Related errors


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