Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 11739ad

Browse files
authored
Merge pull request #19968 from jklymak/enh-draw-no-output
ENH: draw no output
2 parents c89cf88 + 7e05975 commit 11739ad

File tree

9 files changed

+48
-30
lines changed

9 files changed

+48
-30
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Figure now has draw_no_output method
2+
------------------------------------
3+
4+
Rarely, the user will want to trigger a draw without making output to
5+
either the screen or a file. This is useful for determining the final
6+
position of artists on the figure that require a draw, like text artists.
7+
This could be accomplished via ``fig.canvas.draw()`` but has side effects,
8+
sometimes requires an open file, and is documented on an object most users
9+
do not need to access. The `.Figure.draw_no_output` is provided to trigger
10+
a draw without pushing to the final output, and with fewer side effects.

lib/matplotlib/backend_bases.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,9 +1584,9 @@ def _draw(renderer): raise Done(renderer)
15841584

15851585

15861586
def _no_output_draw(figure):
1587-
renderer = _get_renderer(figure)
1588-
with renderer._draw_disabled():
1589-
figure.draw(renderer)
1587+
# _no_output_draw was promoted to the figure level, but
1588+
# keep this here in case someone was calling it...
1589+
figure.draw_no_output()
15901590

15911591

15921592
def _is_non_interactive_terminal_ipython(ip):

lib/matplotlib/backends/backend_pdf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from matplotlib._pylab_helpers import Gcf
3030
from matplotlib.backend_bases import (
3131
_Backend, _check_savefig_extra_args, FigureCanvasBase, FigureManagerBase,
32-
GraphicsContextBase, RendererBase, _no_output_draw)
32+
GraphicsContextBase, RendererBase)
3333
from matplotlib.backends.backend_mixed import MixedModeRenderer
3434
from matplotlib.figure import Figure
3535
from matplotlib.font_manager import findfont, get_font
@@ -2718,7 +2718,7 @@ def print_pdf(self, filename, *,
27182718
file.close()
27192719

27202720
def draw(self):
2721-
_no_output_draw(self.figure)
2721+
self.figure.draw_no_output()
27222722
return super().draw()
27232723

27242724

lib/matplotlib/backends/backend_pgf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from matplotlib import _api, cbook, font_manager as fm
2020
from matplotlib.backend_bases import (
2121
_Backend, _check_savefig_extra_args, FigureCanvasBase, FigureManagerBase,
22-
GraphicsContextBase, RendererBase, _no_output_draw
22+
GraphicsContextBase, RendererBase
2323
)
2424
from matplotlib.backends.backend_mixed import MixedModeRenderer
2525
from matplotlib.backends.backend_pdf import (
@@ -889,7 +889,7 @@ def get_renderer(self):
889889
return RendererPgf(self.figure, None)
890890

891891
def draw(self):
892-
_no_output_draw(self.figure)
892+
self.figure.draw_no_output()
893893
return super().draw()
894894

895895

lib/matplotlib/backends/backend_ps.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from matplotlib.afm import AFM
2424
from matplotlib.backend_bases import (
2525
_Backend, _check_savefig_extra_args, FigureCanvasBase, FigureManagerBase,
26-
GraphicsContextBase, RendererBase, _no_output_draw)
26+
GraphicsContextBase, RendererBase)
2727
from matplotlib.cbook import is_writable_file_like, file_requires_unicode
2828
from matplotlib.font_manager import get_font
2929
from matplotlib.ft2font import LOAD_NO_HINTING, LOAD_NO_SCALE
@@ -1112,7 +1112,7 @@ def _print_figure_tex(
11121112
_move_path_to_path_or_stream(tmpfile, outfile)
11131113

11141114
def draw(self):
1115-
_no_output_draw(self.figure)
1115+
self.figure.draw_no_output()
11161116
return super().draw()
11171117

11181118

lib/matplotlib/backends/backend_svg.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from matplotlib import _api, cbook
1818
from matplotlib.backend_bases import (
1919
_Backend, _check_savefig_extra_args, FigureCanvasBase, FigureManagerBase,
20-
RendererBase, _no_output_draw)
20+
RendererBase)
2121
from matplotlib.backends.backend_mixed import MixedModeRenderer
2222
from matplotlib.colors import rgb2hex
2323
from matplotlib.dates import UTC
@@ -1343,7 +1343,7 @@ def get_default_filetype(self):
13431343
return 'svg'
13441344

13451345
def draw(self):
1346-
_no_output_draw(self.figure)
1346+
self.figure.draw_no_output()
13471347
return super().draw()
13481348

13491349

lib/matplotlib/figure.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from matplotlib.artist import (
2727
Artist, allow_rasterization, _finalize_rasterization)
2828
from matplotlib.backend_bases import (
29-
FigureCanvasBase, NonGuiException, MouseButton)
29+
FigureCanvasBase, NonGuiException, MouseButton, _get_renderer)
3030
import matplotlib._api as _api
3131
import matplotlib.cbook as cbook
3232
import matplotlib.colorbar as cbar
@@ -2776,6 +2776,15 @@ def draw(self, renderer):
27762776

