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 3e4c299

Browse filesBrowse files
committed
Use SubplotSpec.row/colspans more, and deprecate get_rows_columns.
1 parent 6143565 commit 3e4c299
Copy full SHA for 3e4c299

File tree

Expand file treeCollapse file tree

4 files changed

+156
-212
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+156
-212
lines changed

‎doc/api/next_api_changes/deprecations.rst

Copy file name to clipboardExpand all lines: doc/api/next_api_changes/deprecations.rst
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,3 +386,8 @@ instead.
386386
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
387387
The unused ``animation.html_args`` rcParam and ``animation.HTMLWriter.args_key``
388388
attribute are deprecated.
389+
390+
``SubplotSpec.get_rows_columns``
391+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
392+
This method is deprecated. Use the ``GridSpec.nrows``, ``GridSpec.ncols``,
393+
``SubplotSpec.rowspan``, and ``SubplotSpec.colspan`` properties instead.

‎lib/matplotlib/_constrained_layout.py

Copy file name to clipboardExpand all lines: lib/matplotlib/_constrained_layout.py
+128-174Lines changed: 128 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,8 @@
5555
_log = logging.getLogger(__name__)
5656

5757

58-
def _in_same_column(colnum0min, colnum0max, colnumCmin, colnumCmax):
59-
return (colnumCmin <= colnum0min <= colnumCmax
60-
or colnumCmin <= colnum0max <= colnumCmax)
61-
62-
63-
def _in_same_row(rownum0min, rownum0max, rownumCmin, rownumCmax):
64-
return (rownumCmin <= rownum0min <= rownumCmax
65-
or rownumCmin <= rownum0max <= rownumCmax)
58+
def _spans_overlap(span0, span1):
59+
return span0.start in span1 or span1.start in span0
6660

6761

6862
def _axes_all_finite_sized(fig):
@@ -155,7 +149,7 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad,
155149
# fill in any empty gridspec slots w/ ghost axes...
156150
_make_ghost_gridspec_slots(fig, gs)
157151

