Skip to content

Commit 8524caa

Browse files
committed
Shorten tight_layout code.
- Turn hspaces/vspaces into 2D arrays, rather than flat lists that need to be repeatedly accessed with flattened indices, and directly accumulate widths/heights in there. - Merge the num2 is None case by treating it as a slice of length 1, which then allows just inlining _get_{left,right,top,bottom}. - Minor refactorings.
1 parent 3232f58 commit 8524caa

File tree

1 file changed

+32
-93
lines changed

1 file changed

+32
-93
lines changed

lib/matplotlib/tight_layout.py

+32-93
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,13 @@
99
for some cases (for example, left or right margin is affected by xlabel).
1010
"""
1111

12+
import numpy as np
13+
1214
from matplotlib import cbook, rcParams
1315
from matplotlib.font_manager import FontProperties
1416
from matplotlib.transforms import TransformedBbox, Bbox
1517

1618

17-
def _get_left(tight_bbox, axes_bbox):
18-
return axes_bbox.xmin - tight_bbox.xmin
19-
20-
21-
def _get_right(tight_bbox, axes_bbox):
22-
return tight_bbox.xmax - axes_bbox.xmax
23-
24-
25-
def _get_bottom(tight_bbox, axes_bbox):
26-
return axes_bbox.ymin - tight_bbox.ymin
27-
28-
29-
def _get_top(tight_bbox, axes_bbox):
30-
return tight_bbox.ymax - axes_bbox.ymax
31-
32-
3319
def auto_adjust_subplotpars(
3420
fig, renderer, nrows_ncols, num1num2_list, subplot_list,
3521
ax_bbox_list=None, pad=1.08, h_pad=None, w_pad=None, rect=None):
@@ -64,15 +50,8 @@ def auto_adjust_subplotpars(
6450
font_size_inches = (
6551
FontProperties(size=rcParams["font.size"]).get_size_in_points() / 72)
6652
pad_inches = pad * font_size_inches
67-
if h_pad is not None:
68-
vpad_inches = h_pad * font_size_inches
69-
else:
70-
vpad_inches = pad_inches
71-
72-
if w_pad is not None:
73-
hpad_inches = w_pad * font_size_inches
74-
else:
75-
hpad_inches = pad_inches
53+
vpad_inches = h_pad * font_size_inches if h_pad is not None else pad_inches
54+
hpad_inches = w_pad * font_size_inches if w_pad is not None else pad_inches
7655

7756
if len(num1num2_list) != len(subplot_list) or len(subplot_list) == 0:
7857
raise ValueError
@@ -81,23 +60,15 @@ def auto_adjust_subplotpars(
8160
margin_left = margin_bottom = margin_right = margin_top = None
8261
else:
8362
margin_left, margin_bottom, _right, _top = rect
84-
if _right:
85-
margin_right = 1 - _right
86-
else:
87-
margin_right = None
88-
if _top:
89-
margin_top = 1 - _top
90-
else:
91-
margin_top = None
92-
93-
vspaces = [[] for _ in range((rows + 1) * cols)]
94-
hspaces = [[] for _ in range(rows * (cols + 1))]
63+
margin_right = 1 - _right if _right else None
64+
margin_top = 1 - _top if _top else None
9565

96-
union = Bbox.union
66+
vspaces = np.zeros((rows + 1, cols))
67+
hspaces = np.zeros((rows, cols + 1))
9768

9869
if ax_bbox_list is None:
9970
ax_bbox_list = [
100-
union([ax.get_position(original=True) for ax in subplots])
71+
Bbox.union([ax.get_position(original=True) for ax in subplots])
10172
for subplots in subplot_list]
10273

10374
for subplots, ax_bbox, (num1, num2) in zip(subplot_list,
@@ -106,66 +77,39 @@ def auto_adjust_subplotpars(
10677
if all(not ax.get_visible() for ax in subplots):
10778
continue
10879

109-
tight_bbox_raw = union([ax.get_tightbbox(renderer) for ax in subplots
110-
if ax.get_visible()])
80+
tight_bbox_raw = Bbox.union([
81+
ax.get_tightbbox(renderer) for ax in subplots if ax.get_visible()])
11182
tight_bbox = TransformedBbox(tight_bbox_raw,
11283
fig.transFigure.inverted())
11384

11485
row1, col1 = divmod(num1, cols)
115-
11686
if num2 is None:
117-
# left
118-
hspaces[row1 * (cols + 1) + col1].append(
119-
_get_left(tight_bbox, ax_bbox))
120-
# right
121-
hspaces[row1 * (cols + 1) + (col1 + 1)].append(
122-
_get_right(tight_bbox, ax_bbox))
123-
# top
124-
vspaces[row1 * cols + col1].append(
125-
_get_top(tight_bbox, ax_bbox))
126-
# bottom
127-
vspaces[(row1 + 1) * cols + col1].append(
128-
_get_bottom(tight_bbox, ax_bbox))
87+
num2 = num1
88+
row2, col2 = divmod(num2, cols)
12989

130-
else:
131-
row2, col2 = divmod(num2, cols)
132-
133-
for row_i in range(row1, row2 + 1):
134-
# left
135-
hspaces[row_i * (cols + 1) + col1].append(
136-
_get_left(tight_bbox, ax_bbox))
137-
# right
138-
hspaces[row_i * (cols + 1) + (col2 + 1)].append(
139-
_get_right(tight_bbox, ax_bbox))
140-
for col_i in range(col1, col2 + 1):
141-
# top
142-
vspaces[row1 * cols + col_i].append(
143-
_get_top(tight_bbox, ax_bbox))
144-
# bottom
145-
vspaces[(row2 + 1) * cols + col_i].append(
146-
_get_bottom(tight_bbox, ax_bbox))
90+
for row_i in range(row1, row2 + 1):
91+
hspaces[row_i, col1] += ax_bbox.xmin - tight_bbox.xmin # left
92+
hspaces[row_i, col2 + 1] += tight_bbox.xmax - ax_bbox.xmax # right
93+
for col_i in range(col1, col2 + 1):
94+
vspaces[row1, col_i] += tight_bbox.ymax - ax_bbox.ymax # top
95+
vspaces[row2 + 1, col_i] += ax_bbox.ymin - tight_bbox.ymin # bot.
14796

14897
fig_width_inch, fig_height_inch = fig.get_size_inches()
14998

150-
# margins can be negative for axes with aspect applied. And we
151-
# append + [0] to make minimum margins 0
152-
99+
# margins can be negative for axes with aspect applied, so use max(, 0) to
100+
# make them nonnegative.
153101
if not margin_left:
154-
margin_left = max([sum(s) for s in hspaces[::cols + 1]] + [0])
155-
margin_left += pad_inches / fig_width_inch
156-
102+
margin_left = (max(hspaces[:, 0].max(), 0)
103+
+ pad_inches / fig_width_inch)
157104
if not margin_right:
158-
margin_right = max([sum(s) for s in hspaces[cols::cols + 1]] + [0])
159-
margin_right += pad_inches / fig_width_inch
160-
105+
margin_right = (max(hspaces[:, -1].max(), 0)
106+
+ pad_inches / fig_width_inch)
161107
if not margin_top:
162-
margin_top = max([sum(s) for s in vspaces[:cols]] + [0])
163-
margin_top += pad_inches / fig_height_inch
164-
108+
margin_top = (max(vspaces[0, :].max(), 0)
109+
+ pad_inches / fig_height_inch)
165110
if not margin_bottom:
166-
margin_bottom = max([sum(s) for s in vspaces[-cols:]] + [0])
167-
margin_bottom += pad_inches / fig_height_inch
168-
111+
margin_bottom = (max(vspaces[-1, :].max(), 0)
112+
+ pad_inches / fig_height_inch)
169113
if margin_left + margin_right >= 1:
170114
cbook._warn_external('Tight layout not applied. The left and right '
171115
'margins cannot be made large enough to '
@@ -181,12 +125,9 @@ def auto_adjust_subplotpars(
181125
right=1 - margin_right,
182126
bottom=margin_bottom,
183127
top=1 - margin_top)
128+
184129
if cols > 1:
185-
hspace = (
186-
max(sum(s)
187-
for i in range(rows)
188-
for s in hspaces[i * (cols + 1) + 1:(i + 1) * (cols + 1) - 1])
189-
+ hpad_inches / fig_width_inch)
130+
hspace = hspaces[:, 1:-1].max() + hpad_inches / fig_width_inch
190131
# axes widths:
191132
h_axes = (1 - margin_right - margin_left - hspace * (cols - 1)) / cols
192133
if h_axes < 0:
@@ -196,10 +137,8 @@ def auto_adjust_subplotpars(
196137
return None
197138
else:
198139
kwargs["wspace"] = hspace / h_axes
199-
200140
if rows > 1:
201-
vspace = (max(sum(s) for s in vspaces[cols:-cols])
202-
+ vpad_inches / fig_height_inch)
141+
vspace = vspaces[1:-1, :].max() + vpad_inches / fig_height_inch
203142
v_axes = (1 - margin_top - margin_bottom - vspace * (rows - 1)) / rows
204143
if v_axes < 0:
205144
cbook._warn_external('Tight layout not applied. tight_layout '

0 commit comments

Comments
 (0)