Skip to content

FIX: Don't apply tight_layout if axes collapse #12285

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions doc/api/api_changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ This pages lists API changes for the most recent version of Matplotlib.

next_api_changes/*

API Changes for 3.0.1
=====================

`.tight_layout.auto_adjust_subplotpars` can return ``None`` now if the new
subplotparams will collapse axes to zero width or height. This prevents
``tight_layout`` from being executed. Similarly
`.tight_layout.get_tight_layout_figure` will return None.

API Changes for 3.0.0
=====================

Expand Down
3 changes: 2 additions & 1 deletion lib/matplotlib/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -2390,7 +2390,8 @@ def tight_layout(self, renderer=None, pad=1.08, h_pad=None, w_pad=None,
kwargs = get_tight_layout_figure(
self, self.axes, subplotspec_list, renderer,
pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect)
self.subplots_adjust(**kwargs)
if kwargs:
self.subplots_adjust(**kwargs)

def align_xlabels(self, axs=None):
"""
Expand Down
3 changes: 2 additions & 1 deletion lib/matplotlib/gridspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,8 @@ def tight_layout(self, figure, renderer=None,
kwargs = tight_layout.get_tight_layout_figure(
figure, figure.axes, subplotspec_list, renderer,
pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect)
self.update(**kwargs)
if kwargs:
self.update(**kwargs)


class GridSpecFromSubplotSpec(GridSpecBase):
Expand Down
16 changes: 16 additions & 0 deletions lib/matplotlib/tests/test_tightlayout.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,3 +316,19 @@ def test_badsubplotgrid():
with warnings.catch_warnings(record=True) as w:
plt.tight_layout()
assert len(w) == 1


def test_collapsed():
# test that if a call to tight_layout will collapes the axes that
# it does not get applied:
fig, ax = plt.subplots(tight_layout=True)
ax.set_xlim([0, 1])
ax.set_ylim([0, 1])

ax.annotate('BIG LONG STRING', xy=(1.25, 2), xytext=(10.5, 1.75),)
p1 = ax.get_position()
with warnings.catch_warnings(record=True) as w:
plt.tight_layout()
p2 = ax.get_position()
assert p1.width == p2.width
assert len(w) == 1
32 changes: 21 additions & 11 deletions lib/matplotlib/tight_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ def auto_adjust_subplotpars(
fig, renderer, nrows_ncols, num1num2_list, subplot_list,
ax_bbox_list=None, pad=1.08, h_pad=None, w_pad=None, rect=None):
"""
Return a dict of subplot parameters to adjust spacing between subplots.
Return a dict of subplot parameters to adjust spacing between subplots
or ``None`` if resulting axes would have zero height or width.

Note that this function ignores geometry information of subplot
itself, but uses what is given by the *nrows_ncols* and *num1num2_list*
Expand Down Expand Up @@ -172,15 +173,15 @@ def auto_adjust_subplotpars(
margin_bottom += pad_inches / fig_height_inch

if margin_left + margin_right >= 1:
margin_left = 0.4999
margin_right = 0.4999
warnings.warn('The left and right margins cannot be made large '
warnings.warn('Tight layout not applied. The left and right margins '
'cannot be made large '
'enough to accommodate all axes decorations. ')
return None
if margin_bottom + margin_top >= 1:
margin_bottom = 0.4999
margin_top = 0.4999
warnings.warn('The bottom and top margins cannot be made large '
warnings.warn('Tight layout not applied. '
'The bottom and top margins cannot be made large '
'enough to accommodate all axes decorations. ')
return None

kwargs = dict(left=margin_left,
right=1 - margin_right,
Expand All @@ -195,9 +196,10 @@ def auto_adjust_subplotpars(
# axes widths:
h_axes = (1 - margin_right - margin_left - hspace * (cols - 1)) / cols
if h_axes < 0:
warnings.warn('tight_layout cannot make axes width small enough '
warnings.warn('Tight layout not applied. '
'tight_layout cannot make axes width small enough '
'to accommodate all axes decorations')
kwargs["wspace"] = 0.5
return None
else:
kwargs["wspace"] = hspace / h_axes

Expand All @@ -206,9 +208,10 @@ def auto_adjust_subplotpars(
+ vpad_inches / fig_height_inch)
v_axes = (1 - margin_top - margin_bottom - vspace * (rows - 1)) / rows
if v_axes < 0:
warnings.warn('tight_layout cannot make axes height small enough '
warnings.warn('Tight layout not applied. '
'tight_layout cannot make axes height small enough '
'to accommodate all axes decorations')
kwargs["hspace"] = 0.5
return None
else:
kwargs["hspace"] = vspace / v_axes

Expand Down Expand Up @@ -287,6 +290,13 @@ def get_tight_layout_figure(fig, axes_list, subplotspec_list, renderer,
(left, bottom, right, top) rectangle in normalized figure coordinates
that the whole subplots area (including labels) will fit into.
Defaults to using the entire figure.

Returns
-------
subplotspec or None
subplotspec kwargs to be passed to `.Figure.subplots_adjust` or
None if tight_layout could not be accomplished.

"""

subplot_list = []
Expand Down