matplotlib/matplotlib · error · ValueError

The third dimension of 'XY' must be 2

Error message

The third dimension of 'XY' must be 2

What it means

The classmethod Path.compound_path_from_polys(XY) builds a single compound path from a stack of polygons and requires XY to have shape (numpolys, numsides, 2): one polygon per first-axis entry, one vertex per second-axis entry, and an (x, y) pair on the last axis. The unpacking 'numpolys, numsides, two = XY.shape' plus the check 'two != 2' rejects arrays whose last dimension is not exactly 2.

Source

Thrown at lib/matplotlib/path.py:327

    @classmethod
    def make_compound_path_from_polys(cls, XY):
        """
        Make a compound `Path` object to draw a number of polygons with equal
        numbers of sides.

        .. plot:: gallery/misc/histogram_path.py

        Parameters
        ----------
        XY : (numpolys, numsides, 2) array
        """
        # for each poly: 1 for the MOVETO, (numsides-1) for the LINETO, 1 for
        # the CLOSEPOLY; the vert for the closepoly is ignored but we still
        # need it to keep the codes aligned with the vertices
        numpolys, numsides, two = XY.shape
        if two != 2:
            raise ValueError("The third dimension of 'XY' must be 2")
        stride = numsides + 1
        nverts = numpolys * stride
        verts = np.zeros((nverts, 2))
        codes = np.full(nverts, cls.LINETO, dtype=cls.code_type)
        codes[0::stride] = cls.MOVETO
        codes[numsides::stride] = cls.CLOSEPOLY
        for i in range(numsides):
            verts[i::stride] = XY[:, i]
        return cls(verts, codes)

    @classmethod
    def make_compound_path(cls, *args):
        r"""
        Concatenate a list of `Path`\s into a single `Path`, removing all `STOP`\s.
        """
        if not args:
            return Path(np.empty([0, 2], dtype=np.float32))
        vertices = np.concatenate([path.vertices for path in args])

View on GitHub (pinned to b379c1b69e)

Solutions

  1. Stack polygons into one (P, S, 2) array: XY = np.stack(polys) where each polys[i] has shape (S, 2)
  2. If you have separate x/y stacks, use axis=-1: np.stack([xs, ys], axis=-1)
  3. Reshape a flat single polygon: XY = verts.reshape(1, -1, 2)

Example fix

// before
XY = np.stack([xs, ys])          # shape (2, P, S) -> last dim != 2
p = Path.compound_path_from_polys(XY)
// after
XY = np.stack([xs, ys], axis=-1) # shape (P, S, 2)
p = Path.compound_path_from_polys(XY)
Defensive patterns

Strategy: validation

Validate before calling

import numpy as np

def polys_to_xy(polys):
    XY = np.asanyarray(polys)
    if XY.ndim != 3:
        XY = XY.reshape(len(polys), -1, 2)
    assert XY.shape[-1] == 2
    return XY

p = Path.compound_path_from_polys(polys_to_xy(polys))

Prevention

When it happens

Trigger: Passing a flat (N, 2) vertex array of one polygon; passing (P, S, 3) 3-D coordinates; stacking x and y polygons along the wrong axis so the last dimension is numpolys or numsides instead of 2.

Common situations: Converting shapely/geojson polygon lists to matplotlib paths without stacking; np.stack([polys_x, polys_y]) with the default axis=0 instead of axis=-1; assuming the function accepts an unstacked list of (S, 2) arrays (it needs one ndarray).

Related errors


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