Skip to content

Commit 2ae73c6

Browse files
authored
Merge pull request matplotlib#19892 from timhoffm/fig-layout
API: Add Figure parameter layout and discourage tight_layout / constrained_layout
2 parents 0ca5de3 + a83134f commit 2ae73c6

File tree

3 files changed

+99
-13
lines changed

3 files changed

+99
-13
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Discouraged: ``Figure`` parameters *tight_layout* and *constrained_layout*
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
The ``Figure`` parameters *tight_layout* and *constrained_layout* are
4+
triggering competing layout mechanisms and thus should not be used together.
5+
6+
To make the API clearer, we've merged them under the new parameter *layout*
7+
with values 'constrained' (equal to ``constrained_layout=True``), 'tight'
8+
(equal to ``tight_layout=True``). If given *layout* takes precedence.
9+
10+
The use of *tight_layout* and *constrained_layout* is discouraged in favor
11+
of *layout*. However, these parameters will stay available for backward
12+
compatibility.

lib/matplotlib/figure.py

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2149,6 +2149,8 @@ def __init__(self,
21492149
subplotpars=None, # rc figure.subplot.*
21502150
tight_layout=None, # rc figure.autolayout
21512151
constrained_layout=None, # rc figure.constrained_layout.use
2152+
*,
2153+
layout=None,
21522154
**kwargs
21532155
):
21542156
"""
@@ -2178,19 +2180,42 @@ def __init__(self,
21782180
parameters :rc:`figure.subplot.*` are used.
21792181
21802182
tight_layout : bool or dict, default: :rc:`figure.autolayout`
2181-
If ``False`` use *subplotpars*. If ``True`` adjust subplot
2182-
parameters using `.tight_layout` with default padding.
2183-
When providing a dict containing the keys ``pad``, ``w_pad``,
2184-
``h_pad``, and ``rect``, the default `.tight_layout` paddings
2185-
will be overridden.
2183+
Whether to use the tight layout mechanism. See `.set_tight_layout`.
2184+
2185+
.. admonition:: Discouraged
2186+
2187+
The use of this parameter is discouraged. Please use
2188+
``layout='tight'`` instead for the common case of
2189+
``tight_layout=True`` and use `.set_tight_layout` otherwise.
21862190
21872191
constrained_layout : bool, default: :rc:`figure.constrained_layout.use`
2188-
If ``True`` use constrained layout to adjust positioning of plot
2189-
elements. Like ``tight_layout``, but designed to be more
2190-
flexible. See
2191-
:doc:`/tutorials/intermediate/constrainedlayout_guide`
2192-
for examples. (Note: does not work with `add_subplot` or
2193-
`~.pyplot.subplot2grid`.)
2192+
This is equal to ``layout='constrained'``.
2193+
2194+
.. admonition:: Discouraged
2195+
2196+
The use of this parameter is discouraged. Please use
2197+
``layout='constrained'`` instead.
2198+
2199+
layout : {'constrained', 'tight'}, optional
2200+
The layout mechanism for positioning of plot elements.
2201+
Supported values:
2202+
2203+
- 'constrained': The constrained layout solver usually gives the
2204+
best layout results and is thus recommended. However, it is
2205+
computationally expensive and can be slow for complex figures
2206+
with many elements.
2207+
2208+
See :doc:`/tutorials/intermediate/constrainedlayout_guide`
2209+
for examples.
2210+
2211+
- 'tight': Use the tight layout mechanism. This is a relatively
2212+
simple algorithm, that adjusts the subplot parameters so that
2213+
decorations like tick labels, axis labels and titles have enough
2214+
space. See `.Figure.set_tight_layout` for further details.
2215+
2216+
If not given, fall back to using the parameters *tight_layout* and
2217+
*constrained_layout*, including their config defaults
2218+
:rc:`figure.autolayout` and :rc:`figure.constrained_layout.use`.
21942219
21952220
Other Parameters
21962221
----------------
@@ -2200,6 +2225,24 @@ def __init__(self,
22002225
"""
22012226
super().__init__(**kwargs)
22022227

2228+
if layout is not None:
2229+
if tight_layout is not None:
2230+
_api.warn_external(
2231+
"The Figure parameters 'layout' and 'tight_layout' "
2232+
"cannot be used together. Please use 'layout' only.")
2233+
if constrained_layout is not None:
2234+
_api.warn_external(
2235+
"The Figure parameters 'layout' and 'constrained_layout' "
2236+
"cannot be used together. Please use 'layout' only.")
2237+
if layout == 'constrained':
2238+
tight_layout = False
2239+
constrained_layout = True
2240+
elif layout == 'tight':
2241+
tight_layout = True
2242+
constrained_layout = False
2243+
else:
2244+
_api.check_in_list(['constrained', 'tight'], layout=layout)
2245+
22032246
self.callbacks = cbook.CallbackRegistry()
22042247
# Callbacks traditionally associated with the canvas (and exposed with
22052248
# a proxy property), but that actually need to be on the figure for
@@ -2362,7 +2405,7 @@ def set_tight_layout(self, tight):
23622405
----------
23632406
tight : bool or dict with keys "pad", "w_pad", "h_pad", "rect" or None
23642407
If a bool, sets whether to call `.tight_layout` upon drawing.
2365-
If ``None``, use the ``figure.autolayout`` rcparam instead.
2408+
If ``None``, use :rc:`figure.autolayout` instead.
23662409
If a dict, pass it as kwargs to `.tight_layout`, overriding the
23672410
default paddings.
23682411
"""

lib/matplotlib/tests/test_figure.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,13 +501,44 @@ def test_figure_repr():
501501
assert repr(fig) == "<Figure size 100x200 with 0 Axes>"
502502

503503

504-
def test_warn_cl_plus_tl():
504+
def test_valid_layouts():
505+
fig = Figure(layout=None)
506+
assert not fig.get_tight_layout()
507+
assert not fig.get_constrained_layout()
508+
509+
fig = Figure(layout='tight')
510+
assert fig.get_tight_layout()
511+
assert not fig.get_constrained_layout()
512+
513+
fig = Figure(layout='constrained')
514+
assert not fig.get_tight_layout()
515+
assert fig.get_constrained_layout()
516+
517+
518+
def test_invalid_layouts():
505519
fig, ax = plt.subplots(constrained_layout=True)
506520
with pytest.warns(UserWarning):
507521
# this should warn,
508522
fig.subplots_adjust(top=0.8)
509523
assert not(fig.get_constrained_layout())
510524

525+
# Using layout + (tight|constrained)_layout warns, but the former takes
526+
# precedence.
527+
with pytest.warns(UserWarning, match="Figure parameters 'layout' and "
528+
"'tight_layout' cannot"):
529+
fig = Figure(layout='tight', tight_layout=False)
530+
assert fig.get_tight_layout()
531+
assert not fig.get_constrained_layout()
532+
with pytest.warns(UserWarning, match="Figure parameters 'layout' and "
533+
"'constrained_layout' cannot"):
534+
fig = Figure(layout='constrained', constrained_layout=False)
535+
assert not fig.get_tight_layout()
536+
assert fig.get_constrained_layout()
537+
538+
with pytest.raises(ValueError,
539+
match="'foobar' is not a valid value for layout"):
540+
Figure(layout='foobar')
541+
511542

512543
@check_figures_equal(extensions=["png", "pdf"])
513544
def test_add_artist(fig_test, fig_ref):

0 commit comments

Comments
 (0)