matplotlib/matplotlib · error · ValueError

n_axes must be positive and not larger than nrows*ncols

Error message

n_axes must be positive and not larger than nrows*ncols

What it means

When constructing `ImageGrid`/`Grid` (mpl_toolkits.axes_grid1.axes_grid) with an explicit `n_axes`, the value must satisfy 0 < n_axes <= nrows*ncols from the `nrows_ncols` pair. Zero, negative values, or values larger than the grid capacity raise ValueError. Omitting n_axes entirely defaults it to exactly nrows*ncols and never triggers this error.

Source

Thrown at lib/mpl_toolkits/axes_grid1/axes_grid.py:124

            - "L": All axes on the left column get vertical tick labels;
              all axes on the bottom row get horizontal tick labels.
            - "1": Only the bottom left axes is labelled.
            - "all": All axes are labelled.
            - "keep": Do not do anything.

        axes_class : subclass of `matplotlib.axes.Axes`, default: `.mpl_axes.Axes`
            The type of Axes to create.
        aspect : bool, default: False
            Whether the axes aspect ratio follows the aspect ratio of the data
            limits.
        """
        self._nrows, self._ncols = nrows_ncols

        if n_axes is None:
            n_axes = self._nrows * self._ncols
        else:
            if not 0 < n_axes <= self._nrows * self._ncols:
                raise ValueError(
                    "n_axes must be positive and not larger than nrows*ncols")

        self._horiz_pad_size, self._vert_pad_size = map(
            Size.Fixed, np.broadcast_to(axes_pad, 2))

        _api.check_in_list(["column", "row"], direction=direction)
        self._direction = direction

        if axes_class is None:
            axes_class = self._defaultAxesClass
        elif isinstance(axes_class, (list, tuple)):
            cls, kwargs = axes_class
            axes_class = functools.partial(cls, **kwargs)

        kw = dict(horizontal=[], vertical=[], aspect=aspect)
        if isinstance(rect, (Number, SubplotSpec)):
            self._divider = SubplotDivider(fig, rect, **kw)
        elif len(rect) == 3:

View on GitHub (pinned to b379c1b69e)

Solutions

  1. Omit n_axes so it defaults to nrows*ncols
  2. Derive the grid from the data: nrows_ncols sized so rows*cols >= n_axes
  3. If you pass n_axes explicitly, assert 0 < n_axes <= nrows*ncols first
  4. For 'all axes' semantics pass n_axes=nrows*ncols or None

Example fix

# before
grid = ImageGrid(fig, 111, nrows_ncols=(2, 2), n_axes=len(images))  # len=5 fails

# after
n = len(images)
grid = ImageGrid(fig, 111, nrows_ncols=(2, (n + 1) // 2), n_axes=n)
Defensive patterns

Strategy: validation

Validate before calling

rows, cols = nrows_ncols
if n_axes is not None and not 0 < n_axes <= rows * cols:
    nrows_ncols = (max(1, (n_axes + cols - 1) // cols), cols)
grid = ImageGrid(fig, 111, nrows_ncols=nrows_ncols, n_axes=n_axes)

Type guard

def grid_holds(nrows_ncols, n_axes):
    rows, cols = nrows_ncols
    return n_axes is None or 0 < n_axes <= rows * cols

Try / catch

try:
    grid = ImageGrid(fig, 111, nrows_ncols=nrows_ncols, n_axes=n_axes)
except ValueError:
    grid = ImageGrid(fig, 111, nrows_ncols=nrows_ncols)  # default: all cells

Prevention

When it happens

Trigger: ImageGrid(fig, rect, nrows_ncols=(2, 2), n_axes=0); n_axes=5 with nrows_ncols=(2, 2); n_axes computed as len(images) where images outgrew the configured grid; n_axes=-1 intended to mean 'all'.

Common situations: Parameterizing grid size and image count independently in a plotting function so they drift apart; passing n_axes=len(data) while nrows_ncols comes from a config file; assuming n_axes=0 or None disables the check (None does skip it; 0 does not).

Related errors


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