diff --git a/doc/api/next_api_changes/deprecations/17891-BDD.rst b/doc/api/next_api_changes/deprecations/17891-BDD.rst new file mode 100644 index 000000000000..907daf7167f7 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/17891-BDD.rst @@ -0,0 +1,6 @@ +Removing ``ipython_inline_display`` from Webagg backend +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``matplotlib.backends.backend_webagg.ipython_inline_display`` is +deprecated. It relies on outdated functionality of the tornado server and +asyncio event loop and appears to be broken. diff --git a/doc/users/next_whats_new/figure_repr_png.rst b/doc/users/next_whats_new/figure_repr_png.rst new file mode 100644 index 000000000000..fb2656d119b4 --- /dev/null +++ b/doc/users/next_whats_new/figure_repr_png.rst @@ -0,0 +1,7 @@ +Add ``_repr_png_`` for figures with no configured IPython backend +----------------------------------------------------------------- + +Previously, IPython would not show figures as images unless using the +``matplotlib.pyplot`` interface or with an IPython magic statement like +``%matplotlib backend``. Now, no magic is required to view PNG figure +representations. diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index a4ce63879cbf..c909d5bf8bc1 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -1701,6 +1701,26 @@ def __init__(self, figure): self.toolbar = None # NavigationToolbar2 will set me self._is_idle_drawing = False + def _repr_png_(self): + """Generate a PNG representation of the FigureCanvasBase.""" + # Defer to IPython to handle output if possible. + if 'IPython' in sys.modules: + from IPython.core.pylabtools import configure_inline_support + # Check whether %matplotlib was run. + if hasattr(configure_inline_support, 'current_backend'): + return + + png_bytes = io.BytesIO() + self.print_figure( + png_bytes, + format='png', + facecolor=self.figure.get_facecolor(), + edgecolor=self.figure.get_edgecolor(), + dpi=self.figure.dpi, + bbox_inches=self.figure.bbox_inches + ) + return png_bytes.getvalue() + @classmethod @functools.lru_cache() def _fix_ipython_backend2gui(cls): diff --git a/lib/matplotlib/backends/backend_webagg.py b/lib/matplotlib/backends/backend_webagg.py index 555563b1f34f..0b2d26b9cbaf 100644 --- a/lib/matplotlib/backends/backend_webagg.py +++ b/lib/matplotlib/backends/backend_webagg.py @@ -33,6 +33,7 @@ import tornado.websocket import matplotlib as mpl +from matplotlib import cbook from matplotlib.backend_bases import _Backend from matplotlib._pylab_helpers import Gcf from . import backend_webagg_core as core @@ -282,6 +283,7 @@ def catch_sigint(): ioloop.start() +@cbook.deprecated("3.4") def ipython_inline_display(figure): import tornado.template diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 7c740ff39abf..6a546ceeaab4 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -365,16 +365,10 @@ def __init__(self, # list of child gridspecs for this figure self._gridspecs = [] - # TODO: I'd like to dynamically add the _repr_html_ method - # to the figure in the right context, but then IPython doesn't - # use it, for some reason. - - def _repr_html_(self): - # We can't use "isinstance" here, because then we'd end up importing - # webagg unconditionally. - if 'WebAgg' in type(self.canvas).__name__: - from matplotlib.backends import backend_webagg - return backend_webagg.ipython_inline_display(self) + def _repr_png_(self): + """Generate a PNG representation of the Figure.""" + if hasattr(self.canvas, '_repr_png_'): + return self.canvas._repr_png_() def show(self, warn=True): """ diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index 22ecafc4ce8e..3efe4d2a3daf 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -780,6 +780,14 @@ def test_hashable_keys(self, fig_test, fig_ref): fig_ref.subplot_mosaic([["A", "B"]]) +def test_figure_repr_png(): + from matplotlib.figure import Figure + fig = Figure(figsize=(4, 2)) + ax = fig.add_subplot() + png_bytes = fig._repr_png_() + assert len(png_bytes) > 0 + + def test_reused_gridspec(): """Test that these all use the same gridspec""" fig = plt.figure()