Writing a backend -- the pyplot interface#

This page assumes general understanding of the information in theBackends page, and is instead intended as reference forthird-party backend implementers. It also only deals with the interactionbetween backends andpyplot, not with the rendering side, which is describedinbackend_template.

There are two APIs for defining backends: a new canvas-based API (introduced inMatplotlib 3.6), and an older function-based API. The new API is simpler toimplement because many methods can be inherited from "parent backends". It isrecommended 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 topyplot, sothat

  1. pyplot.figure() can create a newFigure instance and associate it withan instance of a backend-provided canvas class, itself hosted in an instanceof 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 abackend_module.FigureCanvassubclass ofFigureCanvasBase. In the canvas-based API, this is the onlystrict requirement for backend modules. The function-based API additionallyrequires many module-level functions to be defined.

Canvas-based API (Matplotlib >= 3.6)#

  1. Creating a figure:pyplot.figure() callsfigure=Figure();FigureCanvas.new_manager(figure,num)(new_manager is a classmethod) to instantiate a canvas and a manager andset up thefigure.canvas andfigure.canvas.manager attributes.Figure unpickling uses the same approach, but replaces the newlyinstantiatedFigure() by the unpickled figure.

    Interactive backends should customize the effect ofnew_manager bysetting theFigureCanvas.manager_class attribute to the desired managerclass, 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 backendscan normally use a trivialFigureManagerBase and can therefore skip thisstep.)

    After a new figure is registered withpyplot (either viapyplot.figure() or via unpickling), if in interactive mode,pyplotwill call its canvas'draw_idle() method, which can be overridden asdesired.

  2. Showing figures:pyplot.show() callsFigureCanvas.manager_class.pyplot_show() (a classmethod), forwarding anyarguments, to start the main event loop.

    By default,pyplot_show() checks whether there are anymanagersregistered withpyplot (exiting early if not), callsmanager.show()on all such managers, and then, if called withblock=True (or withthe defaultblock=None and out of IPython's pylab mode and not ininteractive mode), callsFigureCanvas.manager_class.start_main_loop()(a classmethod) to start the main event loop. Interactive backends shouldtherefore override theFigureCanvas.manager_class.start_main_loopclassmethod accordingly (or alternatively, they may also directly overrideFigureCanvas.manager_class.pyplot_show directly).

Function-based API#

  1. Creating a figure:pyplot.figure() callsnew_figure_manager(num,*args,**kwargs) (which also takes care ofcreating the new figure asFigure(*args,**kwargs)); unpickling callsnew_figure_manager_given_figure(num,figure).

    Furthermore, in interactive mode, the first draw of the newly registeredfigure can be customized by providing a module-leveldraw_if_interactive() function. (In the new canvas-based API, thisfunction is not taken into account anymore.)

  2. 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 viamatplotlib.use() or IPython%matplotlib magic command, it must be compatible with one of the three wayssupported by theBackendRegistry:

Built-in#

A backend built into Matplotlib must have its name andFigureCanvas.required_interactive_framework hard-coded in theBackendRegistry. If the backend moduleis notf"matplotlib.backends.backend_{backend_name.lower()}" then theremust also be an entry in theBackendRegistry._name_to_module.

module:// syntax#

Any backend in a separate module (not built into Matplotlib) can be used byspecifying the path to the module in the formmodule://some.backend.module.An example ismodule://mplcairo.qt formplcairo. The backend'sinteractive framework will be taken from itsFigureCanvas.required_interactive_framework.

Entry point#

An external backend module can self-register as a backend using anentrypoint in itspyproject.toml such as the one used bymatplotlib-inline:

[project.entry-points."matplotlib.backend"]inline="matplotlib_inline.backend_inline"

The backend's interactive framework will be taken from itsFigureCanvas.required_interactive_framework. All entry points are loadedtogether but only when first needed, such as when a backend name is notrecognised as a built-in backend, or whenlist_all() is first called.