{"record":{"id":"50fdfc34fddcd884","repo":"matplotlib/matplotlib","slug":"the-third-dimension-of-xy-must-be-2","errorCode":null,"errorMessage":"The third dimension of 'XY' must be 2","messagePattern":"The third dimension of 'XY' must be 2","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/matplotlib/path.py","lineNumber":327,"sourceCode":"\n    @classmethod\n    def make_compound_path_from_polys(cls, XY):\n        \"\"\"\n        Make a compound `Path` object to draw a number of polygons with equal\n        numbers of sides.\n\n        .. plot:: gallery/misc/histogram_path.py\n\n        Parameters\n        ----------\n        XY : (numpolys, numsides, 2) array\n        \"\"\"\n        # for each poly: 1 for the MOVETO, (numsides-1) for the LINETO, 1 for\n        # the CLOSEPOLY; the vert for the closepoly is ignored but we still\n        # need it to keep the codes aligned with the vertices\n        numpolys, numsides, two = XY.shape\n        if two != 2:\n            raise ValueError(\"The third dimension of 'XY' must be 2\")\n        stride = numsides + 1\n        nverts = numpolys * stride\n        verts = np.zeros((nverts, 2))\n        codes = np.full(nverts, cls.LINETO, dtype=cls.code_type)\n        codes[0::stride] = cls.MOVETO\n        codes[numsides::stride] = cls.CLOSEPOLY\n        for i in range(numsides):\n            verts[i::stride] = XY[:, i]\n        return cls(verts, codes)\n\n    @classmethod\n    def make_compound_path(cls, *args):\n        r\"\"\"\n        Concatenate a list of `Path`\\s into a single `Path`, removing all `STOP`\\s.\n        \"\"\"\n        if not args:\n            return Path(np.empty([0, 2], dtype=np.float32))\n        vertices = np.concatenate([path.vertices for path in args])","sourceCodeStart":309,"sourceCodeEnd":345,"githubUrl":"https://github.com/matplotlib/matplotlib/blob/b379c1b69e012b142c0f496a52bcb30513802d72/lib/matplotlib/path.py#L309-L345","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Stack polygons into one (P, S, 2) array: XY = np.stack(polys) where each polys[i] has shape (S, 2)","If you have separate x/y stacks, use axis=-1: np.stack([xs, ys], axis=-1)","Reshape a flat single polygon: XY = verts.reshape(1, -1, 2)"],"exampleFix":"// before\nXY = np.stack([xs, ys])          # shape (2, P, S) -> last dim != 2\np = Path.compound_path_from_polys(XY)\n// after\nXY = np.stack([xs, ys], axis=-1) # shape (P, S, 2)\np = Path.compound_path_from_polys(XY)","handlingStrategy":"validation","validationCode":"import numpy as np\n\ndef polys_to_xy(polys):\n    XY = np.asanyarray(polys)\n    if XY.ndim != 3:\n        XY = XY.reshape(len(polys), -1, 2)\n    assert XY.shape[-1] == 2\n    return XY\n\np = Path.compound_path_from_polys(polys_to_xy(polys))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Stack polygon arrays so the last axis is (x, y): np.stack([xs, ys], axis=-1)","Verify XY.shape == (numpolys, numsides, 2) before calling compound_path_from_polys","Each polygon contributes numsides + 1 codes (MOVETO + LINETOs + CLOSEPOLY) - vertices and codes must stay aligned"],"tags":["matplotlib","path","compound-path","polygons","numpy","shape-mismatch"],"backgroundTag":"array-shape-mismatch","analyzedSha":"b379c1b69e012b142c0f496a52bcb30513802d72","analyzedAt":"2026-08-21T23:31:55.468Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}