Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6fa3fa9

Browse filesBrowse files
committed
ENH: constrained_layout simple compress axes
1 parent cd33ed2 commit 6fa3fa9
Copy full SHA for 6fa3fa9

File tree

Expand file treeCollapse file tree

3 files changed

+64
-9
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+64
-9
lines changed

‎lib/matplotlib/_constrained_layout.py

Copy file name to clipboardExpand all lines: lib/matplotlib/_constrained_layout.py
+50-5Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161

6262
######################################################
6363
def do_constrained_layout(fig, renderer, h_pad, w_pad,
64-
hspace=None, wspace=None):
64+
hspace=None, wspace=None, compress=False):
6565
"""
6666
Do the constrained_layout. Called at draw time in
6767
``figure.constrained_layout()``
@@ -83,6 +83,11 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad,
8383
A value of 0.2 for a three-column layout would have a space
8484
of 0.1 of the figure width between each column.
8585
If h/wspace < h/w_pad, then the pads are used instead.
86+
87+
compress : boolean, False
88+
Whether to try and push axes together if their aspect ratios
89+
make it so that the they will have lots of extra white space
90+
between them. Useful for grids of images or maps.
8691
"""
8792

8893
# list of unique gridspecs that contain child axes:
@@ -98,7 +103,7 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad,
98103
'Possibly did not call parent GridSpec with the'
99104
' "figure" keyword')
100105

101-
for _ in range(2):
106+
for nn in range(2):
102107
# do the algorithm twice. This has to be done because decorations
103108
# change size after the first re-position (i.e. x/yticklabels get
104109
# larger/smaller). This second reposition tends to be much milder,
@@ -118,16 +123,56 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad,
118123
# update all the variables in the layout.
119124
fig._layoutgrid.update_variables()
120125

126+
warn_collapsed = ('constrained_layout not applied because '
127+
'axes sizes collapsed to zero. Try making '
128+
'figure larger or axes decorations smaller.')
121129
if _check_no_collapsed_axes(fig):
122130
_reposition_axes(fig, renderer, h_pad=h_pad, w_pad=w_pad,
123131
hspace=hspace, wspace=wspace)
132+
if compress:
133+
_compress_fixed_aspect(fig)
134+
# update all the variables in the layout.
135+
fig._layoutgrid.update_variables()
136+
if _check_no_collapsed_axes(fig):
137+
_reposition_axes(fig, renderer, h_pad=h_pad, w_pad=w_pad,
138+
hspace=hspace, wspace=wspace)
139+
else:
140+
_api.warn_external(warn_collapsed)
124141
else:
125-
_api.warn_external('constrained_layout not applied because '
126-
'axes sizes collapsed to zero. Try making '
127-
'figure larger or axes decorations smaller.')
142+
_api.warn_external(warn_collapsed)
128143
_reset_margins(fig)
129144

130145

