{"record":{"id":"9e56b357a2da820a","repo":"matplotlib/matplotlib","slug":"third-dimension-must-be-3-or-4","errorCode":null,"errorMessage":"Third dimension must be 3 or 4","messagePattern":"Third dimension must be 3 or 4","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/matplotlib/colorizer.py","lineNumber":167,"sourceCode":"    @staticmethod\n    def _pass_image_data(x, alpha=None, bytes=False, norm=True):\n        \"\"\"\n        Helper function to pass ndarray of shape (...,3) or (..., 4)\n        through `to_rgba()`, see `to_rgba()` for docstring.\n        \"\"\"\n        if x.shape[2] == 3:\n            if alpha is None:\n                alpha = 1\n            if x.dtype == np.uint8:\n                alpha = np.uint8(alpha * 255)\n            m, n = x.shape[:2]\n            xx = np.empty(shape=(m, n, 4), dtype=x.dtype)\n            xx[:, :, :3] = x\n            xx[:, :, 3] = alpha\n        elif x.shape[2] == 4:\n            xx = x\n        else:\n            raise ValueError(\"Third dimension must be 3 or 4\")\n        if xx.dtype.kind == 'f':\n            # If any of R, G, B, or A is nan, set to 0\n            if np.any(nans := np.isnan(x)):\n                if x.shape[2] == 4:\n                    xx = xx.copy()\n                xx[np.any(nans, axis=2), :] = 0\n\n            if norm and (xx.max() > 1 or xx.min() < 0):\n                raise ValueError(\"Floating point image RGB values \"\n                                 \"must be in the [0,1] range\")\n            if bytes:\n                xx = (xx * 255).astype(np.uint8)\n        elif xx.dtype == np.uint8:\n            if not bytes:\n                xx = xx.astype(np.float32) / 255\n        else:\n            raise ValueError(\"Image RGB array must be uint8 or \"\n                             \"floating point; found %s\" % xx.dtype)","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/matplotlib/matplotlib/blob/b379c1b69e012b142c0f496a52bcb30513802d72/lib/matplotlib/colorizer.py#L149-L185","documentation":"Colorizer.to_rgba converts already-colorized (M, N, 3) RGB or (M, N, 4) RGBA data to output RGBA. The last axis must be exactly 3 or 4 channels; any other third dimension is rejected. This is the raw-color path — scalar (M, N) data meant to go through the colormap does not belong here.","triggerScenarios":"colorizer.to_rgba(x) with x of shape (M, N, 2) (e.g. stacked x/y pairs), (M, N, 1) (an unsqueezed single channel), or (M, N, 5)+; passing pre-stacked arrays whose last axis is not color channels.","commonSituations":"Feeding coordinate or velocity-vector stacks into the color API by mistake; an extra squeeze/expand_dims bug leaving a trailing 1-axis; assuming any 3-D array is interpreted as multi-channel scalar data.","solutions":["Ensure the input is (M, N, 3) RGB or (M, N, 4) RGBA before calling to_rgba","Squeeze stray trailing axes: np.squeeze on shape (M, N, 1) data","For scalar (M, N) data, use the normal mappable/colormap path rather than the raw RGBA path"],"exampleFix":"// before\nrgba = colorizer.to_rgba(pairs)   # pairs is (M, N, 2)\n// after\nrgba = colorizer.to_rgba(rgb)      # rgb is (M, N, 3) or (M, N, 4)","handlingStrategy":"type-guard","validationCode":"import numpy as np\n\nif x.ndim != 3 or x.shape[-1] not in (3, 4):\n    raise ValueError(f'expected (M, N, 3|4) color data, got {x.shape}')","typeGuard":"def is_rgba_like(a):\n    return getattr(a, 'ndim', 0) == 3 and a.shape[-1] in (3, 4)","tryCatchPattern":null,"preventionTips":["Check a.shape[-1] before handing stacked arrays to the color API","Name variables rgb/rgba at conversion boundaries so misuse is visible in review"],"tags":["matplotlib","colorizer","rgba","numpy","shape"],"backgroundTag":"array-shape-mismatch","analyzedSha":"b379c1b69e012b142c0f496a52bcb30513802d72","analyzedAt":"2026-08-21T23:31:55.468Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}