From a0e77e963005696a6f7db0c3eff244935fe10177 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sun, 5 Feb 2023 16:15:57 +0100 Subject: [PATCH] Allow swapping the underlying rendering backend. This patch implements backend_inline.set_rendering_backend, such that `set_rendering_backend("foo")` behaves as if calling `matplotlib.use("foo")`, which allows selecting an alternative rendering backend. In matplotlib itself, the only relevant alternative rendering backend is cairo, which is generally less feature-ful than agg, but there are also third-party backends, such as mplcairo (`set_rendering_backend("module://mplcairo.base")`) which provide e.g. improved text rendering for complex scripts (Arabic, Hebrew) and different compositing options. --- matplotlib_inline/backend_inline.py | 35 +++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/matplotlib_inline/backend_inline.py b/matplotlib_inline/backend_inline.py index 6bcc1d4..97319fa 100644 --- a/matplotlib_inline/backend_inline.py +++ b/matplotlib_inline/backend_inline.py @@ -3,10 +3,10 @@ # Copyright (c) IPython Development Team. # Distributed under the terms of the BSD 3-Clause License. +import importlib + import matplotlib from matplotlib import colors -from matplotlib.backends import backend_agg -from matplotlib.backends.backend_agg import FigureCanvasAgg from matplotlib._pylab_helpers import Gcf from matplotlib.figure import Figure @@ -18,6 +18,29 @@ from .config import InlineBackend +def set_rendering_backend(backend_name): + """ + Set the rendering backend. + + Parameters + ---------- + backend_name : str + A backend name, as would be passed to ``matplotlib.use()``. The + backend should be non-interactive. + """ + global _backend_module, FigureCanvas + _backend_module = importlib.import_module( + backend_name[9:] if backend_name.startswith("module://") + else f"matplotlib.backends.backend_{backend_name.lower()}") + # Changes to matplotlib in version 1.2 requires a mpl backend to supply a + # FigureCanvas. See https://github.com/matplotlib/matplotlib/pull/1125 + FigureCanvas = _backend_module.FigureCanvas + + +_backend_module = FigureCanvas = None # Will be set by the call below. +set_rendering_backend("agg") # The default rendering backend. + + def new_figure_manager(num, *args, FigureClass=Figure, **kwargs): """ Return a new figure manager for a new figure instance. @@ -33,7 +56,7 @@ def new_figure_manager_given_figure(num, figure): This function is part of the API expected by Matplotlib backends. """ - manager = backend_agg.new_figure_manager_given_figure(num, figure) + manager = _backend_module.new_figure_manager_given_figure(num, figure) # Hack: matplotlib FigureManager objects in interacive backends (at least # in some of them) monkeypatch the figure object and add a .show() method @@ -152,12 +175,6 @@ def flush_figures(): show._draw_called = False -# Changes to matplotlib in version 1.2 requires a mpl backend to supply a default -# figurecanvas. This is set here to a Agg canvas -# See https://github.com/matplotlib/matplotlib/pull/1125 -FigureCanvas = FigureCanvasAgg - - def configure_inline_support(shell, backend): """Configure an IPython shell object for matplotlib use.