146+
def _compress_fixed_aspect(fig):
147+
extraw = dict()
148+
extrah = dict()
149+
for ax in fig.axes:
150+
if hasattr(ax, 'get_subplotspec'):
151+
actual = ax.get_position(original=False)
152+
ax.apply_aspect()
153+
sub = ax.get_subplotspec()
154+
gs = sub.get_gridspec()
155+
if gs not in extraw.keys():
156+
extraw[gs] = np.zeros(gs.ncols)
157+
extrah[gs] = np.zeros(gs.nrows)
158+
orig = ax.get_position(original=True)
159+
actual = ax.get_position(original=False)
160+
dw = orig.width - actual.width
161+
if dw > 0:
162+
for i in sub.colspan:
163+
extraw[gs][i] = max(extraw[gs][i], dw)
164+
dh = orig.height - actual.height
165+
if dh > 0:
166+
for i in sub.rowspan:
167+
extrah[gs][i] = max(extrah[gs][i], dh)
168+
169+
fig._layoutgrid.edit_margin_min('left', np.sum(extraw[gs]) / 2)
170+
fig._layoutgrid.edit_margin_min('right', np.sum(extraw[gs]) / 2)
171+
172+
fig._layoutgrid.edit_margin_min('top', np.sum(extrah[gs]) / 2)
173+
fig._layoutgrid.edit_margin_min('bottom', np.sum(extrah[gs]) / 2)
174+
175+
131176
def _check_no_collapsed_axes(fig):
132177
"""
133178
Check that no axes have collapsed to zero size.

‎lib/matplotlib/_layoutgrid.py

Copy file name to clipboardExpand all lines: lib/matplotlib/_layoutgrid.py
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ def __repr__(self):
120120
f'innerW{self.inner_widths[j].value():1.3f}, ' \
121121
f'innerH{self.inner_heights[i].value():1.3f}, ' \
122122
f'ML{self.margins["left"][j].value():1.3f}, ' \
123-
f'MR{self.margins["right"][j].value():1.3f}, \n'
123+
f'MR{self.margins["right"][j].value():1.3f}, ' \
124+
f'MB{self.margins["bottom"][j].value():1.3f}, ' \
125+
f'MT{self.margins["top"][j].value():1.3f}, \n'
124126
return str
125127

126128
def reset_margins(self):

‎lib/matplotlib/figure.py

Copy file name to clipboardExpand all lines: lib/matplotlib/figure.py
+11-3Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2449,6 +2449,10 @@ def set_constrained_layout_pads(self, **kwargs):
24492449
Height padding between subplots, expressed as a fraction of the
24502450
subplot width. The total padding ends up being h_pad + hspace.
24512451
2452+
compress : boolean
2453+
Try to compress axes in constrained layout. Useful when
2454+
axes aspect ratios make it so that there is substantial
2455+
white space between them.
24522456
"""
24532457

24542458
todo = ['w_pad', 'h_pad', 'wspace', 'hspace']
@@ -2458,6 +2462,8 @@ def set_constrained_layout_pads(self, **kwargs):
24582462
else:
24592463
self._constrained_layout_pads[td] = (
24602464
mpl.rcParams['figure.constrained_layout.' + td])
2465+
self._constrained_layout_pads['compress'] = (
2466+
kwargs.get('compress', False))
24612467

24622468
def get_constrained_layout_pads(self, relative=False):
24632469
"""
@@ -2477,14 +2483,15 @@ def get_constrained_layout_pads(self, relative=False):
24772483
h_pad = self._constrained_layout_pads['h_pad']
24782484
wspace = self._constrained_layout_pads['wspace']
24792485
hspace = self._constrained_layout_pads['hspace']
2486+
compress = self._constrained_layout_pads['compress']
24802487

24812488
if relative and (w_pad is not None or h_pad is not None):
24822489
renderer0 = layoutgrid.get_renderer(self)
24832490
dpi = renderer0.dpi
24842491
w_pad = w_pad * dpi / renderer0.width
24852492
h_pad = h_pad * dpi / renderer0.height
24862493

2487-
return w_pad, h_pad, wspace, hspace
2494+
return w_pad, h_pad, wspace, hspace, compress
24882495

24892496
def set_canvas(self, canvas):
24902497
"""
@@ -3073,15 +3080,16 @@ def execute_constrained_layout(self, renderer=None):
30733080
"or you need to call figure or subplots "
30743081
"with the constrained_layout=True kwarg.")
30753082
return
3076-
w_pad, h_pad, wspace, hspace = self.get_constrained_layout_pads()
3083+
w_pad, h_pad, wspace, hspace, comp = self.get_constrained_layout_pads()
30773084
# convert to unit-relative lengths
30783085
fig = self
30793086
width, height = fig.get_size_inches()
30803087
w_pad = w_pad / width
30813088
h_pad = h_pad / height
30823089
if renderer is None:
30833090
renderer = _get_renderer(fig)
3084-
do_constrained_layout(fig, renderer, h_pad, w_pad, hspace, wspace)
3091+
do_constrained_layout(fig, renderer, h_pad, w_pad, hspace, wspace,
3092+
compress=comp)
30853093

30863094
def tight_layout(self, *, pad=1.08, h_pad=None, w_pad=None, rect=None):
30873095
"""

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.