8000 Merge pull request #10658 from jklymak/fix-speedup-constrainedlayout · matplotlib/matplotlib@b5391ce · GitHub
[go: up one dir, main page]

Skip to content

Commit b5391ce

Browse files
authored
Merge pull request #10658 from jklymak/fix-speedup-constrainedlayout
PRF: Speed up constrained layout
2 parents 7d85cf0 + 4f69414 commit b5391ce

File tree

1 file changed

+64
-64
lines changed

1 file changed

+64
-64
lines changed

lib/matplotlib/_constrained_layout.py

Lines changed: 64 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -76,35 +76,15 @@ def get_axall_tightbbox(ax, renderer):
7676
return bbox
7777

7878

79-
def in_same_column(ss0, ssc):
80-
nrows, ncols = ss0.get_gridspec().get_geometry()
81-
82-
if ss0.num2 is None:
83-
ss0.num2 = ss0.num1
84-
rownum0min, colnum0min = divmod(ss0.num1, ncols)
85-
rownum0max, colnum0max = divmod(ss0.num2, ncols)
86-
if ssc.num2 is None:
87-
ssc.num2 = ssc.num1
88-
rownumCmin, colnumCmin = divmod(ssc.num1, ncols)
89-
rownumCmax, colnumCmax = divmod(ssc.num2, ncols)
79+
def in_same_column(colnum0min, colnum0max, colnumCmin, colnumCmax):
9080
if colnum0min >= colnumCmin and colnum0min <= colnumCmax:
9181
return True
9282
if colnum0max >= colnumCmin and colnum0max <= colnumCmax:
9383
return True
9484
return False
9585

9686

