From 3b2484c6f99b3610d6c4820053cab1e4f295a6f3 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Tue, 31 Aug 2021 15:33:12 +0200 Subject: [PATCH] Backport PR #20931: API: rename draw_no_output to draw_without_rendering --- .../next_whats_new/fig_draw_no_output.rst | 10 ------ .../fig_draw_without_rendering.rst | 12 +++++++ lib/matplotlib/backend_bases.py | 2 +- lib/matplotlib/backends/backend_pdf.py | 2 +- lib/matplotlib/backends/backend_pgf.py | 2 +- lib/matplotlib/backends/backend_ps.py | 2 +- lib/matplotlib/backends/backend_svg.py | 2 +- lib/matplotlib/figure.py | 2 +- lib/matplotlib/tests/test_axes.py | 2 +- lib/matplotlib/tests/test_colorbar.py | 6 ++-- .../tests/test_constrainedlayout.py | 32 +++++++++---------- lib/matplotlib/tests/test_dates.py | 4 +-- lib/matplotlib/tests/test_figure.py | 8 ++--- lib/matplotlib/tests/test_mathtext.py | 4 +-- lib/matplotlib/tests/test_units.py | 12 +++---- 15 files changed, 52 insertions(+), 50 deletions(-) delete mode 100644 doc/users/next_whats_new/fig_draw_no_output.rst create mode 100644 doc/users/next_whats_new/fig_draw_without_rendering.rst diff --git a/doc/users/next_whats_new/fig_draw_no_output.rst b/doc/users/next_whats_new/fig_draw_no_output.rst deleted file mode 100644 index 293c6590b8c9..000000000000 --- a/doc/users/next_whats_new/fig_draw_no_output.rst +++ /dev/null @@ -1,10 +0,0 @@ -Figure now has draw_no_output method ------------------------------------- - -Rarely, the user will want to trigger a draw without making output to -either the screen or a file. This is useful for determining the final -position of artists on the figure that require a draw, like text artists. -This could be accomplished via ``fig.canvas.draw()`` but has side effects, -sometimes requires an open file, and is documented on an object most users -do not need to access. The `.Figure.draw_no_output` is provided to trigger -a draw without pushing to the final output, and with fewer side effects. \ No newline at end of file diff --git a/doc/users/next_whats_new/fig_draw_without_rendering.rst b/doc/users/next_whats_new/fig_draw_without_rendering.rst new file mode 100644 index 000000000000..8b9e3147bf07 --- /dev/null +++ b/doc/users/next_whats_new/fig_draw_without_rendering.rst @@ -0,0 +1,12 @@ +Figure now has ``draw_without_rendering`` method +------------------------------------------------ + +Some aspects of a figure are only determined at draw-time, such as the exact +position of text artists or deferred computation like automatic data limits. +If you need these values, you can use ``figure.canvas.draw()`` to force a full +draw. However, this has side effects, sometimes requires an open file, and is +doing more work than is needed. + +The new `.Figure.draw_without_rendering` method runs all the updates that +``draw()`` does, but skips rendering the figure. It's thus more efficient if you +need the updated values to configure further aspects of the figure. diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 00e99c9f073e..70f09d543c39 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -1570,7 +1570,7 @@ def _draw(renderer): raise Done(renderer) def _no_output_draw(figure): # _no_output_draw was promoted to the figure level, but # keep this here in case someone was calling it... - figure.draw_no_output() + figure.draw_without_rendering() def _is_non_interactive_terminal_ipython(ip): diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index 9980d49af85b..9ca791db0c5a 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -2793,7 +2793,7 @@ def print_pdf(self, filename, *, file.close() def draw(self): - self.figure.draw_no_output() + self.figure.draw_without_rendering() return super().draw() diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index 3f1cb7b172eb..749da559662c 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -883,7 +883,7 @@ def get_renderer(self): return RendererPgf(self.figure, None) def draw(self): - self.figure.draw_no_output() + self.figure.draw_without_rendering() return super().draw() diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index f13e114a815b..93d0705ae363 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -1119,7 +1119,7 @@ def _print_figure_tex( _move_path_to_path_or_stream(tmpfile, outfile) def draw(self): - self.figure.draw_no_output() + self.figure.draw_without_rendering() return super().draw() diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 904cca7bf313..e4de85905ca7 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -1343,7 +1343,7 @@ def get_default_filetype(self): return 'svg' def draw(self): - self.figure.draw_no_output() + self.figure.draw_without_rendering() return super().draw() diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index abe8ec694922..dbd879521f25 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -2808,7 +2808,7 @@ def draw(self, renderer): self.canvas.draw_event(renderer) - def draw_no_output(self): + def draw_without_rendering(self): """ Draw the figure with no output. Useful to get the final size of artists that require a draw before their size is known (e.g. text). diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 509910bdeec1..32b0c202478b 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -4793,7 +4793,7 @@ def test_reset_ticks(fig_test, fig_ref): labelsize=14, labelcolor='C1', labelrotation=45, grid_color='C2', grid_alpha=0.8, grid_linewidth=3, grid_linestyle='--') - fig.draw_no_output() + fig.draw_without_rendering() # After we've changed any setting on ticks, reset_ticks will mean # re-creating them from scratch. This *should* appear the same as not diff --git a/lib/matplotlib/tests/test_colorbar.py b/lib/matplotlib/tests/test_colorbar.py index 055c4acb7642..5f19a0aaf20a 100644 --- a/lib/matplotlib/tests/test_colorbar.py +++ b/lib/matplotlib/tests/test_colorbar.py @@ -613,7 +613,7 @@ def test_mappable_2d_alpha(): # the original alpha array assert cb.alpha is None assert pc.get_alpha() is x - fig.draw_no_output() + fig.draw_without_rendering() def test_colorbar_label(): @@ -766,7 +766,7 @@ def test_inset_colorbar_layout(): cax = ax.inset_axes([1.02, 0.1, 0.03, 0.8]) cb = fig.colorbar(pc, cax=cax) - fig.draw_no_output() + fig.draw_without_rendering() # make sure this is in the figure. In the colorbar swapping # it was being dropped from the list of children... np.testing.assert_allclose(cb.ax.get_position().bounds, @@ -806,7 +806,7 @@ def test_aspects(): pc = ax[mm, nn].pcolormesh(np.arange(100).reshape(10, 10)) cb[nn][mm] = fig.colorbar(pc, ax=ax[mm, nn], orientation=orient, aspect=aspect, extend=extend) - fig.draw_no_output() + fig.draw_without_rendering() # check the extends are right ratio: np.testing.assert_almost_equal(cb[0][1].ax.get_position().height, cb[0][0].ax.get_position().height * 0.9, diff --git a/lib/matplotlib/tests/test_constrainedlayout.py b/lib/matplotlib/tests/test_constrainedlayout.py index 007fac6ec1f9..a8222a73d5ee 100644 --- a/lib/matplotlib/tests/test_constrainedlayout.py +++ b/lib/matplotlib/tests/test_constrainedlayout.py @@ -128,7 +128,7 @@ def test_constrained_layout7(): for gs in gsl: fig.add_subplot(gs) # need to trigger a draw to get warning - fig.draw_no_output() + fig.draw_without_rendering() @image_comparison(['constrained_layout8.png']) @@ -309,7 +309,7 @@ def test_constrained_layout18(): ax2 = ax.twinx() example_plot(ax) example_plot(ax2, fontsize=24) - fig.draw_no_output() + fig.draw_without_rendering() assert all(ax.get_position().extents == ax2.get_position().extents) @@ -321,7 +321,7 @@ def test_constrained_layout19(): example_plot(ax2, fontsize=24) ax2.set_title('') ax.set_title('') - fig.draw_no_output() + fig.draw_without_rendering() assert all(ax.get_position().extents == ax2.get_position().extents) @@ -341,11 +341,11 @@ def test_constrained_layout21(): fig, ax = plt.subplots(constrained_layout=True) fig.suptitle("Suptitle0") - fig.draw_no_output() + fig.draw_without_rendering() extents0 = np.copy(ax.get_position().extents) fig.suptitle("Suptitle1") - fig.draw_no_output() + fig.draw_without_rendering() extents1 = np.copy(ax.get_position().extents) np.testing.assert_allclose(extents0, extents1) @@ -355,11 +355,11 @@ def test_constrained_layout22(): """#11035: suptitle should not be include in CL if manually positioned""" fig, ax = plt.subplots(constrained_layout=True) - fig.draw_no_output() + fig.draw_without_rendering() extents0 = np.copy(ax.get_position().extents) fig.suptitle("Suptitle", y=0.5) - fig.draw_no_output() + fig.draw_without_rendering() extents1 = np.copy(ax.get_position().extents) np.testing.assert_allclose(extents0, extents1) @@ -407,7 +407,7 @@ def test_hidden_axes(): # (as does a gridspec slot that is empty) fig, axs = plt.subplots(2, 2, constrained_layout=True) axs[0, 1].set_visible(False) - fig.draw_no_output() + fig.draw_without_rendering() extents1 = np.copy(axs[0, 0].get_position().extents) np.testing.assert_allclose( @@ -433,7 +433,7 @@ def test_colorbar_align(): fig.set_constrained_layout_pads(w_pad=4 / 72, h_pad=4 / 72, hspace=0.1, wspace=0.1) - fig.draw_no_output() + fig.draw_without_rendering() if location in ['left', 'right']: np.testing.assert_allclose(cbs[0].ax.get_position().x0, cbs[2].ax.get_position().x0) @@ -475,7 +475,7 @@ def test_colorbars_no_overlapH(): def test_manually_set_position(): fig, axs = plt.subplots(1, 2, constrained_layout=True) axs[0].set_position([0.2, 0.2, 0.3, 0.3]) - fig.draw_no_output() + fig.draw_without_rendering() pp = axs[0].get_position() np.testing.assert_allclose(pp, [[0.2, 0.2], [0.5, 0.5]]) @@ -483,7 +483,7 @@ def test_manually_set_position(): axs[0].set_position([0.2, 0.2, 0.3, 0.3]) pc = axs[0].pcolormesh(np.random.rand(20, 20)) fig.colorbar(pc, ax=axs[0]) - fig.draw_no_output() + fig.draw_without_rendering() pp = axs[0].get_position() np.testing.assert_allclose(pp, [[0.2, 0.2], [0.44, 0.5]]) @@ -528,7 +528,7 @@ def test_align_labels(): fig.align_ylabels(axs=(ax3, ax1, ax2)) - fig.draw_no_output() + fig.draw_without_rendering() after_align = [ax1.yaxis.label.get_window_extent(), ax2.yaxis.label.get_window_extent(), ax3.yaxis.label.get_window_extent()] @@ -541,22 +541,22 @@ def test_align_labels(): def test_suplabels(): fig, ax = plt.subplots(constrained_layout=True) - fig.draw_no_output() + fig.draw_without_rendering() pos0 = ax.get_tightbbox(fig.canvas.get_renderer()) fig.supxlabel('Boo') fig.supylabel('Booy') - fig.draw_no_output() + fig.draw_without_rendering() pos = ax.get_tightbbox(fig.canvas.get_renderer()) assert pos.y0 > pos0.y0 + 10.0 assert pos.x0 > pos0.x0 + 10.0 fig, ax = plt.subplots(constrained_layout=True) - fig.draw_no_output() + fig.draw_without_rendering() pos0 = ax.get_tightbbox(fig.canvas.get_renderer()) # check that specifying x (y) doesn't ruin the layout fig.supxlabel('Boo', x=0.5) fig.supylabel('Boo', y=0.5) - fig.draw_no_output() + fig.draw_without_rendering() pos = ax.get_tightbbox(fig.canvas.get_renderer()) assert pos.y0 > pos0.y0 + 10.0 assert pos.x0 > pos0.x0 + 10.0 diff --git a/lib/matplotlib/tests/test_dates.py b/lib/matplotlib/tests/test_dates.py index c440003f49c9..3a38516c7272 100644 --- a/lib/matplotlib/tests/test_dates.py +++ b/lib/matplotlib/tests/test_dates.py @@ -76,7 +76,7 @@ def test_date_empty(): # http://sourceforge.net/tracker/?func=detail&aid=2850075&group_id=80706&atid=560720 fig, ax = plt.subplots() ax.xaxis_date() - fig.draw_no_output() + fig.draw_without_rendering() np.testing.assert_allclose(ax.get_xlim(), [mdates.date2num(np.datetime64('2000-01-01')), mdates.date2num(np.datetime64('2010-01-01'))]) @@ -85,7 +85,7 @@ def test_date_empty(): mdates.set_epoch('0000-12-31') fig, ax = plt.subplots() ax.xaxis_date() - fig.draw_no_output() + fig.draw_without_rendering() np.testing.assert_allclose(ax.get_xlim(), [mdates.date2num(np.datetime64('2000-01-01')), mdates.date2num(np.datetime64('2010-01-01'))]) diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index 7a222f20a058..317528879304 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -412,11 +412,11 @@ def test_autofmt_xdate(which): @mpl.style.context('default') def test_change_dpi(): fig = plt.figure(figsize=(4, 4)) - fig.draw_no_output() + fig.draw_without_rendering() assert fig.canvas.renderer.height == 400 assert fig.canvas.renderer.width == 400 fig.dpi = 50 - fig.draw_no_output() + fig.draw_without_rendering() assert fig.canvas.renderer.height == 200 assert fig.canvas.renderer.width == 200 @@ -1082,10 +1082,10 @@ def test_subfigure_ticks(): ax3 = subfig_bl.add_subplot(gs[0, 3:14], sharey=ax1) fig.set_dpi(120) - fig.draw_no_output() + fig.draw_without_rendering() ticks120 = ax2.get_xticks() fig.set_dpi(300) - fig.draw_no_output() + fig.draw_without_rendering() ticks300 = ax2.get_xticks() np.testing.assert_allclose(ticks120, ticks300) diff --git a/lib/matplotlib/tests/test_mathtext.py b/lib/matplotlib/tests/test_mathtext.py index 768db940c756..0055d54a03a8 100644 --- a/lib/matplotlib/tests/test_mathtext.py +++ b/lib/matplotlib/tests/test_mathtext.py @@ -402,7 +402,7 @@ def test_default_math_fontfamily(): prop2 = text2.get_fontproperties() assert prop2.get_math_fontfamily() == 'cm' - fig.draw_no_output() + fig.draw_without_rendering() def test_argument_order(): @@ -427,7 +427,7 @@ def test_argument_order(): prop4 = text4.get_fontproperties() assert prop4.get_math_fontfamily() == 'dejavusans' - fig.draw_no_output() + fig.draw_without_rendering() def test_mathtext_cmr10_minus_sign(): diff --git a/lib/matplotlib/tests/test_units.py b/lib/matplotlib/tests/test_units.py index c7a06e0e32ac..a6f6b44c9707 100644 --- a/lib/matplotlib/tests/test_units.py +++ b/lib/matplotlib/tests/test_units.py @@ -226,17 +226,17 @@ def test_empty_default_limits(quantity_converter): munits.registry[Quantity] = quantity_converter fig, ax1 = plt.subplots() ax1.xaxis.update_units(Quantity([10], "miles")) - fig.draw_no_output() + fig.draw_without_rendering() assert ax1.get_xlim() == (0, 100) ax1.yaxis.update_units(Quantity([10], "miles")) - fig.draw_no_output() + fig.draw_without_rendering() assert ax1.get_ylim() == (0, 100) fig, ax = plt.subplots() ax.axhline(30) ax.plot(Quantity(np.arange(0, 3), "miles"), Quantity(np.arange(0, 6, 2), "feet")) - fig.draw_no_output() + fig.draw_without_rendering() assert ax.get_xlim() == (0, 2) assert ax.get_ylim() == (0, 30) @@ -244,20 +244,20 @@ def test_empty_default_limits(quantity_converter): ax.axvline(30) ax.plot(Quantity(np.arange(0, 3), "miles"), Quantity(np.arange(0, 6, 2), "feet")) - fig.draw_no_output() + fig.draw_without_rendering() assert ax.get_xlim() == (0, 30) assert ax.get_ylim() == (0, 4) fig, ax = plt.subplots() ax.xaxis.update_units(Quantity([10], "miles")) ax.axhline(30) - fig.draw_no_output() + fig.draw_without_rendering() assert ax.get_xlim() == (0, 100) assert ax.get_ylim() == (28.5, 31.5) fig, ax = plt.subplots() ax.yaxis.update_units(Quantity([10], "miles")) ax.axvline(30) - fig.draw_no_output() + fig.draw_without_rendering() assert ax.get_ylim() == (0, 100) assert ax.get_xlim() == (28.5, 31.5)