8000 ENH: supxlabel and supylabel · matplotlib/matplotlib@d1a0cc4 · GitHub
[go: up one dir, main page]

Skip to content

Commit d1a0cc4

Browse files
committed
ENH: supxlabel and supylabel
1 parent 81b962a commit d1a0cc4

File tree

3 files changed

+83
-37
lines changed

3 files changed

+83
-37
lines changed

lib/matplotlib/_constrained_layout.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -277,15 +277,17 @@ def _make_margin_suptitles(fig, renderer, *, w_pad=0, h_pad=0):
277277
fig._suptitle.set_position((p[0], 1-h_pad))
278278
fig._layoutgrid.edit_margin_min('top', bbox.height + 2 * h_pad)
279279

280-
if 0:
281-
# Not implimented yet!
282-
if fig._supxlabel is not None:
283-
bbox = invTransFig(fig._supxlabel.get_tightbbox(renderer))
284-
fig._layoutgrid.edit_margin_min('bottom', bbox.height + 2 * h_pad)
285-
286-
if fig._supylabel is not None:
287-
bbox = invTransFig(fig._supylabel.get_tightbbox(renderer))
288-
fig._layoutgrid.edit_margin_min('left', bbox.width + 2 * w_pad)
280+
if fig._supxlabel is not None:
281+
bbox = invTransFig(fig._supxlabel.get_tightbbox(renderer))
282+
p = fig._supxlabel.get_position()
283+
fig._supxlabel.set_position((p[0], h_pad))
284+
fig._layoutgrid.edit_margin_min('bottom', bbox.height + 2 * h_pad)
285+
286+
if fig._supylabel is not None:
287+
bbox = invTransFig(fig._supylabel.get_tightbbox(renderer))
288+
p = fig._supylabel.get_position()
289+
fig._supylabel.set_position((h_pad, p[1]))
290+
fig._layoutgrid.edit_margin_min('left', bbox.width + 2 * w_pad)
289291

290292

291293
def _match_submerged_margins(fig):