158-
for nnn in range(2):
152+
for _ in range(2):
159153
# do the algorithm twice. This has to be done because decorators
160154
# change size after the first re-position (i.e. x/yticklabels get
161155
# larger/smaller). This second reposition tends to be much milder,
@@ -329,131 +323,109 @@ def _align_spines(fig, gs):
329323
if (hasattr(ax, 'get_subplotspec')
330324
and ax._layoutbox is not None
331325
and ax.get_subplotspec().get_gridspec() == gs)]
332-
rownummin = np.zeros(len(axs), dtype=np.int8)
333-
rownummax = np.zeros(len(axs), dtype=np.int8)
334-
colnummin = np.zeros(len(axs), dtype=np.int8)
335-
colnummax = np.zeros(len(axs), dtype=np.int8)
336-
width = np.zeros(len(axs))
337-
height = np.zeros(len(axs))
338-
339-
for n, ax in enumerate(axs):
326+
rowspans = []
327+
colspans = []
328+
heights = []
329+
widths = []
330+
331+
for ax in axs:
340332
ss0 = ax.get_subplotspec()
341-
rownummin[n], colnummin[n] = divmod(ss0.num1, ncols)
342-
rownummax[n], colnummax[n] = divmod(ss0.num2, ncols)
343-
width[n] = np.sum(
344-
width_ratios[colnummin[n]:(colnummax[n] + 1)])
345-
height[n] = np.sum(
346-
height_ratios[rownummin[n]:(rownummax[n] + 1)])
347-
348-
for nn, ax in enumerate(axs[:-1]):
349-
# now compare ax to all the axs:
350-
#
351-
# If the subplotspecs have the same colnumXmax, then line
352-
# up their right sides. If they have the same min, then
353-
# line up their left sides (and vertical equivalents).
354-
rownum0min, colnum0min = rownummin[nn], colnummin[nn]
355-
rownum0max, colnum0max = rownummax[nn], colnummax[nn]
356-
width0, height0 = width[nn], height[nn]
333+
rowspan = ss0.rowspan
334+
colspan = ss0.colspan
335+
rowspans.append(rowspan)
336+
colspans.append(colspan)
337+
heights.append(sum(height_ratios[rowspan.start:rowspan.stop]))
338+
widths.append(sum(width_ratios[colspan.start:colspan.stop]))
339+
340+
for idx0, ax0 in enumerate(axs):
341+
# Compare ax to all other axs: If the subplotspecs start (/stop) at
342+
# the same column, then line up their left (/right) sides; likewise
343+
# for rows/top/bottom.
344+
rowspan0 = rowspans[idx0]
345+
colspan0 = colspans[idx0]
346+
height0 = heights[idx0]
347+
width0 = widths[idx0]
357348
alignleft = False
358349
alignright = False
359350
alignbot = False
360351
aligntop = False
361352
alignheight = False
362353
alignwidth = False
363-
for mm in range(nn+1, len(axs)):
364-
axc = axs[mm]
365-
rownumCmin, colnumCmin = rownummin[mm], colnummin[mm]
366-
rownumCmax, colnumCmax = rownummax[mm], colnummax[mm]
367-
widthC, heightC = width[mm], height[mm]
368-
# Horizontally align axes spines if they have the
369-
# same min or max:
370-
if not alignleft and colnum0min == colnumCmin:
371-
# we want the _poslayoutboxes to line up on left
372-
# side of the axes spines...
373-
layoutbox.align([ax._poslayoutbox, axc._poslayoutbox],
354+
for idx1 in range(idx0 + 1, len(axs)):
355+
ax1 = axs[idx1]
356+
rowspan1 = rowspans[idx1]
357+
colspan1 = colspans[idx1]
358+
width1 = widths[idx1]
359+
height1 = heights[idx1]
360+
# Horizontally align axes spines if they have the same min or max:
361+
if not alignleft and colspan0.start == colspan1.start:
362+
_log.debug('same start columns; line up layoutbox lefts')
363+
layoutbox.align([ax0._poslayoutbox, ax1._poslayoutbox],
374364
'left')
375365
alignleft = True
376-
if not alignright and colnum0max == colnumCmax:
377-
# line up right sides of _poslayoutbox
378-
layoutbox.align([ax._poslayoutbox, axc._poslayoutbox],
366+
if not alignright and colspan0.stop == colspan1.stop:
367+
_log.debug('same stop columns; line up layoutbox rights')
368+
layoutbox.align([ax0._poslayoutbox, ax1._poslayoutbox],
379369
'right')
380370
alignright = True
381-
# Vertically align axes spines if they have the
382-
# same min or max:
383-
if not aligntop and rownum0min == rownumCmin:
384-
# line up top of _poslayoutbox
385-
_log.debug('rownum0min == rownumCmin')
386-
layoutbox.align([ax._poslayoutbox, axc._poslayoutbox],
371+
# Vertically align axes spines if they have the same min or max:
372+
if not aligntop and rowspan0.start == rowspan1.start:
373+
_log.debug('same start rows; line up layoutbox tops')
374+
layoutbox.align([ax0._poslayoutbox, ax1._poslayoutbox],
387375
'top')
388376
aligntop = True
389-
if not alignbot and rownum0max == rownumCmax:
390-
# line up bottom of _poslayoutbox
391-
_log.debug('rownum0max == rownumCmax')
392-
layoutbox.align([ax._poslayoutbox, axc._poslayoutbox],
377+
if not alignbot and rowspan0.stop == rowspan1.stop:
378+
_log.debug('same stop rows; line up layoutbox bottoms')
379+
layoutbox.align([ax0._poslayoutbox, ax1._poslayoutbox],
393380
'bottom')
394381
alignbot = True
395-
###########
382+
396383
# Now we make the widths and heights of position boxes
397384
# similar. (i.e the spine locations)
398-
# This allows vertically stacked subplots to have
399-
# different sizes if they occupy different amounts
400-
# of the gridspec: i.e.
401-
# gs = gridspec.GridSpec(3, 1)
402-
# ax1 = gs[0, :]
403-
# ax2 = gs[1:, :]
404-
# then drows0 = 1, and drowsC = 2, and ax2
405-
# should be at least twice as large as ax1.
385+
# This allows vertically stacked subplots to have different sizes
386+
# if they occupy different amounts of the gridspec, e.g. if
387+
# gs = gridspec.GridSpec(3, 1)
388+
# ax0 = gs[0, :]
389+
# ax1 = gs[1:, :]
390+
# then len(rowspan0) = 1, and len(rowspan1) = 2,
391+
# and ax1 should be at least twice as large as ax0.
406392
# But it can be more than twice as large because
407393
# it needs less room for the labeling.
408-
#
409-
# For height, this only needs to be done if the
410-
# subplots share a column. For width if they
411-
# share a row.
412-
413-
drowsC = (rownumCmax - rownumCmin + 1)
414-
drows0 = (rownum0max - rownum0min + 1)
415-
dcolsC = (colnumCmax - colnumCmin + 1)
416-
dcols0 = (colnum0max - colnum0min + 1)
417-
418-
if not alignheight and drows0 == drowsC:
419-
ax._poslayoutbox.constrain_height(
420-
axc._poslayoutbox.height * height0 / heightC)
394+
395+
# For heights, do it if the subplots share a column.
396+
if not alignheight and len(rowspan0) == len(rowspan1):
397+
ax0._poslayoutbox.constrain_height(
398+
ax1._poslayoutbox.height * height0 / height1)
421399
alignheight = True
422-
elif _in_same_column(colnum0min, colnum0max,
423-
colnumCmin, colnumCmax):
424-
if height0 > heightC:
425-
ax._poslayoutbox.constrain_height_min(
426-
axc._poslayoutbox.height * height0 / heightC)
400+
elif _spans_overlap(colspan0, colspan1):
401+
if height0 > height1:
402+
ax0._poslayoutbox.constrain_height_min(
403+
ax1._poslayoutbox.height * height0 / height1)
427404
# these constraints stop the smaller axes from
428405
# being allowed to go to zero height...
429-
axc._poslayoutbox.constrain_height_min(
430-
ax._poslayoutbox.height * heightC /
431-
(height0*1.8))
432-
elif height0 < heightC:
433-
axc._poslayoutbox.constrain_height_min(
434-
ax._poslayoutbox.height * heightC / height0)
435-
ax._poslayoutbox.constrain_height_min(
436-
ax._poslayoutbox.height * height0 /
437-
(heightC*1.8))
438-
# widths...
439-
if not alignwidth and dcols0 == dcolsC:
440-
ax._poslayoutbox.constrain_width(
441-
axc._poslayoutbox.width * width0 / widthC)
406+
ax1._poslayoutbox.constrain_height_min(
407+
ax0._poslayoutbox.height * height1 / (height0*1.8))
408+
elif height0 < height1:
409+
ax1._poslayoutbox.constrain_height_min(
410+
ax0._poslayoutbox.height * height1 / height0)
411+
ax0._poslayoutbox.constrain_height_min(
412+
ax0._poslayoutbox.height * height0 / (height1*1.8))
413+
# For widths, do it if the subplots share a row.
414+
if not alignwidth and len(colspan0) == len(colspan1):
415+
ax0._poslayoutbox.constrain_width(
416+
ax1._poslayoutbox.width * width0 / width1)
442417
alignwidth = True
443-
elif _in_same_row(rownum0min, rownum0max,
444-
rownumCmin, rownumCmax):
445-
if width0 > widthC:
446-
ax._poslayoutbox.constrain_width_min(
447-
axc._poslayoutbox.width * width0 / widthC)
448-
axc._poslayoutbox.constrain_width_min(
449-
ax._poslayoutbox.width * widthC /
450-
(width0*1.8))
451-
elif width0 < widthC:
452-
axc._poslayoutbox.constrain_width_min(
453-
ax._poslayoutbox.width * widthC / width0)
454-
ax._poslayoutbox.constrain_width_min(
455-
axc._poslayoutbox.width * width0 /
456-
(widthC*1.8))
418+
elif _spans_overlap(rowspan0, rowspan1):
419+
if width0 > width1:
420+
ax0._poslayoutbox.constrain_width_min(
421+
ax1._poslayoutbox.width * width0 / width1)
422+
ax1._poslayoutbox.constrain_width_min(
423+
ax0._poslayoutbox.width * width1 / (width0*1.8))
424+
elif width0 < width1:
425+
ax1._poslayoutbox.constrain_width_min(
426+
ax0._poslayoutbox.width * width1 / width0)
427+
ax0._poslayoutbox.constrain_width_min(
428+
ax1._poslayoutbox.width * width0 / (width1*1.8))
457429

458430

459431
def _arrange_subplotspecs(gs, hspace=0, wspace=0):
@@ -470,34 +442,25 @@ def _arrange_subplotspecs(gs, hspace=0, wspace=0):
470442
for child0 in sschildren:
471443
ss0 = child0.artist
472444
nrows, ncols = ss0.get_gridspec().get_geometry()
473-
rowNum0min, colNum0min = divmod(ss0.num1, ncols)
474-
rowNum0max, colNum0max = divmod(ss0.num2, ncols)
445+
rowspan0 = ss0.rowspan
446+
colspan0 = ss0.colspan
475447
sschildren = sschildren[1:]
476-
for childc in sschildren:
477-
ssc = childc.artist
478-
rowNumCmin, colNumCmin = divmod(ssc.num1, ncols)
479-
rowNumCmax, colNumCmax = divmod(ssc.num2, ncols)
480-
# OK, this tells us the relative layout of ax
481-
# with axc
482-
thepad = wspace / ncols
483-
if colNum0max < colNumCmin:
484-
layoutbox.hstack([ss0._layoutbox, ssc._layoutbox],
485-
padding=thepad)
486-
if colNumCmax < colNum0min:
487-
layoutbox.hstack([ssc._layoutbox, ss0._layoutbox],
488-
padding=thepad)
489-
490-
####
448+
for child1 in sschildren:
449+
ss1 = child1.artist
450+
rowspan1 = ss1.rowspan
451+
colspan1 = ss1.colspan
452+
# OK, this tells us the relative layout of child0 with child1.
453+
pad = wspace / ncols
454+
if colspan0.stop <= colspan1.start:
455+
layoutbox.hstack([ss0._layoutbox, ss1._layoutbox], padding=pad)
456+
if colspan1.stop <= colspan0.start:
457+
layoutbox.hstack([ss1._layoutbox, ss0._layoutbox], padding=pad)
491458
# vertical alignment
492-
thepad = hspace / nrows
493-
if rowNum0max < rowNumCmin:
494-
layoutbox.vstack([ss0._layoutbox,
495-
ssc._layoutbox],
496-
padding=thepad)
497-
if rowNumCmax < rowNum0min:
498-
layoutbox.vstack([ssc._layoutbox,
499-
ss0._layoutbox],
500-
padding=thepad)
459+
pad = hspace / nrows
460+
if rowspan0.stop <= rowspan1.start:
461+
layoutbox.vstack([ss0._layoutbox, ss1._layoutbox], padding=pad)
462+
if rowspan1.stop <= rowspan0.start:
463+
layoutbox.vstack([ss1._layoutbox, ss0._layoutbox], padding=pad)
501464

502465

503466
def layoutcolorbarsingle(ax, cax, shrink, aspect, location, pad=0.05):
@@ -560,33 +523,28 @@ def layoutcolorbarsingle(ax, cax, shrink, aspect, location, pad=0.05):
560523

561524

562525
def _getmaxminrowcolumn(axs):
563-
# helper to get the min/max rows and columns of a list of axes.
564-
maxrow = -100000
565-
minrow = 1000000
566-
maxax = None
567-
minax = None
568-
maxcol = -100000
569-
mincol = 1000000
570-
maxax_col = None
571-
minax_col = None
572-
526+
"""
527+
Find axes covering the first and last rows and columns of a list of axes.
528+
"""
529+
startrow = startcol = np.inf
530+
stoprow = stopcol = -np.inf
531+
startax_row = startax_col = stopax_row = stopax_col = None
573532
for ax in axs:
574533
subspec = ax.get_subplotspec()
575-
nrows, ncols, row_start, row_stop, col_start, col_stop = \
576-
subspec.get_rows_columns()
577-
if row_stop > maxrow:
578-
maxrow = row_stop
579-
maxax = ax
580-
if row_start < minrow:
581-
minrow = row_start
582-
minax = ax
583-
if col_stop > maxcol:
584-
maxcol = col_stop
585-
maxax_col = ax
586-
if col_start < mincol:
587-
mincol = col_start
588-
minax_col = ax
589-
return (minrow, maxrow, minax, maxax, mincol, maxcol, minax_col, maxax_col)
534+
if subspec.rowspan.start < startrow:
535+
startrow = subspec.rowspan.start
536+
startax_row = ax
537+
if subspec.rowspan.stop > stoprow:
538+
stoprow = subspec.rowspan.stop
539+
stopax_row = ax
540+
if subspec.colspan.start < startcol:
541+
startcol = subspec.colspan.start
542+
startax_col = ax
543+
if subspec.colspan.stop > stopcol:
544+
stopcol = subspec.colspan.stop
545+
stopax_col = ax
546+
return (startrow, stoprow - 1, startax_row, stopax_row,
547+
startcol, stopcol - 1, startax_col, stopax_col)
590548

591549

592550
def layoutcolorbargridspec(parents, cax, shrink, aspect, location, pad=0.05):
@@ -630,18 +588,16 @@ def layoutcolorbargridspec(parents, cax, shrink, aspect, location, pad=0.05):
630588
# Horizontal Layout: need to check all the axes in this gridspec
631589
for ch in gslb.children:
632590
subspec = ch.artist
633-
nrows, ncols, row_start, row_stop, col_start, col_stop = \
634-
subspec.get_rows_columns()
635591
if location == 'right':
636-
if col_stop <= maxcol:
592+
if subspec.colspan.stop - 1 <= maxcol:
637593
order = [subspec._layoutbox, lb]
638594
# arrange to right of the parents
639-
if col_start > maxcol:
595+
elif subspec.colspan.start > maxcol:
640596
order = [lb, subspec._layoutbox]
641597
elif location == 'left':
642-
if col_start >= mincol:
598+
if subspec.colspan.start >= mincol:
643599
order = [lb, subspec._layoutbox]
644-
if col_stop < mincol:
600+
elif subspec.colspan.stop - 1 < mincol:
645601
order = [subspec._layoutbox, lb]
646602
layoutbox.hstack(order, padding=pad * gslb.width,
647603
strength='strong')
@@ -686,17 +642,15 @@ def layoutcolorbargridspec(parents, cax, shrink, aspect, location, pad=0.05):
686642
# Vertical Layout: need to check all the axes in this gridspec
687643
for ch in gslb.children:
688644
subspec = ch.artist
689-
nrows, ncols, row_start, row_stop, col_start, col_stop = \
690-
subspec.get_rows_columns()
691645
if location == 'bottom':
692-
if row_stop <= minrow:
646+
if subspec.rowspan.stop - 1 <= minrow:
693647
order = [subspec._layoutbox, lb]
694-
if row_start > maxrow:
648+
elif subspec.rowspan.start > maxrow:
695649
order = [lb, subspec._layoutbox]
696650
elif location == 'top':
697-
if row_stop < minrow:
651+
if subspec.rowspan.stop - 1 < minrow:
698652
order = [subspec._layoutbox, lb]
699-
if row_start >= maxrow:
653+
elif subspec.rowspan.start >= maxrow:
700654
order = [lb, subspec._layoutbox]
701655
layoutbox.vstack(order, padding=pad * gslb.width,
702656
strength='strong')

0 commit comments

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