diff --git a/lib/matplotlib/_api/__init__.py b/lib/matplotlib/_api/__init__.py index 22b58b62ff8e..47c32f701729 100644 --- a/lib/matplotlib/_api/__init__.py +++ b/lib/matplotlib/_api/__init__.py @@ -25,6 +25,15 @@ MatplotlibDeprecationWarning) +# A sentinel value for optional arguments, when None cannot be used as +# default because we need to distinguish between None passed explicitly +# and parameter not given. Usage: def foo(arg=_api.UNSET): +class _Unset: + def __repr__(self): + return "" +UNSET = _Unset() + + class classproperty: """ Like `property`, but also triggers on access via the class, and it is the diff --git a/lib/matplotlib/_api/__init__.pyi b/lib/matplotlib/_api/__init__.pyi index ea7076feac3c..9bf67110bb54 100644 --- a/lib/matplotlib/_api/__init__.pyi +++ b/lib/matplotlib/_api/__init__.pyi @@ -18,6 +18,8 @@ from .deprecation import ( # noqa: F401, re-exported API _T = TypeVar("_T") +class _Unset: ... + class classproperty(Any): def __init__( self, diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index c87c789048c4..376eeb00b04d 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -107,12 +107,6 @@ def _stale_axes_callback(self, val): _XYPair = namedtuple("_XYPair", "x y") -class _Unset: - def __repr__(self): - return "" -_UNSET = _Unset() - - class Artist: """ Abstract base class for objects that render into a FigureCanvas. @@ -166,7 +160,7 @@ def _update_set_signature_and_docstring(cls): """ cls.set.__signature__ = Signature( [Parameter("self", Parameter.POSITIONAL_OR_KEYWORD), - *[Parameter(prop, Parameter.KEYWORD_ONLY, default=_UNSET) + *[Parameter(prop, Parameter.KEYWORD_ONLY, default=_api.UNSET) for prop in ArtistInspector(cls).get_setters() if prop not in Artist._PROPERTIES_EXCLUDED_FROM_SET]]) cls.set._autogenerated_signature = True diff --git a/lib/matplotlib/artist.pyi b/lib/matplotlib/artist.pyi index be23f69d44a6..7b8b0c36be69 100644 --- a/lib/matplotlib/artist.pyi +++ b/lib/matplotlib/artist.pyi @@ -26,8 +26,6 @@ class _XYPair(NamedTuple): x: ArrayLike y: ArrayLike -class _Unset: ... - class Artist: zorder: float stale_callback: Callable[[Artist, bool], None] | None diff --git a/lib/matplotlib/gridspec.py b/lib/matplotlib/gridspec.py index 06f0b2f7f781..de2406dd21ef 100644 --- a/lib/matplotlib/gridspec.py +++ b/lib/matplotlib/gridspec.py @@ -18,6 +18,7 @@ import matplotlib as mpl from matplotlib import _api, _pylab_helpers, _tight_layout +from matplotlib._api import UNSET as _UNSET from matplotlib.transforms import Bbox _log = logging.getLogger(__name__) @@ -366,7 +367,8 @@ def __init__(self, nrows, ncols, figure=None, _AllowedKeys = ["left", "bottom", "right", "top", "wspace", "hspace"] - def update(self, **kwargs): + def update(self, *, left=_UNSET, bottom=_UNSET, right=_UNSET, top=_UNSET, + wspace=_UNSET, hspace=_UNSET): """ Update the subplot parameters of the grid. @@ -377,15 +379,23 @@ def update(self, **kwargs): ---------- left, right, top, bottom : float or None, optional Extent of the subplots as a fraction of figure width or height. - wspace, hspace : float, optional + wspace, hspace : float or None, optional Spacing between the subplots as a fraction of the average subplot width / height. """ - for k, v in kwargs.items(): - if k in self._AllowedKeys: - setattr(self, k, v) - else: - raise AttributeError(f"{k} is an unknown keyword") + if left is not _UNSET: + self.left = left + if bottom is not _UNSET: + self.bottom = bottom + if right is not _UNSET: + self.right = right + if top is not _UNSET: + self.top = top + if wspace is not _UNSET: + self.wspace = wspace + if hspace is not _UNSET: + self.hspace = hspace + for figmanager in _pylab_helpers.Gcf.figs.values(): for ax in figmanager.canvas.figure.axes: if ax.get_subplotspec() is not None: diff --git a/lib/matplotlib/gridspec.pyi b/lib/matplotlib/gridspec.pyi index 3bf13ee17c4e..a1dc5deaa62c 100644 --- a/lib/matplotlib/gridspec.pyi +++ b/lib/matplotlib/gridspec.pyi @@ -3,6 +3,7 @@ from typing import Any, Literal, overload from numpy.typing import ArrayLike import numpy as np +from matplotlib._api import _Unset from matplotlib.axes import Axes from matplotlib.backend_bases import RendererBase from matplotlib.figure import Figure @@ -78,7 +79,16 @@ class GridSpec(GridSpecBase): width_ratios: ArrayLike | None = ..., height_ratios: ArrayLike | None = ..., ) -> None: ... - def update(self, **kwargs: float | None) -> None: ... + def update( + self, + *, + left: float | None | _Unset = ..., + bottom: float | None | _Unset = ..., + right: float | None | _Unset = ..., + top: float | None | _Unset = ..., + wspace: float | None | _Unset = ..., + hspace: float | None | _Unset = ..., + ) -> None: ... def locally_modified_subplot_params(self) -> list[str]: ... def tight_layout( self,