27772777
self.canvas.draw_event(renderer)
27782778

2779+
def draw_no_output(self):
2780+
"""
2781+
Draw the figure with no output. Useful to get the final size of
2782+
artists that require a draw before their size is known (e.g. text).
2783+
"""
2784+
renderer = _get_renderer(self)
2785+
with renderer._draw_disabled():
2786+
self.draw(renderer)
2787+
27792788
def draw_artist(self, a):
27802789
"""
27812790
Draw `.Artist` *a* only.
@@ -3052,7 +3061,6 @@ def execute_constrained_layout(self, renderer=None):
30523061
"""
30533062

30543063
from matplotlib._constrained_layout import do_constrained_layout
3055-
from matplotlib.tight_layout import get_renderer
30563064

30573065
_log.debug('Executing constrainedlayout')
30583066
if self._layoutgrid is None:
@@ -3070,7 +3078,7 @@ def execute_constrained_layout(self, renderer=None):
30703078
w_pad = w_pad / width
30713079
h_pad = h_pad / height
30723080
if renderer is None:
3073-
renderer = get_renderer(fig)
3081+
renderer = _get_renderer(fig)
30743082
do_constrained_layout(fig, renderer, h_pad, w_pad, hspace, wspace)
30753083

30763084
def tight_layout(self, *, pad=1.08, h_pad=None, w_pad=None, rect=None):
@@ -3100,15 +3108,15 @@ def tight_layout(self, *, pad=1.08, h_pad=None, w_pad=None, rect=None):
31003108
"""
31013109

31023110
from .tight_layout import (
3103-
get_renderer, get_subplotspec_list, get_tight_layout_figure)
3111+
get_subplotspec_list, get_tight_layout_figure)
31043112
from contextlib import suppress
31053113
subplotspec_list = get_subplotspec_list(self.axes)
31063114
if None in subplotspec_list:
31073115
_api.warn_external("This figure includes Axes that are not "
31083116
"compatible with tight_layout, so results "
31093117
"might be incorrect.")
31103118

3111-
renderer = get_renderer(self)
3119+
renderer = _get_renderer(self)
31123120
ctx = (renderer._draw_disabled()
31133121
if hasattr(renderer, '_draw_disabled')
31143122
else suppress())

lib/matplotlib/tests/test_constrainedlayout.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def test_constrained_layout7():
134134
for gs in gsl:
135135
fig.add_subplot(gs)
136136
# need to trigger a draw to get warning
137-
fig.draw(fig.canvas.get_renderer())
137+
fig.draw_no_output()
138138

139139

140140
@image_comparison(['constrained_layout8.png'])
@@ -327,7 +327,7 @@ def test_constrained_layout18():
327327
ax2 = ax.twinx()
328328
example_plot(ax)
329329
example_plot(ax2, fontsize=24)
330-
fig.canvas.draw()
330+
fig.draw_no_output()
331331
assert all(ax.get_position().extents == ax2.get_position().extents)
332332

333333

@@ -339,7 +339,7 @@ def test_constrained_layout19():
339339
example_plot(ax2, fontsize=24)
340340
ax2.set_title('')
341341
ax.set_title('')
342-
fig.canvas.draw()
342+
fig.draw_no_output()
343343
assert all(ax.get_position().extents == ax2.get_position().extents)
344344

345345

@@ -359,11 +359,11 @@ def test_constrained_layout21():
359359
fig, ax = plt.subplots(constrained_layout=True)
360360

361361
fig.suptitle("Suptitle0")
362-
fig.canvas.draw()
362+
fig.draw_no_output()
363363
extents0 = np.copy(ax.get_position().extents)
364364

365365
fig.suptitle("Suptitle1")
366-
fig.canvas.draw()
366+
fig.draw_no_output()
367367
extents1 = np.copy(ax.get_position().extents)
368368

369369
np.testing.assert_allclose(extents0, extents1)
@@ -373,11 +373,11 @@ def test_constrained_layout22():
373373
"""#11035: suptitle should not be include in CL if manually positioned"""
374374
fig, ax = plt.subplots(constrained_layout=True)
375375

