{"record":{"id":"9fa00d7cea1a4dc6","repo":"matplotlib/matplotlib","slug":"rotation-point-must-be-one-of-xy-center","errorCode":null,"errorMessage":"`rotation_point` must be one of {'xy', 'center', (number, number)}.","messagePattern":"`rotation_point` must be one of (.+?)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/matplotlib/patches.py","lineNumber":916,"sourceCode":"                .scale(1, self._aspect_ratio_correction) \\\n                .rotate_deg(self.angle) \\\n                .scale(1, 1 / self._aspect_ratio_correction) \\\n                .translate(*rotation_point)\n\n    @property\n    def rotation_point(self):\n        \"\"\"The rotation point of the patch.\"\"\"\n        return self._rotation_point\n\n    @rotation_point.setter\n    def rotation_point(self, value):\n        if value in ['center', 'xy'] or (\n                isinstance(value, tuple) and len(value) == 2 and\n                isinstance(value[0], Real) and isinstance(value[1], Real)\n                ):\n            self._rotation_point = value\n        else:\n            raise ValueError(\"`rotation_point` must be one of \"\n                             \"{'xy', 'center', (number, number)}.\")\n\n    def get_x(self):\n        \"\"\"Return the left coordinate of the rectangle.\"\"\"\n        return self._x0\n\n    def get_y(self):\n        \"\"\"Return the bottom coordinate of the rectangle.\"\"\"\n        return self._y0\n\n    def get_xy(self):\n        \"\"\"Return the left and bottom coords of the rectangle as a tuple.\"\"\"\n        return self._x0, self._y0\n\n    def get_corners(self):\n        \"\"\"\n        Return the corners of the rectangle, moving anti-clockwise from\n        (x0, y0).","sourceCodeStart":898,"sourceCodeEnd":934,"githubUrl":"https://github.com/matplotlib/matplotlib/blob/b379c1b69e012b142c0f496a52bcb30513802d72/lib/matplotlib/patches.py#L898-L934","documentation":"Rectangle accepts a rotation_point ('xy' by default) that fixes the pivot used when rotating the rectangle via its angle attribute: allowed values are the strings 'center' and 'xy' or a tuple of two Real numbers. The setter validates this union and raises ValueError(\"`rotation_point` must be one of {'xy', 'center', (number, number)}.\") for anything else. Note the type strictness: a list [x, y] or a numpy array is rejected because only tuple passes the isinstance check, and 1-element or 3-element tuples fail too.","triggerScenarios":"rect.rotation_point = 'left' or 'top' (not supported); rect.rotation_point = [0.5, 0.5] (list, not tuple); rect.rotation_point = (0.5,) (wrong length); Rectangle(..., rotation_point='center bottom') copied from other APIs.","commonSituations":"Users expecting anchor strings like those of AnchoredOffsetbox ('upper left'); passing JSON-decoded coordinates (always lists); interpolating a pivot from config as a list instead of a tuple; interactive rectangle-rotation tools (e.g. widgets.RectangleSelector ecosystem) setting arbitrary pivots.","solutions":["Use 'center' or 'xy' for named pivots.","For a custom pivot pass a 2-tuple of numbers: rect.rotation_point = (0.5, 0.5).","Coerce dynamic inputs: tuple(map(float, value)) before assignment.","Compute the wanted pivot from the rectangle bbox: (rect.get_x() + w/2, rect.get_y() + h/2) reproduces 'center' if you need numeric control."],"exampleFix":"# before\nrect = Rectangle((0, 0), 2, 1, angle=30, rotation_point=[0.5, 0.5])\n\n# after\nrect = Rectangle((0, 0), 2, 1, angle=30, rotation_point=(1.0, 0.5))\n# or a named pivot: rotation_point='center'","handlingStrategy":"type-guard","validationCode":"from numbers import Real\n\ndef coerce_rotation_point(v):\n    if isinstance(v, (list, np.ndarray)):\n        v = tuple(v)\n    if not (v in ('xy', 'center') or (\n            isinstance(v, tuple) and len(v) == 2\n            and all(isinstance(c, Real) for c in v))):\n        raise ValueError(f'bad rotation_point: {v!r}')\n    return v","typeGuard":"def is_valid_rotation_point(v) -> bool:\n    from numbers import Real\n    return v in ('xy', 'center') or (\n        isinstance(v, tuple) and len(v) == 2\n        and isinstance(v[0], Real) and isinstance(v[1], Real))","tryCatchPattern":null,"preventionTips":["Convert JSON/config lists to tuples before assigning rotation_point.","Only 'xy', 'center', or a 2-number tuple are valid — lists and arrays are not.","Compute numeric pivots from rect.get_x()/get_y() + size when you need custom anchors."],"tags":["matplotlib","patches","rectangle","rotation","argument-validation"],"backgroundTag":"invalid-argument-type","analyzedSha":"b379c1b69e012b142c0f496a52bcb30513802d72","analyzedAt":"2026-08-21T23:31:55.468Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}