97-
def in_same_row(ss0, ssc):
98-
nrows, ncols = ss0.get_gridspec().get_geometry()
99-
100-
if ss0.num2 is None:
101-
ss0.num2 = ss0.num1
102-
rownum0min, colnum0min = divmod(ss0.num1, ncols)
103-
rownum0max, colnum0max = divmod(ss0.num2, ncols)
104-
if ssc.num2 is None:
105-
ssc.num2 = ssc.num1
106-
rownumCmin, colnumCmin = divmod(ssc.num1, ncols)
107-
rownumCmax, colnumCmax = divmod(ssc.num2, ncols)
87+
def in_same_row(rownum0min, rownum0max, rownumCmin, rownumCmax):
10888
if rownum0min >= rownumCmin and rownum0min <= rownumCmax:
10989
return True
11090
if rownum0max >= rownumCmin and rownum0max <= rownumCmax:
@@ -177,6 +157,7 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad,
177157
margins) is very large. There must be a math way to check for this case.
178158
179159
'''
160+
180161
invTransFig = fig.transFigure.inverted().transform_bbox
181162

182163
# list of unique gridspecs that contain child axes:
@@ -314,52 +295,77 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad,
314295
and ax._layoutbox is not None):
315296
if ax.get_subplotspec().get_gridspec() == gs:
316297
axs += [ax]
317-
for ax in axs:
318-
axs = axs[1:]
298+
rownummin = np.zeros(len(axs), dtype=np.int8)
299+
rownummax = np.zeros(len(axs), dtype=np.int8)
300+
colnummin = np.zeros(len(axs), dtype=np.int8)
301+
colnummax = np.zeros(len(axs), dtype=np.int8)
302+
width = np.zeros(len(axs))
303+
height = np.zeros(len(axs))
304+
305+
for n, ax in enumerate(axs):
306+
ss0 = ax.get_subplotspec()
307+
if ss0.num2 is None:
308+
ss0.num2 = ss0.num1
309+
rownummin[n], colnummin[n] = divmod(ss0.num1, ncols)
310+
rownummax[n], colnummax[n] = divmod(ss0.num2, ncols)
311+
width[n] = np.sum(
312+
width_ratios[colnummin[n]:(colnummax[n] + 1)])
313+
height[n] = np.sum(
314+
height_ratios[rownummin[n]:(rownummax[n] + 1)])
315+
316+
for nn, ax in enumerate(axs[:-1]):
317+
ss0 = ax.get_subplotspec()
318+
319319
# now compare ax to all the axs:
320320
#
321321
# If the subplotspecs have the same colnumXmax, then line
322322
# up their right sides. If they have the same min, then
323323
# line up their left sides (and vertical equivalents).
324-
ss0 = ax.get_subplotspec()
325-
if ss0.num2 is None:
326-
ss0.num2 = ss0.num1
327-
rownum0min, colnum0min = divmod(ss0.num1, ncols)
328-
rownum0max, colnum0max = divmod(ss0.num2, ncols)
329-
for axc in axs:
330-
ssc = axc.get_subplotspec()
331-
# get the rownums and colnums
332-
rownumCmin, colnumCmin = divmod(ssc.num1, ncols)
333-
if ssc.num2 is None:
334-
ssc.num2 = ssc.num1
335-
rownumCmax, colnumCmax = divmod(ssc.num2, ncols)
336-
324+
rownum0min, colnum0min = rownummin[nn], colnummin[nn]
325+
rownum0max, colnum0max = rownummax[nn], colnummax[nn]
326+
width0, height0 = width[nn], height[nn]
327+
alignleft = False
328+
alignright = False
329+
alignbot = False
330+
aligntop = False
331+
alignheight = False
332+
alignwidth = False
333+
for mm in range(nn+1, len(axs)):
334+
axc = axs[mm]
335+
rownumCmin, colnumCmin = rownummin[mm], colnummin[mm]
336+
rownumCmax, colnumCmax = rownummax[mm], colnummax[mm]
337+
widthC, heightC = width[mm], height[mm]
337338
# Horizontally align axes spines if they have the
338339
# same min or max:
339-
if colnum0min == colnumCmin:
340+
if not alignleft and colnum0min == colnumCmin:
340341
# we want the _poslayoutboxes to line up on left
341342
# side of the axes spines...
342343
layoutbox.align([ax._poslayoutbox,
343344
axc._poslayoutbox],
344345
'left')
345-
if colnum0max == colnumCmax:
346+
alignleft = True
347+
348+
if not alignright and colnum0max == colnumCmax:
346349
# line up right sides of _poslayoutbox
347350
layoutbox.align([ax._poslayoutbox,
348351
axc._poslayoutbox],
349352
'right')
353+
alignright = True
350354
# Vertically align axes spines if they have the
351355
# same min or max:
352-
if rownum0min == rownumCmin:
356+
if not aligntop and rownum0min == rownumCmin:
353357
# line up top of _poslayoutbox
354358
_log.debug('rownum0min == rownumCmin')
355359
layoutbox.align([ax._poslayoutbox, axc._poslayoutbox],
356360
'top')
357-
if rownum0max == rownumCmax:
361+
aligntop = True
362+
363+
if not alignbot and rownum0max == rownumCmax:
358364
# line up bottom of _poslayoutbox
359365
_log.debug('rownum0max == rownumCmax')
360366
layoutbox.align([ax._poslayoutbox, axc._poslayoutbox],
361367
'bottom')
362-
368+
alignbot = True
363369
###########
364370
# Now we make the widths and heights of position boxes
365371
# similar. (i.e the spine locations)
@@ -377,57 +383,51 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad,
377383
# For height, this only needs to be done if the
378384
# subplots share a column. For width if they
379385
# share a row.
380-
widthC = np.sum(
381-
width_ratios[colnumCmin:(colnumCmax + 1)])
382-
width0 = np.sum(
383-
width_ratios[colnum0min:(colnum0max + 1)])
384-
heightC = np.sum(
385-
height_ratios[rownumCmin:(rownumCmax + 1)])
386-
height0 = np.sum(
387-
height_ratios[rownum0min:(rownum0max + 1)])
388386

389387
drowsC = (rownumCmax - rownumCmin + 1)
390388
drows0 = (rownum0max - rownum0min + 1)
391389
dcolsC = (colnumCmax - colnumCmin + 1)
392390
dcols0 = (colnum0max - colnum0min + 1)
393391

394-
if height0 > heightC:
395-
if in_same_column(ss0, ssc):
392+
if not alignheight and drows0 == drowsC:
393+
ax._poslayoutbox.constrain_height(
394+
axc._poslayoutbox.height * height0 / heightC)
395+
alignheight = True
396+
elif in_same_column(colnum0min, colnum0max,
397+
colnumCmin, colnumCmax):
398+
if height0 > heightC:
396399
ax._poslayoutbox.constrain_height_min(
397400
axc._poslayoutbox.height * height0 / heightC)
398401
# these constraints stop the smaller axes from
399402
# being allowed to go to zero height...
400403
axc._poslayoutbox.constrain_height_min(
401404
ax._poslayoutbox.height * heightC /
402405
(height0*1.8))
403-
else:
404-
if in_same_column(ss0, ssc):
406+
elif height0 < heightC:
405407
axc._poslayoutbox.constrain_height_min(
406408
ax._poslayoutbox.height * heightC / height0)
407409
ax._poslayoutbox.constrain_height_min(
408410
ax._poslayoutbox.height * height0 /
409411
(heightC*1.8))
410-
if drows0 == drowsC:
411-
ax._poslayoutbox.constrain_height(
412-
axc._poslayoutbox.height * height0 / heightC)
413412
# widths...
414-
if width0 > widthC:
415-
if in_same_row(ss0, ssc):
413+
if not alignwidth and dcols0 == dcolsC:
414+
ax._poslayoutbox.constrain_width(
415+
axc._poslayoutbox.width * width0 / widthC)
416+
alignwidth = True
417+
elif in_same_row(rownum0min, rownum0max,
418+
rownumCmin, rownumCmax):
419+
if width0 > widthC:
416420
ax._poslayoutbox.constrain_width_min(
417421
axc._poslayoutbox.width * width0 / widthC)
418422
axc._poslayoutbox.constrain_width_min(
419423
ax._poslayoutbox.width * widthC /
420424
(width0*1.8))
421-
else:
422-
if in_same_row(ss0, ssc):
425+
elif width0 < widthC:
423426
axc._poslayoutbox.constrain_width_min(
424427
ax._poslayoutbox.width * widthC / width0)
425428
ax._poslayoutbox.constrain_width_min(
426429
axc._poslayoutbox.width * width0 /
427430
(widthC*1.8))
428-
if dcols0 == dcolsC:
429-
ax._poslayoutbox.constrain_width(
430-
axc._poslayoutbox.width * width0 / widthC)
431431

432432
fig._layoutbox.constrained_layout_called += 1
433433
fig._layoutbox.update_variables()

0 commit comments

Comments
 (0)
0