Skip to content

Commit 652a679

Browse files
committed
MNT: make renderer always optional
1 parent c3cf938 commit 652a679

File tree

21 files changed

+161
-115
lines changed

21 files changed

+161
-115
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
No need to specify renderer for get_tightbbox and get_window_extent
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
The ``get_tightbbox`` and `~.Artist.get_window_extent` methods
5+
no longer require the *renderer* kwarg, saving users from having to
6+
querry it from ``fig.canvas.get_renderer``. Currently, all Artists are
7+
aware of their parent figure (``artist.figure``), and if the *renderer*
8+
kwarg is not supplied these methods first check if there is a cached renderer
9+
from a previous draw and use that. If there is no cahched renderer, then
10+
the methods will use ``fig.canvas.get_renderer()`` as a fallback.

lib/matplotlib/_constrained_layout.py

Lines changed: 54 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -11,52 +11,51 @@
1111
layout. Axes manually placed via ``figure.add_axes()`` will not.
1212
1313
See Tutorial: :doc:`/tutorials/intermediate/constrainedlayout_guide`
14-
15-
General idea:
16-
-------------
17-
18-
First, a figure has a gridspec that divides the figure into nrows and ncols,
19-
with heights and widths set by ``height_ratios`` and ``width_ratios``,
20-
often just set to 1 for an equal grid.
21-
22-
Subplotspecs that are derived from this gridspec can contain either a
23-
``SubPanel``, a ``GridSpecFromSubplotSpec``, or an ``Axes``. The ``SubPanel``
24-
and ``GridSpecFromSubplotSpec`` are dealt with recursively and each contain an
25-
analogous layout.
26-
27-
Each ``GridSpec`` has a ``_layoutgrid`` attached to it. The ``_layoutgrid``
28-
has the same logical layout as the ``GridSpec``. Each row of the grid spec
29-
has a top and bottom "margin" and each column has a left and right "margin".
30-
The "inner" height of each row is constrained to be the same (or as modified
31-
by ``height_ratio``), and the "inner" width of each column is
32-
constrained to be the same (as modified by ``width_ratio``), where "inner"
33-
is the width or height of each column/row minus the size of the margins.
34-
35-
Then the size of the margins for each row and column are determined as the
36-
max width of the decorators on each axes that has decorators in that margin.
37-
For instance, a normal axes would have a left margin that includes the
38-
left ticklabels, and the ylabel if it exists. The right margin may include a
39-
colorbar, the bottom margin the xaxis decorations, and the top margin the
40-
title.
41-
42-
With these constraints, the solver then finds appropriate bounds for the
43-
columns and rows. It's possible that the margins take up the whole figure,
44-
in which case the algorithm is not applied and a warning is raised.
45-
46-
See the tutorial doc:`/tutorials/intermediate/constrainedlayout_guide`
47-
for more discussion of the algorithm with examples.
4814
"""
4915

5016
import logging
5117

5218
import numpy as np
5319

5420
from matplotlib import _api, artist as martist
55-
from matplotlib._tight_layout import get_renderer
5621
import matplotlib.transforms as mtransforms
5722
import matplotlib._layoutgrid as mlayoutgrid
5823

5924

25+
# General idea:
26+
# -------------
27+
#
28+
# First, a figure has a gridspec that divides the figure into nrows and ncols,
29+
# with heights and widths set by ``height_ratios`` and ``width_ratios``,
30+
# often just set to 1 for an equal grid.
31+
#
32+
# Subplotspecs that are derived from this gridspec can contain either a
33+
# ``SubPanel``, a ``GridSpecFromSubplotSpec``, or an ``Axes``. The ``SubPanel``
34+
# and ``GridSpecFromSubplotSpec`` are dealt with recursively and each contain an
35+
# analogous layout.
36+
#
37+
# Each ``GridSpec`` has a ``_layoutgrid`` attached to it. The ``_layoutgrid``
38+
# has the same logical layout as the ``GridSpec``. Each row of the grid spec
39+
# has a top and bottom "margin" and each column has a left and right "margin".
40+
# The "inner" height of each row is constrained to be the same (or as modified
41+
# by ``height_ratio``), and the "inner" width of each column is
42+
# constrained to be the same (as modified by ``width_ratio``), where "inner"
43+
# is the width or height of each column/row minus the size of the margins.
44+
#
45+
# Then the size of the margins for each row and column are determined as the
46+
# max width of the decorators on each axes that has decorators in that margin.
47+
# For instance, a normal axes would have a left margin that includes the
48+
# left ticklabels, and the ylabel if it exists. The right margin may include a
49+
# colorbar, the bottom margin the xaxis decorations, and the top margin the
50+
# title.
51+
#
52+
# With these constraints, the solver then finds appropriate bounds for the
53+
# columns and rows. It's possible that the margins take up the whole figure,
54+
# in which case the algorithm is not applied and a warning is raised.
55+
#
56+
# See the tutorial doc:`/tutorials/intermediate/constrainedlayout_guide`
57+
# for more discussion of the algorithm with examples.
58+
6059
_log = logging.getLogger(__name__)
6160

6261

@@ -72,8 +71,6 @@ def do_constrained_layout(fig, h_pad, w_pad,
7271
fig : Figure
7372
``Figure`` instance to do the layout in.
7473
75-
renderer : Renderer
76-
Renderer to use.
7774
7875
h_pad, w_pad : float
7976
Padding around the axes elements in figure-normalized units.
@@ -94,7 +91,6 @@ def do_constrained_layout(fig, h_pad, w_pad,
9491
layoutgrid : private debugging structure
9592
"""
9693

