Writing a backend -- the pyplot interface#
This page assumes general understanding of the information in the
Backends page, and is instead intended as reference for
third-party backend implementers. It also only deals with the interaction
between backends and pyplot
, not with the rendering side, which is described
in backend_template
.
There are two APIs for defining backends: a new canvas-based API (introduced in Matplotlib 3.6), and an older function-based API. The new API is simpler to implement because many methods can be inherited from "parent backends". It is recommended if back-compatibility for Matplotlib < 3.6 is not a concern. However, the old API remains supported.
Fundamentally, a backend module needs to provide information to pyplot
, so
that
pyplot.figure()
can create a newFigure
instance and associate it with an instance of a backend-provided canvas class, itself hosted in an instance of a backend-provided manager class.pyplot.show()
can show all figures and start the GUI event loop (if any).
To do so, the backend module must define a backend_module.FigureCanvas
subclass of FigureCanvasBase
. In the canvas-based API, this is the only
strict requirement for backend modules. The function-based API additionally
requires many module-level functions to be defined.
Canvas-based API (Matplotlib >= 3.6)#
Creating a figure:
pyplot.figure()
callsfigure = Figure(); FigureCanvas.new_manager(figure, num)
(new_manager
is a classmethod) to instantiate a canvas and a manager and set up thefigure.canvas
andfigure.canvas.manager
attributes. Figure unpickling uses the same approach, but replaces the newly instantiatedFigure()
by the unpickled figure.Interactive backends should customize the effect of
new_manager
by setting theFigureCanvas.manager_class
attribute to the desired manager class, and additionally (if the canvas cannot be created before the manager, as in the case of the wx backends) by overriding theFigureManager.create_with_canvas
classmethod. (Non-interactive backends can normally use a trivialFigureManagerBase
and can therefore skip this step.)After a new figure is registered with
pyplot
(either viapyplot.figure()
or via unpickling), if in interactive mode,pyplot
will call its canvas'draw_idle()
method, which can be overridden as desired.Showing figures:
pyplot.show()
callsFigureCanvas.manager_class.pyplot_show()
(a classmethod), forwarding any arguments, to start the main event loop.By default,
pyplot_show()
checks whether there are anymanagers
registered withpyplot
(exiting early if not), callsmanager.show()
on all such managers, and then, if called withblock=True
(or with the defaultblock=None
and out of IPython's pylab mode and not in interactive mode), callsFigureCanvas.manager_class.start_main_loop()
(a classmethod) to start the main event loop. Interactive backends should therefore override theFigureCanvas.manager_class.start_main_loop
classmethod accordingly (or alternatively, they may also directly overrideFigureCanvas.manager_class.pyplot_show
directly).
Function-based API#
Creating a figure:
pyplot.figure()
callsnew_figure_manager(num, *args, **kwargs)
(which also takes care of creating the new figure asFigure(*args, **kwargs)
); unpickling callsnew_figure_manager_given_figure(num, figure)
.Furthermore, in interactive mode, the first draw of the newly registered figure can be customized by providing a module-level
draw_if_interactive()
function. (In the new canvas-based API, this function is not taken into account anymore.)Showing figures:
pyplot.show()
calls a module-levelshow()
function, which is typically generated via theShowBase
class and itsmainloop
method.
Registering a backend#
For a new backend to be usable via matplotlib.use()
or IPython
%matplotlib
magic command, it must be compatible with one of the three ways
supported by the BackendRegistry
:
Built-in#
A backend built into Matplotlib must have its name and
FigureCanvas.required_interactive_framework
hard-coded in the
BackendRegistry
. If the backend module
is not f"matplotlib.backends.backend_{backend_name.lower()}"
then there
must also be an entry in the BackendRegistry._name_to_module
.
module:// syntax#
Any backend in a separate module (not built into Matplotlib) can be used by
specifying the path to the module in the form module://some.backend.module
.
An example is module://mplcairo.qt
for
mplcairo. The backend's
interactive framework will be taken from its
FigureCanvas.required_interactive_framework
.
Entry point#
An external backend module can self-register as a backend using an
entry point
in its pyproject.toml
such as the one used by
matplotlib-inline
:
[project.entry-points."matplotlib.backend"]
inline = "matplotlib_inline.backend_inline"
The backend's interactive framework will be taken from its
FigureCanvas.required_interactive_framework
. All entry points are loaded
together but only when first needed, such as when a backend name is not
recognised as a built-in backend, or when
list_all()
is first called.