From 6902345697bcdd65ab46459b90a18e3f6462ea76 Mon Sep 17 00:00:00 2001 From: Muhtasim-Munif-Fahim Date: Tue, 11 Aug 2026 23:57:42 +0600 Subject: [PATCH] feat(figure): add loc parameter to suptitle Add loc parameter to ig.suptitle() supporting 'left', 'center', 'right' positions, defaulting to 'center' for backward compatibility. The loc parameter controls both the x-position and horizontal alignment of the super title text. --- lib/matplotlib/figure.py | 11 ++++++++++- lib/matplotlib/figure.pyi | 2 +- lib/matplotlib/tests/test_figure.py | 25 +++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 9920f6d908b3..5c6beecf9c77 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -415,6 +415,8 @@ def _suplabels(self, t, info, **kwargs): fontweight, weight : default: :rc:`figure.%(rc)sweight` The font weight of the text. See `.Text.set_weight` for possible values. + loc : {'left', 'center', 'right'}, default: 'center' + The horizontal position of the %(name)s. Returns ------- @@ -475,11 +477,18 @@ def _remove_suplabel(self, label, name): @_docstring.Substitution(x0=0.5, y0=0.98, name='super title', ha='center', va='top', rc='title') @_docstring.copy(_suplabels) - def suptitle(self, t, **kwargs): + def suptitle(self, t, loc=None, **kwargs): # docstring from _suplabels... info = {'name': '_suptitle', 'x0': 0.5, 'y0': 0.98, 'ha': 'center', 'va': 'top', 'rotation': 0, 'size': 'figure.titlesize', 'weight': 'figure.titleweight'} + if loc is not None: + _valid_locs = {'left': (0.02, 'left'), + 'center': (0.5, 'center'), + 'right': (0.98, 'right')} + _loc = loc.lower() + _api.check_in_list(_valid_locs, loc=_loc) + info['x0'], info['ha'] = _valid_locs[_loc] return self._suplabels(t, info, **kwargs) def get_suptitle(self): diff --git a/lib/matplotlib/figure.pyi b/lib/matplotlib/figure.pyi index cf17f4694dbd..222c11417436 100644 --- a/lib/matplotlib/figure.pyi +++ b/lib/matplotlib/figure.pyi @@ -57,7 +57,7 @@ class FigureBase(Artist): def get_children(self) -> list[Artist]: ... def contains(self, mouseevent: MouseEvent) -> tuple[bool, dict[Any, Any]]: ... - def suptitle(self, t: str, **kwargs) -> Text: ... + def suptitle(self, t: str, loc: Literal['left', 'center', 'right'] | None = None, **kwargs) -> Text: ... def get_suptitle(self) -> str: ... def supxlabel(self, t: str, **kwargs) -> Text: ... def get_supxlabel(self) -> str: ... diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index d8bf1954df94..dc6620326a12 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -339,6 +339,31 @@ def test_suptitle_fontproperties(): assert txt.get_weight() == fps.get_weight() +def test_suptitle_loc(): + fig, _ = plt.subplots() + t_left = fig.suptitle('left', loc='left') + assert t_left.get_ha() == 'left' + assert t_left.get_position()[0] == 0.02 + + t_center = fig.suptitle('center', loc='center') + assert t_center.get_ha() == 'center' + assert t_center.get_position()[0] == 0.5 + + t_right = fig.suptitle('right', loc='right') + assert t_right.get_ha() == 'right' + assert t_right.get_position()[0] == 0.98 + + # default (loc=None) should use center + fig2, _ = plt.subplots() + t_default = fig2.suptitle('default') + assert t_default.get_ha() == 'center' + assert t_default.get_position()[0] == 0.5 + + # invalid loc should raise + with pytest.raises(ValueError, match="'invalid' is not a valid value for loc"): + fig.suptitle('bad', loc='invalid') + + def test_suptitle_subfigures(): fig = plt.figure(figsize=(4, 3)) sf1, sf2 = fig.subfigures(1, 2)