376-
fig.canvas.draw()
376+
fig.draw_no_output()
377377
extents0 = np.copy(ax.get_position().extents)
378378

379379
fig.suptitle("Suptitle", y=0.5)
380-
fig.canvas.draw()
380+
fig.draw_no_output()
381381
extents1 = np.copy(ax.get_position().extents)
382382

383383
np.testing.assert_allclose(extents0, extents1)
@@ -425,7 +425,7 @@ def test_hidden_axes():
425425
# (as does a gridspec slot that is empty)
426426
fig, axs = plt.subplots(2, 2, constrained_layout=True)
427427
axs[0, 1].set_visible(False)
428-
fig.canvas.draw()
428+
fig.draw_no_output()
429429
extents1 = np.copy(axs[0, 0].get_position().extents)
430430

431431
np.testing.assert_allclose(
@@ -451,7 +451,7 @@ def test_colorbar_align():
451451
fig.set_constrained_layout_pads(w_pad=4 / 72, h_pad=4 / 72, hspace=0.1,
452452
wspace=0.1)
453453

454-
fig.canvas.draw()
454+
fig.draw_no_output()
455455
if location in ['left', 'right']:
456456
np.testing.assert_allclose(cbs[0].ax.get_position().x0,
457457
cbs[2].ax.get_position().x0)
@@ -493,15 +493,15 @@ def test_colorbars_no_overlapH():
493493
def test_manually_set_position():
494494
fig, axs = plt.subplots(1, 2, constrained_layout=True)
495495
axs[0].set_position([0.2, 0.2, 0.3, 0.3])
496-
fig.canvas.draw()
496+
fig.draw_no_output()
497497
pp = axs[0].get_position()
498498
np.testing.assert_allclose(pp, [[0.2, 0.2], [0.5, 0.5]])
499499

500500
fig, axs = plt.subplots(1, 2, constrained_layout=True)
501501
axs[0].set_position([0.2, 0.2, 0.3, 0.3])
502502
pc = axs[0].pcolormesh(np.random.rand(20, 20))
503503
fig.colorbar(pc, ax=axs[0])
504-
fig.canvas.draw()
504+
fig.draw_no_output()
505505
pp = axs[0].get_position()
506506
np.testing.assert_allclose(pp, [[0.2, 0.2], [0.44, 0.5]])
507507

@@ -546,7 +546,7 @@ def test_align_labels():
546546

547547
fig.align_ylabels(axs=(ax3, ax1, ax2))
548548

549-
fig.canvas.draw()
549+
fig.draw_no_output()
550550
after_align = [ax1.yaxis.label.get_window_extent(),
551551
ax2.yaxis.label.get_window_extent(),
552552
ax3.yaxis.label.get_window_extent()]

lib/matplotlib/tests/test_figure.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,11 +415,11 @@ def test_autofmt_xdate(which):
415415
@pytest.mark.style('default')
416416
def test_change_dpi():
417417
fig = plt.figure(figsize=(4, 4))
418-
fig.canvas.draw()
418+
fig.draw_no_output()
419419
assert fig.canvas.renderer.height == 400
420420
assert fig.canvas.renderer.width == 400
421421
fig.dpi = 50
422-
fig.canvas.draw()
422+
fig.draw_no_output()
423423
assert fig.canvas.renderer.height == 200
424424
assert fig.canvas.renderer.width == 200
425425

0 commit comments

Comments
 (0)