lib/matplotlib/figure.py

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -662,26 +662,27 @@ def get_window_extent(self, *args, **kwargs):
662662
"""
663663
return self.bbox
664664

665-
def suptitle(self, t, **kwargs):
665+
def _suplabels(self, t, info, **kwargs):
666666
"""
667-
Add a centered title to the figure.
667+
Add a centered {name} to the figure.
668668
669669
Parameters
670670
----------
671671
t : str
672-
The title text.
672+
The {name} text.
673673
674-
x : float, default 0.5
674+
x : float, default {x0}
675675
The x location of the text in figure coordinates.
676676
677-
y : float, default 0.98
677+
y : float, default {y0}
678678
The y location of the text in figure coordinates.
679679
680-
horizontalalignment, ha : {'center', 'left', right'}, default: 'center'
680+
horizontalalignment, ha : 'center', 'left', 'right', \
681+
default: {ha}
681682
The horizontal alignment of the text relative to (*x*, *y*).
682683
683-
verticalalignment, va : {'top', 'center', 'bottom', 'baseline'}, \
684-
default: 'top'
684+
verticalalignment, va : 'top', 'center', 'bottom', 'baseline', \
685+
default: {va}
685686
The vertical alignment of the text relative to (*x*, *y*).
686687
687688
fontsize, size : default: :rc:`figure.titlesize`
@@ -695,7 +696,7 @@ def suptitle(self, t, **kwargs):
695696
Returns
696697
-------
697698
text
698-
The `.Text` instance of the title.
699+
The `.Text` instance of the {name}.
699700
700701
Other Parameters
701702
----------------
@@ -708,19 +709,20 @@ def suptitle(self, t, **kwargs):
708709
**kwargs
709710
Additional kwargs are `matplotlib.text.Text` properties.
710711
711-
Examples
712-
--------
713-
>>> fig.suptitle('This is the figure title', fontsize=12)
714712
"""
713+
715714
manual_position = ('x' in kwargs or 'y' in kwargs)
715+
suplab = getattr(self, info['name'])
716716

717-
x = kwargs.pop('x', 0.5)
718-
y = kwargs.pop('y', 0.98)
717+
x = kwargs.pop('x', info['x0'])
718+
y = kwargs.pop('y', info['y0'])
719719

720720
if 'horizontalalignment' not in kwargs and 'ha' not in kwargs:
721-
kwargs['horizontalalignment'] = 'center'
721+
kwargs['horizontalalignment'] = info['ha']
722722
if 'verticalalignment' not in kwargs and 'va' not in kwargs:
723-
kwargs['verticalalignment'] = 'top'
723+
kwargs['verticalalignment'] = info['va']
724+
if 'rotation' not in kwargs:
725+
kwargs['rotation'] = info['rotation']
724726

725727
if 'fontproperties' not in kwargs:
726728
if 'fontsize' not in kwargs and 'size' not in kwargs:
@@ -729,17 +731,46 @@ def suptitle(self, t, **kwargs):
729731
kwargs['weight'] = mpl.rcParams['figure.titleweight']
730732

731733
sup = self.text(x, y, t, **kwargs)
732-
if self._suptitle is not None:
733-
self._suptitle.set_text(t)
734-
self._suptitle.set_position((x, y))
735-
self._suptitle.update_from(sup)
734+
if suplab is not None:
735+
suplab.set_text(t)
736+
suplab.set_position((x, y))
737+
suplab.update_from(sup)
736738
sup.remove()
737739
else:
738-
self._suptitle = sup
740+
suplab = sup
739741
if manual_position:
740-
self._suptitle.set_in_layout(False)
742+
suplab.set_in_layout(False)
743+
setattr(self, info['name'], suplab)
741744
self.stale = True
742-
return self._suptitle
745+
return suplab
746+
747+
def suptitle(self, t, **kwargs):
748+
# docstring from _suplabels...
749+
info = {'name': '_suptitle', 'x0': 0.5, 'y0': 0.98,
750+
'ha': 'center', 'va': 'top', 'rotation': 0}
751+
return self._suplabels(t, info, **kwargs)
752+
753+
suptitle.__doc__ = _suplabels.__doc__.format(
754+
x0=0.5, y0=0.98, name='suptitle', ha='center', va='top')
755+
756+
def supxlabel(self, t, **kwargs):
757+
# docstring from _suplabels...
758+
info = {'name': '_supxlabel', 'x0': 0.5, 'y0': 0.01,
759+
'ha': 'center', 'va': 'bottom', 'rotation': 0}
760+
return self._suplabels(t, info, **kwargs)
761+
762+
supxlabel.__doc__ = _suplabels.__doc__.format(
763+
x0=0.5, y0=0.01, name='supxlabel', ha='center', va='bottom')
764+
765+
def supylabel(self, t, **kwargs):
766+
# docstring from _suplabels...
767+
info = {'name': '_supylabel', 'x0': 0.02, 'y0': 0.5,
768+
'ha': 'left', 'va': 'center', 'rotation': 90}
769+
return self._suplabels(t, info, **kwargs)
770+
771+
supylabel.__doc__ = _suplabels.__doc__.format(
772+
x0=0.02, y0=0.5, name='supylabel', ha='left', va='center')
773+
743774

744775
def set_canvas(self, canvas):
745776
"""
@@ -1603,6 +1634,8 @@ def clf(self, keep_observers=False):
16031634
if not keep_observers:
16041635
self._axobservers = cbook.CallbackRegistry()
16051636
self._suptitle = None
1637+
self._supxlabel = None
1638+
self._supylabel = None
16061639
if self.get_constrained_layout():
16071640
layoutgrid.nonetree(self._layoutgrid)
16081641
self.stale = True

lib/matplotlib/tight_layout.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,20 +108,31 @@ def auto_adjust_subplotpars(
108108
if not margin_left:
109109
margin_left = (max(hspaces[:, 0].max(), 0)
110110
+ pad_inches / fig_width_inch)
111+
suplabel = fig._supylabel
112+
if suplabel and suplabel.get_in_layout():
113+
rel_width = fig.transFigure.inverted().transform_bbox(
114+
suplabel.get_window_extent(renderer)).width
115+
margin_left += rel_width + pad_inches / fig_width_inch
116+
111117
if not margin_right:
112118
margin_right = (max(hspaces[:, -1].max(), 0)
113119
+ pad_inches / fig_width_inch)
114120
if not margin_top:
115121
margin_top = (max(vspaces[0, :].max(), 0)
116122
+ pad_inches / fig_height_inch)
117-
suptitle = fig._suptitle
118-
if suptitle and suptitle.get_in_layout():
119-
rel_suptitle_height = fig.transFigure.inverted().transform_bbox(
120-
suptitle.get_window_extent(renderer)).height
121-
margin_top += rel_suptitle_height + pad_inches / fig_height_inch
123+
suplabel = fig._suptitle
124+
if suplabel and suplabel.get_in_layout():
125+
rel_height = fig.transFigure.inverted().transform_bbox(
126+
suplabel.get_window_extent(renderer)).height
127+
margin_top += rel_height + pad_inches / fig_height_inch
122128
if not margin_bottom:
123129
margin_bottom = (max(vspaces[-1, :].max(), 0)
124130
+ pad_inches / fig_height_inch)
131+
suplabel = fig._supxlabel
132+
if suplabel and suplabel.get_in_layout():
133+
rel_height = fig.transFigure.inverted().transform_bbox(
134+
suplabel.get_window_extent(renderer)).height
135+
margin_bottom += rel_height + pad_inches / fig_height_inch
125136

126137
if margin_left + margin_right >= 1:
127138
cbook._warn_external('Tight layout not applied. The left and right '

0 commit comments

Comments
 (0)
0