From 7f15d446e117dd977446914753386573b643798e Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Sun, 12 Apr 2020 15:58:27 -0700 Subject: [PATCH 1/5] JUNK: notes --- lib/matplotlib/_constrained_layout.py | 85 ++++++++++++++++++++++++++- lib/matplotlib/_layoutbox.py | 8 ++- lib/matplotlib/axes/_subplots.py | 2 +- lib/matplotlib/figure.py | 13 +++- lib/matplotlib/gridspec.py | 2 + 5 files changed, 102 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/_constrained_layout.py b/lib/matplotlib/_constrained_layout.py index bb20713700dc..fbcca710bdd1 100644 --- a/lib/matplotlib/_constrained_layout.py +++ b/lib/matplotlib/_constrained_layout.py @@ -71,7 +71,7 @@ def _axes_all_finite_sized(fig): ###################################################### def do_constrained_layout(fig, renderer, h_pad, w_pad, - hspace=None, wspace=None): + hspace=None, wspace=None, reset=True): """ Do the constrained_layout. Called at draw time in ``figure.constrained_layout()`` @@ -130,8 +130,12 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad, # This can break down if the decoration size for the right hand axis (the # margins) is very large. There must be a math way to check for this case. + print("IN HERE") invTransFig = fig.transFigure.inverted().transform_bbox + conh = None + conw = None + # list of unique gridspecs that contain child axes: gss = set() for ax in fig.axes: @@ -154,12 +158,17 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad, # change size after the first re-position (i.e. x/yticklabels get # larger/smaller). This second reposition tends to be much milder, # so doing twice makes things work OK. + bboxes = {} # need these for packing the layout later... for ax in fig.axes: _log.debug(ax._layoutbox) if ax._layoutbox is not None: # make margins for each layout box based on the size of # the decorators. - _make_layout_margins(ax, renderer, h_pad, w_pad) + bbox = _make_layout_margins(ax, renderer, h_pad, w_pad) + else: + bbox = None + bboxes[ax] = bbox + print(bboxes) # do layout for suptitle. suptitle = fig._suptitle @@ -199,7 +208,61 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad, for gs in gss: _align_spines(fig, gs) + # prob with autoscaling: no redraw to see how big the new + # layout should be... + if not reset: + for gs in gss: + axs = [ax for ax in fig.axes + if (hasattr(ax, 'get_subplotspec') + and ax._layoutbox is not None + and ax.get_subplotspec().get_gridspec() == gs)] + nrows, ncols = gs.get_geometry() + # get widths: + dxs = np.zeros(ncols) + for i in range(ncols): + print('checking i', i) + for ax in axs: + ss = ax.get_subplotspec() + if i in ss.colspan: + dn = ss.rowspan[-1] - ss.rowspan[0] + 1 + dx = (bboxes[ax].bounds[2] + 2 * w_pad)/ dn + dxs[i] = max(dxs[i], dx) + dx = np.sum(dxs) + + dys = np.zeros(nrows) + for i in range(nrows): + print('checking i', i) + for ax in axs: + ss = ax.get_subplotspec() + if i in ss.rowspan: + dn = ss.colspan[-1] - ss.colspan[0] + 1 + dy = (bboxes[ax].bounds[3] + 2 * h_pad)/ dn + dys[i] = max(dys[i], dy) + dy = np.sum(dys) + + print('dx dy', dx, dy) + parent = gs._layoutbox.parent + if dy < dx: + if conh is not None: + gs._layoutbox.solver.removeConstraint(conh) + gs._layoutbox.edit_height(dy) + conw = gs._layoutbox.constrain_width(parent.width) + #gs._layoutbox.edit_bottom_margin_min((parent.height-dy)/2) + else: + if conw is not None: + gs._layoutbox.solver.removeConstraint(conw) + conw = gs._layoutbox.constrain_width(dx) + conh = gs._layoutbox.constrain_height(parent.height) + #gs._layoutbox.edit_bottom_margin((parent.width-dx)/2) + else: # reset! + for gs in gss: + parent = gs._layoutbox.parent + conh = gs._layoutbox.constrain_height(parent.height) + conw = gs._layoutbox.constrain_height(parent.width) + + fig._layoutbox.constrained_layout_called += 1 + # call the kiwi solver: fig._layoutbox.update_variables() # check if any axes collapsed to zero. If not, don't change positions: @@ -223,6 +286,14 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad, cbook._warn_external('constrained_layout not applied. At least ' 'one axes collapsed to zero width or height.') + ## clean up temporary constraints: + for gs in gss: + if conh is not None: + gs._layoutbox.solver.removeConstraint(conh) + if conw is not None: + gs._layoutbox.solver.removeConstraint(conw) + + def _make_ghost_gridspec_slots(fig, gs): """ @@ -236,6 +307,7 @@ def _make_ghost_gridspec_slots(fig, gs): hassubplotspec = np.zeros(nrows * ncols, dtype=bool) axs = [] for ax in fig.axes: + print(ax, ax._layoutbox) if (hasattr(ax, 'get_subplotspec') and ax._layoutbox is not None and ax.get_subplotspec().get_gridspec() == gs): @@ -243,10 +315,12 @@ def _make_ghost_gridspec_slots(fig, gs): for ax in axs: ss0 = ax.get_subplotspec() hassubplotspec[ss0.num1:(ss0.num2 + 1)] = True + print(hassubplotspec, axs) for nn, hss in enumerate(hassubplotspec): if not hss: # this gridspec slot doesn't have an axis so we # make a "ghost". + print('ghosty!', nn) ax = fig.add_subplot(gs[nn]) ax.set_visible(False) @@ -256,6 +330,8 @@ def _make_layout_margins(ax, renderer, h_pad, w_pad): For each axes, make a margin between the *pos* layoutbox and the *axes* layoutbox be a minimum size that can accommodate the decorations on the axis. + + Returns the bbox for some width/heigth calcs outside this loop. """ fig = ax.figure invTransFig = fig.transFigure.inverted().transform_bbox @@ -300,6 +376,7 @@ def _make_layout_margins(ax, renderer, h_pad, w_pad): ax._poslayoutbox.constrain_bottom_margin(0, strength='weak') ax._poslayoutbox.constrain_right_margin(0, strength='weak') ax._poslayoutbox.constrain_left_margin(0, strength='weak') + return bbox def _align_spines(fig, gs): @@ -310,9 +387,11 @@ def _align_spines(fig, gs): as they should be. """ # for each gridspec... + print('Aligning Spines!') nrows, ncols = gs.get_geometry() width_ratios = gs.get_width_ratios() height_ratios = gs.get_height_ratios() + print('hieght_ratios', height_ratios) if width_ratios is None: width_ratios = np.ones(ncols) if height_ratios is None: @@ -394,6 +473,7 @@ def _align_spines(fig, gs): # For heights, do it if the subplots share a column. if not alignheight and len(rowspan0) == len(rowspan1): + print('heights', height0, height1) ax0._poslayoutbox.constrain_height( ax1._poslayoutbox.height * height0 / height1) alignheight = True @@ -428,6 +508,7 @@ def _align_spines(fig, gs): ax1._poslayoutbox.width * width0 / (width1*1.8)) + def _arrange_subplotspecs(gs, hspace=0, wspace=0): """Recursively arrange the subplotspec children of the given gridspec.""" sschildren = [] diff --git a/lib/matplotlib/_layoutbox.py b/lib/matplotlib/_layoutbox.py index 0afa2e4829f2..93418e88c635 100644 --- a/lib/matplotlib/_layoutbox.py +++ b/lib/matplotlib/_layoutbox.py @@ -324,6 +324,7 @@ def constrain_width(self, width, strength='strong'): """ c = (self.width == width) self.solver.addConstraint(c | strength) + return c def constrain_width_min(self, width, strength='strong'): c = (self.width >= width) @@ -652,11 +653,13 @@ def print_tree(lb): print_tree(lb.parent) -def plot_children(fig, box, level=0, printit=True): +def plot_children(fig, box, level=0, printit=True, stop=1000): """Simple plotting to show where boxes are.""" import matplotlib import matplotlib.pyplot as plt + if stop < 0: + return if isinstance(fig, matplotlib.figure.Figure): ax = fig.add_axes([0., 0., 1., 1.]) ax.set_facecolor([1., 1., 1., 0.7]) @@ -665,6 +668,7 @@ def plot_children(fig, box, level=0, printit=True): else: ax = fig + import matplotlib.patches as patches colors = plt.rcParams["axes.prop_cycle"].by_key()["color"] if printit: @@ -692,4 +696,4 @@ def plot_children(fig, box, level=0, printit=True): ha='right', va='top', size=12-level, color=colors[level]) - plot_children(ax, child, level=level+1, printit=printit) + plot_children(ax, child, level=level+1, printit=printit, stop=stop-1) diff --git a/lib/matplotlib/axes/_subplots.py b/lib/matplotlib/axes/_subplots.py index 90511e58b394..894598636bcc 100644 --- a/lib/matplotlib/axes/_subplots.py +++ b/lib/matplotlib/axes/_subplots.py @@ -92,7 +92,7 @@ def get_gridspec(self): def update_params(self): """Update the subplot position from ``self.figure.subplotpars``.""" self.figbox, _, _, self.numRows, self.numCols = \ - self.get_subplotspec().get_position(self.figure, + self.get_subplotspec().get_position(self.figure, return_all=True) @cbook.deprecated("3.2", alternative="ax.get_subplotspec().rowspan.start") diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 299e893993f8..449e6873f237 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1719,7 +1719,14 @@ def draw(self, renderer): try: renderer.open_group('figure', gid=self.get_gid()) if self.get_constrained_layout() and self.axes: - self.execute_constrained_layout(renderer) + self.execute_constrained_layout(renderer, reset=True) + # yay extra draw! + self.patch.draw(renderer) + mimage._draw_list_compositing_images( + renderer, self, artists, self.suppressComposite) + self.execute_constrained_layout(renderer, reset=False) + + if self.get_tight_layout() and self.axes: try: self.tight_layout(**self._tight_parameters) @@ -2377,7 +2384,7 @@ def init_layoutbox(self): parent=None, name='figlb', artist=self) self._layoutbox.constrain_geometry(0., 0., 1., 1.) - def execute_constrained_layout(self, renderer=None): + def execute_constrained_layout(self, renderer=None, reset=True): """ Use ``layoutbox`` to determine pos positions within axes. @@ -2403,7 +2410,7 @@ def execute_constrained_layout(self, renderer=None): h_pad = h_pad / height if renderer is None: renderer = layoutbox.get_renderer(fig) - do_constrained_layout(fig, renderer, h_pad, w_pad, hspace, wspace) + do_constrained_layout(fig, renderer, h_pad, w_pad, hspace, wspace, reset=reset) @cbook._delete_parameter("3.2", "renderer") def tight_layout(self, renderer=None, pad=1.08, h_pad=None, w_pad=None, diff --git a/lib/matplotlib/gridspec.py b/lib/matplotlib/gridspec.py index 844ad81fcaab..eb17dc2127ec 100644 --- a/lib/matplotlib/gridspec.py +++ b/lib/matplotlib/gridspec.py @@ -195,6 +195,8 @@ def get_grid_positions(self, fig, raw=False): fig_tops, fig_bottoms = (top - cell_hs).reshape((-1, 2)).T fig_lefts, fig_rights = (left + cell_ws).reshape((-1, 2)).T + + print('Done this!') return fig_bottoms, fig_tops, fig_lefts, fig_rights def __getitem__(self, key): From 36ad19ea9b895fba32ddd313e60c379500439af0 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Sat, 18 Apr 2020 19:12:29 -0700 Subject: [PATCH 2/5] FIX --- lib/matplotlib/_constrained_layout.py | 144 +++++++++++++------------- lib/matplotlib/gridspec.py | 1 - 2 files changed, 74 insertions(+), 71 deletions(-) diff --git a/lib/matplotlib/_constrained_layout.py b/lib/matplotlib/_constrained_layout.py index fbcca710bdd1..1da4e6264479 100644 --- a/lib/matplotlib/_constrained_layout.py +++ b/lib/matplotlib/_constrained_layout.py @@ -130,12 +130,8 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad, # This can break down if the decoration size for the right hand axis (the # margins) is very large. There must be a math way to check for this case. - print("IN HERE") invTransFig = fig.transFigure.inverted().transform_bbox - conh = None - conw = None - # list of unique gridspecs that contain child axes: gss = set() for ax in fig.axes: @@ -168,7 +164,6 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad, else: bbox = None bboxes[ax] = bbox - print(bboxes) # do layout for suptitle. suptitle = fig._suptitle @@ -208,59 +203,6 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad, for gs in gss: _align_spines(fig, gs) - # prob with autoscaling: no redraw to see how big the new - # layout should be... - if not reset: - for gs in gss: - axs = [ax for ax in fig.axes - if (hasattr(ax, 'get_subplotspec') - and ax._layoutbox is not None - and ax.get_subplotspec().get_gridspec() == gs)] - nrows, ncols = gs.get_geometry() - # get widths: - dxs = np.zeros(ncols) - for i in range(ncols): - print('checking i', i) - for ax in axs: - ss = ax.get_subplotspec() - if i in ss.colspan: - dn = ss.rowspan[-1] - ss.rowspan[0] + 1 - dx = (bboxes[ax].bounds[2] + 2 * w_pad)/ dn - dxs[i] = max(dxs[i], dx) - dx = np.sum(dxs) - - dys = np.zeros(nrows) - for i in range(nrows): - print('checking i', i) - for ax in axs: - ss = ax.get_subplotspec() - if i in ss.rowspan: - dn = ss.colspan[-1] - ss.colspan[0] + 1 - dy = (bboxes[ax].bounds[3] + 2 * h_pad)/ dn - dys[i] = max(dys[i], dy) - dy = np.sum(dys) - - print('dx dy', dx, dy) - parent = gs._layoutbox.parent - if dy < dx: - if conh is not None: - gs._layoutbox.solver.removeConstraint(conh) - gs._layoutbox.edit_height(dy) - conw = gs._layoutbox.constrain_width(parent.width) - #gs._layoutbox.edit_bottom_margin_min((parent.height-dy)/2) - else: - if conw is not None: - gs._layoutbox.solver.removeConstraint(conw) - conw = gs._layoutbox.constrain_width(dx) - conh = gs._layoutbox.constrain_height(parent.height) - #gs._layoutbox.edit_bottom_margin((parent.width-dx)/2) - else: # reset! - for gs in gss: - parent = gs._layoutbox.parent - conh = gs._layoutbox.constrain_height(parent.height) - conw = gs._layoutbox.constrain_height(parent.width) - - fig._layoutbox.constrained_layout_called += 1 # call the kiwi solver: fig._layoutbox.update_variables() @@ -285,13 +227,11 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad, else: cbook._warn_external('constrained_layout not applied. At least ' 'one axes collapsed to zero width or height.') + _squish(fig) + + + - ## clean up temporary constraints: - for gs in gss: - if conh is not None: - gs._layoutbox.solver.removeConstraint(conh) - if conw is not None: - gs._layoutbox.solver.removeConstraint(conw) @@ -307,7 +247,6 @@ def _make_ghost_gridspec_slots(fig, gs): hassubplotspec = np.zeros(nrows * ncols, dtype=bool) axs = [] for ax in fig.axes: - print(ax, ax._layoutbox) if (hasattr(ax, 'get_subplotspec') and ax._layoutbox is not None and ax.get_subplotspec().get_gridspec() == gs): @@ -315,12 +254,10 @@ def _make_ghost_gridspec_slots(fig, gs): for ax in axs: ss0 = ax.get_subplotspec() hassubplotspec[ss0.num1:(ss0.num2 + 1)] = True - print(hassubplotspec, axs) for nn, hss in enumerate(hassubplotspec): if not hss: # this gridspec slot doesn't have an axis so we # make a "ghost". - print('ghosty!', nn) ax = fig.add_subplot(gs[nn]) ax.set_visible(False) @@ -387,11 +324,9 @@ def _align_spines(fig, gs): as they should be. """ # for each gridspec... - print('Aligning Spines!') nrows, ncols = gs.get_geometry() width_ratios = gs.get_width_ratios() height_ratios = gs.get_height_ratios() - print('hieght_ratios', height_ratios) if width_ratios is None: width_ratios = np.ones(ncols) if height_ratios is None: @@ -473,7 +408,6 @@ def _align_spines(fig, gs): # For heights, do it if the subplots share a column. if not alignheight and len(rowspan0) == len(rowspan1): - print('heights', height0, height1) ax0._poslayoutbox.constrain_height( ax1._poslayoutbox.height * height0 / height1) alignheight = True @@ -749,3 +683,73 @@ def layoutcolorbargridspec(parents, cax, shrink, aspect, location, pad=0.05): strength='medium') return lb, lbpos + +def _squish(fig, w_pad=0.0, h_pad=0.0): + gss = set() + bboxes = {} # need these for packing the layout later... + invTransFig = fig.transFigure.inverted().transform_bbox + + for ax in fig.axes: + if hasattr(ax, 'get_subplotspec'): + gs = ax.get_subplotspec().get_gridspec() + gss.add(gs) + bbox = ax.get_tightbbox(fig.canvas.get_renderer()) + bbox = invTransFig(bbox) + bboxes[ax] = bbox + + # we placed everything, but what if there are huge gaps... + for gs in gss: + axs = [ax for ax in fig.axes + if (hasattr(ax, 'get_subplotspec') + and ax.get_subplotspec().get_gridspec() == gs)] + nrows, ncols = gs.get_geometry() + # get widths: + dxs = np.zeros((nrows, ncols)) + dys = np.zeros((nrows, ncols)) + margxs = np.zeros((nrows, ncols)) + + for i in range(nrows): + for j in range(ncols): + for ax in axs: + ss = ax.get_subplotspec() + if (i in ss.rowspan) and (j in ss.colspan): + di = ss.colspan[-1] - ss.colspan[0] + 1 + dj = ss.rowspan[-1] - ss.rowspan[0] + 1 + dxs[i, j] = bboxes[ax].bounds[2] / di + if ss.colspan[-1] < ncols - 1: + dxs[i, j] = dxs[i, j] + w_pad / di + dys[i, j] = bboxes[ax].bounds[3] / dj + if ss.rowspan[-1] < nrows - 1: + dys[i, j] = dys[i, j] + h_pad / dj + orpos = ax.get_position(original=True) + margxs[i, j] = bboxes[ax].x0 - orpos.x0 + + dx = np.max(np.sum(dxs, axis=0)) + dy = np.max(np.sum(dys, axis=1)) + print('dxs', dxs) + print('margxs', margxs) + ddxs = np.max(dxs, axis=0) + dx = np.sum(ddxs) + margx = np.min(margxs, axis=0) + print(ddxs, margx, np.cumsum(ddxs)) + if (dx < dy) and (dx < 0.98): + extra = (1 - dx) / 2 + print('Squish X', extra) + for ax in axs: + # newpos = ax._poslayoutbox.get_rect() + ss = ax.get_subplotspec() + orpos = ax.get_position(original=True) + # acpos = ax.get_position(original=False) + # margx = bboxes[ax].x0 - orpos.x0 + x = extra + for j in range(0, ss.colspan[0]): + x += ddxs[j] + # x = 0.5 + print('x', x, margx[ss.colspan[0]]) + orpos.x1 = x - margx[ss.colspan[0]] + orpos.bounds[2] + orpos.x0 = x - margx[ss.colspan[0]] + # Now set the new position. + # ax.set_position will zero out the layout for + # this axis, allowing users to hard-code the position, + # so this does the same w/o zeroing layout. + ax._set_position(orpos, which='original') diff --git a/lib/matplotlib/gridspec.py b/lib/matplotlib/gridspec.py index eb17dc2127ec..1570eac47716 100644 --- a/lib/matplotlib/gridspec.py +++ b/lib/matplotlib/gridspec.py @@ -196,7 +196,6 @@ def get_grid_positions(self, fig, raw=False): fig_tops, fig_bottoms = (top - cell_hs).reshape((-1, 2)).T fig_lefts, fig_rights = (left + cell_ws).reshape((-1, 2)).T - print('Done this!') return fig_bottoms, fig_tops, fig_lefts, fig_rights def __getitem__(self, key): From 8a990576d7eed77cad16880c0be864303379fa24 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Sun, 19 Apr 2020 22:16:27 -0700 Subject: [PATCH 3/5] Hmm --- lib/matplotlib/_constrained_layout.py | 7 +------ lib/matplotlib/axes/_base.py | 1 + lib/matplotlib/colorbar.py | 5 +++++ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/_constrained_layout.py b/lib/matplotlib/_constrained_layout.py index 1da4e6264479..f887e8549c03 100644 --- a/lib/matplotlib/_constrained_layout.py +++ b/lib/matplotlib/_constrained_layout.py @@ -230,11 +230,6 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad, _squish(fig) - - - - - def _make_ghost_gridspec_slots(fig, gs): """ Check for unoccupied gridspec slots and make ghost axes for these @@ -442,7 +437,6 @@ def _align_spines(fig, gs): ax1._poslayoutbox.width * width0 / (width1*1.8)) - def _arrange_subplotspecs(gs, hspace=0, wspace=0): """Recursively arrange the subplotspec children of the given gridspec.""" sschildren = [] @@ -690,6 +684,7 @@ def _squish(fig, w_pad=0.0, h_pad=0.0): invTransFig = fig.transFigure.inverted().transform_bbox for ax in fig.axes: + print(ax, hasattr(ax, 'get_subplotspec')) if hasattr(ax, 'get_subplotspec'): gs = ax.get_subplotspec().get_gridspec() gss.add(gs) diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 61a0d64cd86f..97f516580846 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -567,6 +567,7 @@ def __init__(self, fig, rect, self._layoutbox = None self._poslayoutbox = None + self._colorbars = [] # a list of colorbars attached to this axes. def __getstate__(self): # The renderer should be re-created by the figure, and then cached at diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 0520ba5cb0ff..16557f59d24b 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -1395,6 +1395,7 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, Returns (cax, kw), the child axes and the reduced kw dictionary to be passed when creating the colorbar instance. """ + locations = ["left", "right", "top", "bottom"] if orientation is not None and location is not None: raise TypeError('position and orientation are mutually exclusive. ' @@ -1498,6 +1499,10 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, ax.set_anchor(parent_anchor) cax = fig.add_axes(pbcb, label="") + if len(parents) == 1: + # single colorbar on an axes... + ax._colorbars += [cax] + # OK, now make a layoutbox for the cb axis. Later, we will use this # to make the colorbar fit nicely. From dc17aebaf32b9f617eadbcb69ad8473ee6c70167 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Tue, 21 Apr 2020 13:47:21 -0700 Subject: [PATCH 4/5] Progress --- lib/matplotlib/_constrained_layout.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/matplotlib/_constrained_layout.py b/lib/matplotlib/_constrained_layout.py index f887e8549c03..7a9b13862e9c 100644 --- a/lib/matplotlib/_constrained_layout.py +++ b/lib/matplotlib/_constrained_layout.py @@ -50,6 +50,7 @@ import numpy as np import matplotlib.cbook as cbook +import matplotlib.transforms as mtransforms import matplotlib._layoutbox as layoutbox _log = logging.getLogger(__name__) @@ -689,6 +690,12 @@ def _squish(fig, w_pad=0.0, h_pad=0.0): gs = ax.get_subplotspec().get_gridspec() gss.add(gs) bbox = ax.get_tightbbox(fig.canvas.get_renderer()) + print('before', bbox) + for cba in ax._colorbars: + print('colorbar!!!', cba) + bboxcb = cba.get_tightbbox(fig.canvas.get_renderer()) + bbox = mtransforms.BboxBase.union([bbox, bboxcb]) + print('after', bbox) bbox = invTransFig(bbox) bboxes[ax] = bbox @@ -748,3 +755,16 @@ def _squish(fig, w_pad=0.0, h_pad=0.0): # this axis, allowing users to hard-code the position, # so this does the same w/o zeroing layout. ax._set_position(orpos, which='original') + # place any colorbars: + for cba in ax._colorbars: + bbox = cba.get_tightbbox(fig.canvas.get_renderer()) + bbox = invTransFig(bbox) + print('thebbox', bbox.extents) + pos = cba.get_position(original=True) + margin = pos.x0 - bbox.x0 + print('margin', margin) + w = pos.width + pos.x0 = x + bboxes[ax].width - bbox.width + margin + pos.x1 = pos.x0 + w + print('the pos', cba, pos.extents) + cba._set_position(pos, which='original') From c7bfb37ae981162556827f335e0d23c2adb44470 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Wed, 22 Apr 2020 17:52:18 -0700 Subject: [PATCH 5/5] FIX --- lib/matplotlib/_constrained_layout.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/_constrained_layout.py b/lib/matplotlib/_constrained_layout.py index 7a9b13862e9c..94c7b9c9c3bf 100644 --- a/lib/matplotlib/_constrained_layout.py +++ b/lib/matplotlib/_constrained_layout.py @@ -680,6 +680,7 @@ def layoutcolorbargridspec(parents, cax, shrink, aspect, location, pad=0.05): return lb, lbpos def _squish(fig, w_pad=0.0, h_pad=0.0): + gss = set() bboxes = {} # need these for packing the layout later... invTransFig = fig.transFigure.inverted().transform_bbox @@ -749,6 +750,7 @@ def _squish(fig, w_pad=0.0, h_pad=0.0): # x = 0.5 print('x', x, margx[ss.colspan[0]]) orpos.x1 = x - margx[ss.colspan[0]] + orpos.bounds[2] + deltax = -orpos.x0 + x - margx[ss.colspan[0]] orpos.x0 = x - margx[ss.colspan[0]] # Now set the new position. # ax.set_position will zero out the layout for @@ -757,14 +759,9 @@ def _squish(fig, w_pad=0.0, h_pad=0.0): ax._set_position(orpos, which='original') # place any colorbars: for cba in ax._colorbars: - bbox = cba.get_tightbbox(fig.canvas.get_renderer()) - bbox = invTransFig(bbox) - print('thebbox', bbox.extents) + #bbox = cba.get_tightbbox(fig.canvas.get_renderer()) + #bbox = invTransFig(bbox) pos = cba.get_position(original=True) - margin = pos.x0 - bbox.x0 - print('margin', margin) - w = pos.width - pos.x0 = x + bboxes[ax].width - bbox.width + margin - pos.x1 = pos.x0 + w - print('the pos', cba, pos.extents) + pos.x0 = pos.x0 + deltax + pos.x1 = pos.x1 + deltax cba._set_position(pos, which='original')