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

  1. pyplot.figure() can create a new Figure instance and associate it with an instance of a backend-provided canvas class, itself hosted in an instance of a backend-provided manager class.

  2. 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)#

  1. Creating a figure: pyplot.figure() calls figure = Figure(); FigureCanvas.new_manager(figure, num) (new_manager is a classmethod) to instantiate a canvas and a manager and set up the figure.canvas and figure.canvas.manager attributes. Figure unpickling uses the same approach, but replaces the newly instantiated Figure() by the unpickled figure.

    Interactive backends should customize the effect of new_manager by setting the FigureCanvas.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 the FigureManager.create_with_canvas classmethod. (Non-interactive backends can normally use a trivial FigureManagerBase and can therefore skip this step.)

    After a new figure is registered with pyplot (either via pyplot.figure() or via unpickling), if in interactive mode, pyplot will call its canvas' draw_idle() method, which can be overridden as desired.

  2. Showing figures: pyplot.show() calls FigureCanvas.manager_class.pyplot_show() (a classmethod), forwarding any arguments, to start the main event loop.

    By default, pyplot_show() checks whether there are any managers registered with pyplot (exiting early if not), calls manager.show() on all such managers, and then, if called with block=True (or with the default block=None and out of IPython's pylab mode and not in interactive mode), calls FigureCanvas.manager_class.start_main_loop() (a classmethod) to start the main event loop. Interactive backends should therefore override the FigureCanvas.manager_class.start_main_loop classmethod accordingly (or alternatively, they may also directly override FigureCanvas.manager_class.pyplot_show directly).

Function-based API#

  1. Creating a figure: pyplot.figure() calls new_figure_manager(num, *args, **kwargs) (which also takes care of creating the new figure as Figure(*args, **kwargs)); unpickling calls new_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.)

  2. Showing figures: pyplot.show() calls a module-level show() function, which is typically generated via the ShowBase class and its mainloop 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:


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:

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.