97-
renderer = get_renderer(fig)
9894
# make layoutgrid tree...
9995
layoutgrids = make_layoutgrids(fig, None, rect=rect)
10096
if not layoutgrids['hasgrids']:
@@ -111,9 +107,9 @@ def do_constrained_layout(fig, h_pad, w_pad,
111107

112108
# make margins for all the axes and subfigures in the
113109
# figure. Add margins for colorbars...
114-
make_layout_margins(layoutgrids, fig, renderer, h_pad=h_pad,
110+
make_layout_margins(layoutgrids, fig, h_pad=h_pad,
115111
w_pad=w_pad, hspace=hspace, wspace=wspace)
116-
make_margin_suptitles(layoutgrids, fig, renderer, h_pad=h_pad,
112+
make_margin_suptitles(layoutgrids, fig, h_pad=h_pad,
117113
w_pad=w_pad)
118114

119115
# if a layout is such that a columns (or rows) margin has no
@@ -125,7 +121,7 @@ def do_constrained_layout(fig, h_pad, w_pad,
125121
layoutgrids[fig].update_variables()
126122

127123
if check_no_collapsed_axes(layoutgrids, fig):
128-
reposition_axes(layoutgrids, fig, renderer, h_pad=h_pad,
124+
reposition_axes(layoutgrids, fig, h_pad=h_pad,
129125
w_pad=w_pad, hspace=hspace, wspace=wspace)
130126
else:
131127
_api.warn_external('constrained_layout not applied because '
@@ -286,7 +282,7 @@ def get_margin_from_padding(obj, *, w_pad=0, h_pad=0,
286282
return margin
287283

288284

289-
def make_layout_margins(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0,
285+
def make_layout_margins(layoutgrids, fig, *, w_pad=0, h_pad=0,
290286
hspace=0, wspace=0):
291287
"""
292288
For each axes, make a margin between the *pos* layoutbox and the
@@ -297,7 +293,7 @@ def make_layout_margins(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0,
297293
"""
298294
for sfig in fig.subfigs: # recursively make child panel margins
299295
ss = sfig._subplotspec
300-
make_layout_margins(layoutgrids, sfig, renderer,
296+
make_layout_margins(layoutgrids, sfig,
301297
w_pad=w_pad, h_pad=h_pad,
302298
hspace=hspace, wspace=wspace)
303299

@@ -317,7 +313,7 @@ def make_layout_margins(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0,
317313

318314
margin = get_margin_from_padding(ax, w_pad=w_pad, h_pad=h_pad,
319315
hspace=hspace, wspace=wspace)
320-
pos, bbox = get_pos_and_bbox(ax, renderer)
316+
pos, bbox = get_pos_and_bbox(ax)
321317
# the margin is the distance between the bounding box of the axes
322318
# and its position (plus the padding from above)
323319
margin['left'] += pos.x0 - bbox.x0
@@ -334,7 +330,7 @@ def make_layout_margins(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0,
334330
# colorbars can be child of more than one subplot spec:
335331
cbp_rspan, cbp_cspan = get_cb_parent_spans(cbax)
336332
loc = cbax._colorbar_info['location']
337-
cbpos, cbbbox = get_pos_and_bbox(cbax, renderer)
333+
cbpos, cbbbox = get_pos_and_bbox(cbax)
338334
if loc == 'right':
339335
if cbp_cspan.stop == ss.colspan.stop:
340336
# only increase if the colorbar is on the right edge
@@ -370,7 +366,7 @@ def make_layout_margins(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0,
370366
layoutgrids[gs].edit_outer_margin_mins(margin, ss)
371367

372368

373-
def make_margin_suptitles(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0):
369+
def make_margin_suptitles(layoutgrids, fig, *, w_pad=0, h_pad=0):
374370
# Figure out how large the suptitle is and make the
375371
# top level figure margin larger.
376372

@@ -383,29 +379,29 @@ def make_margin_suptitles(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0):
383379
w_pad_local = padbox.width
384380

385381
for sfig in fig.subfigs:
386-
make_margin_suptitles(layoutgrids, sfig, renderer,
382+
make_margin_suptitles(layoutgrids, sfig,
387383
w_pad=w_pad, h_pad=h_pad)
388384

389385
if fig._suptitle is not None and fig._suptitle.get_in_layout():
390386
p = fig._suptitle.get_position()
391387
if getattr(fig._suptitle, '_autopos', False):
392388
fig._suptitle.set_position((p[0], 1 - h_pad_local))
393-
bbox = inv_trans_fig(fig._suptitle.get_tightbbox(renderer))
389+
bbox = inv_trans_fig(fig._suptitle.get_tightbbox())
394390
layoutgrids[fig].edit_margin_min('top', bbox.height + 2 * h_pad)
395391

396392
if fig._supxlabel is not None and fig._supxlabel.get_in_layout():
397393
p = fig._supxlabel.get_position()
398394
if getattr(fig._supxlabel, '_autopos', False):
399395
fig._supxlabel.set_position((p[0], h_pad_local))
400-
bbox = inv_trans_fig(fig._supxlabel.get_tightbbox(renderer))
396+
bbox = inv_trans_fig(fig._supxlabel.get_tightbbox())
401397
layoutgrids[fig].edit_margin_min('bottom',
402398
bbox.height + 2 * h_pad)
403399

404400
if fig._supylabel is not None and fig._supylabel.get_in_layout():
405401
p = fig._supylabel.get_position()
406402
if getattr(fig._supylabel, '_autopos', False):
407403
fig._supylabel.set_position((w_pad_local, p[1]))
408-
bbox = inv_trans_fig(fig._supylabel.get_tightbbox(renderer))
404+
bbox = inv_trans_fig(fig._supylabel.get_tightbbox())
409405
layoutgrids[fig].edit_margin_min('left', bbox.width + 2 * w_pad)
410406

411407

@@ -526,14 +522,14 @@ def get_cb_parent_spans(cbax):
526522
return rowspan, colspan
527523

528524

529-
def get_pos_and_bbox(ax, renderer):
525+
def get_pos_and_bbox(ax):
530526
"""
531527
Get the position and the bbox for the axes.
532528
533529
Parameters
534530
----------
535531
ax
536-
renderer
532+
537533
538534
Returns
539535
-------
@@ -546,15 +542,15 @@ def get_pos_and_bbox(ax, renderer):
546542
pos = ax.get_position(original=True)
547543
# pos is in panel co-ords, but we need in figure for the layout
548544
pos = pos.transformed(fig.transSubfigure - fig.transFigure)
549-
tightbbox = martist._get_tightbbox_for_layout_only(ax, renderer)
545+
tightbbox = martist._get_tightbbox_for_layout_only(ax)
550546
if tightbbox is None:
551547
bbox = pos
552548
else:
553549
bbox = tightbbox.transformed(fig.transFigure.inverted())
554550
return pos, bbox
555551

556552

557-
def reposition_axes(layoutgrids, fig, renderer, *,
553+
def reposition_axes(layoutgrids, fig, *,
558554
w_pad=0, h_pad=0, hspace=0, wspace=0):
559555
"""
560556
Reposition all the axes based on the new inner bounding box.
@@ -564,7 +560,7 @@ def reposition_axes(layoutgrids, fig, renderer, *,
564560
bbox = layoutgrids[sfig].get_outer_bbox()
565561
sfig._redo_transform_rel_fig(
566562
bbox=bbox.transformed(trans_fig_to_subfig))
567-
reposition_axes(layoutgrids, sfig, renderer,
563+
reposition_axes(layoutgrids, sfig,
568564
w_pad=w_pad, h_pad=h_pad,
569565
wspace=wspace, hspace=hspace)
570566

@@ -592,11 +588,11 @@ def reposition_axes(layoutgrids, fig, renderer, *,
592588
offset = {'left': 0, 'right': 0, 'bottom': 0, 'top': 0}
593589
for nn, cbax in enumerate(ax._colorbars[::-1]):
594590
if ax == cbax._colorbar_info['parents'][0]:
595-
reposition_colorbar(layoutgrids, cbax, renderer,
591+
reposition_colorbar(layoutgrids, cbax,
596592
offset=offset)
597593

598594

599-
def reposition_colorbar(layoutgrids, cbax, renderer, *, offset=None):
595+
def reposition_colorbar(layoutgrids, cbax, *, offset=None):
600596
"""
601597
Place the colorbar in its new place.
602598
@@ -605,7 +601,6 @@ def reposition_colorbar(layoutgrids, cbax, renderer, *, offset=None):
605601
cbax : Axes
606602
Axes for the colorbar
607603
608-
renderer :
609604
w_pad, h_pad : float
610605
width and height padding (in fraction of figure)
611606
hspace, wspace : float
@@ -632,7 +627,7 @@ def reposition_colorbar(layoutgrids, cbax, renderer, *, offset=None):
632627
aspect = cbax._colorbar_info['aspect']
633628
shrink = cbax._colorbar_info['shrink']
634629

635-
cbpos, cbbbox = get_pos_and_bbox(cbax, renderer)
630+
cbpos, cbbbox = get_pos_and_bbox(cbax)
636631

637632
# Colorbar gets put at extreme edge of outer bbox of the subplotspec
638633
# It needs to be moved in by: 1) a pad 2) its "margin" 3) by

lib/matplotlib/_tight_layout.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -199,15 +199,7 @@ def auto_adjust_subplotpars(
199199

200200

201201
def get_renderer(fig):
202-
if fig._cachedRenderer:
203-
return fig._cachedRenderer
204-
else:
205-
canvas = fig.canvas
206-
if canvas and hasattr(canvas, "get_renderer"):
207-
return canvas.get_renderer()
208-
else:
209-
from . import backend_bases
210-
return backend_bases._get_renderer(fig)
202+
fig._get_cached_renderer()
211203

212204

213205
def get_subplotspec_list(axes_list, grid_spec=None):
@@ -244,7 +236,7 @@ def get_subplotspec_list(axes_list, grid_spec=None):
244236
return subplotspec_list
245237

246238

247-
def get_tight_layout_figure(fig, axes_list, subplotspec_list, renderer,
239+
def get_tight_layout_figure(fig, axes_list, subplotspec_list, renderer=None,
248240
pad=1.08, h_pad=None, w_pad=None, rect=None):
249241
"""
250242
Return subplot parameters for tight-layouted-figure with specified padding.

lib/matplotlib/artist.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ def stale(self, val):
298298
if val and self.stale_callback is not None:
299299
self.stale_callback(self, val)
300300

301-
def get_window_extent(self, renderer):
301+
def get_window_extent(self, renderer=None):
302302
"""
303303
Get the artist's bounding box in display space.
304304
@@ -318,7 +318,7 @@ def get_window_extent(self, renderer):
318318
"""
319319
return Bbox([[0, 0], [0, 0]])
320320

321-
def get_tightbbox(self, renderer):
321+
def get_tightbbox(self, renderer=None):
322322
"""
323323
Like `.Artist.get_window_extent`, but includes any clipping.
324324

lib/matplotlib/axes/_base.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4433,7 +4433,7 @@ def get_default_bbox_extra_artists(self):
44334433
return [a for a in artists if a.get_visible() and a.get_in_layout()
44344434
and (isinstance(a, noclip) or not a._fully_clipped_to_axes())]
44354435

4436-
def get_tightbbox(self, renderer, call_axes_locator=True,
4436+
def get_tightbbox(self, renderer=None, call_axes_locator=True,
44374437
bbox_extra_artists=None, *, for_layout_only=False):
44384438
"""
44394439
Return the tight bounding box of the Axes, including axis and their
@@ -4477,6 +4477,8 @@ def get_tightbbox(self, renderer, call_axes_locator=True,
44774477
"""
44784478

44794479
bb = []
4480+
if renderer is None:
4481+
renderer = self.figure._get_cached_renderer()
44804482

44814483
if not self.get_visible():
44824484
return None

lib/matplotlib/axis.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,14 +1203,16 @@ def _update_ticks(self):
12031203

12041204
return ticks_to_draw
12051205

1206-
def _get_ticklabel_bboxes(self, ticks, renderer):
1206+
def _get_ticklabel_bboxes(self, ticks, renderer=None):
12071207
"""Return lists of bboxes for ticks' label1's and label2's."""
1208+
if renderer is None:
1209+
renderer = self.figure._get_cached_renderer()
12081210
return ([tick.label1.get_window_extent(renderer)
12091211
for tick in ticks if tick.label1.get_visible()],
12101212
[tick.label2.get_window_extent(renderer)
12111213
for tick in ticks if tick.label2.get_visible()])
12121214

1213-
def get_tightbbox(self, renderer, *, for_layout_only=False):
1215+
def get_tightbbox(self, renderer=None, *, for_layout_only=False):
12141216
"""
12151217
Return a bounding box that encloses the axis. It only accounts
12161218
tick labels, axis label, and offsetText.
@@ -1222,7 +1224,8 @@ def get_tightbbox(self, renderer, *, for_layout_only=False):
12221224
"""
12231225
if not self.get_visible():
12241226
return
1225-
1227+
if renderer is None:
1228+
renderer = self.figure._get_cached_renderer()
12261229
ticks_to_draw = self._update_ticks()
12271230

12281231
self._update_label_position(renderer)

lib/matplotlib/collections.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ def get_datalim(self, transData):
303303
return bbox
304304
return transforms.Bbox.null()
305305

306-
def get_window_extent(self, renderer):
306+
def get_window_extent(self, renderer=None):
307307
# TODO: check to ensure that this does not fail for
308308
# cases other than scatter plot legend
309309
return self.get_datalim(transforms.IdentityTransform())

0 commit comments

Comments
 (0)