|
| 1 | +================= |
| 2 | +Writing a backend |
| 3 | +================= |
| 4 | + |
| 5 | +**This is a work in progress.** |
| 6 | + |
| 7 | +This page assumes general understanding of the information in the |
| 8 | +:doc:`/users/explain/backends` page, and is instead intended as reference for |
| 9 | +third-party backend implementers. It also only deals with the interaction |
| 10 | +between backends and `.pyplot`, not with the rendering side, which is described |
| 11 | +in `.backend_template`. |
| 12 | + |
| 13 | +There are two APIs for defining backends: a new canvas-based API (introduced |
| 14 | +in Matplotlib 3.6), and an older function-based API. The newer API should |
| 15 | +be preferred if back-compatibility is not a concern (because of better |
| 16 | +composability: many methods can be inherited from "parent backends"), and is |
| 17 | +therefore described first, but the older API is also briefly described here. |
| 18 | + |
| 19 | +Fundamentally, a backend module needs to provide information to `.pyplot`, so |
| 20 | +that |
| 21 | + |
| 22 | +- `.pyplot.figure()` can attach a newly created `.Figure` to an instance of a |
| 23 | + backend-provided canvas class, itself hosted in an instance of a |
| 24 | + backend-provided manager class. |
| 25 | +- `.pyplot.show()` can show all figures and start the GUI event loop (if any). |
| 26 | + |
| 27 | +To do so, the backend module must define a class accessible as |
| 28 | +``backend_module.FigureCanvas``. In the canvas-based API, this is the only |
| 29 | +strict requirement for backend modules. (The function-based API additionally |
| 30 | +requires many module-level functions to be defined.) |
| 31 | + |
| 32 | +- `.pyplot.figure()` calls ``FigureCanvas.new_manager(Figure(), num)`` (a |
| 33 | + classmethod) to attach a canvas and a manager. Figure unpickling uses the |
| 34 | + same approach, but replaces the ``Figure()`` instantiation by the unpickled |
| 35 | + figure. |
| 36 | + |
| 37 | + Interactive backends should customize the effect of ``new_manager`` |
| 38 | + by setting a ``manager_class`` attribute on their ``FigureCanvas``, |
| 39 | + and additionally (if the canvas cannot be created before the |
| 40 | + manager, as in the case of the wx backend) by overriding the |
| 41 | + ``FigureManager.create_with_canvas`` classmethod. (Non-interactive backends |
| 42 | + can normally use a trivial ``FigureManagerBase`` and can therefore skip this |
| 43 | + step.) |
| 44 | + |
| 45 | + In the old function-based API, this customization point was provided by |
| 46 | + two functions, ``new_figure_manager(num, *args, **kwargs)`` (for |
| 47 | + `.pyplot.figure`) and ``new_figure_manager_given_figure`` (for unpickling). |
| 48 | + |
| 49 | +- After a new figure is registered with `.pyplot` (either via |
| 50 | + `.pyplot.figure()` or via unpickling), if in interactive mode, `.pyplot` will |
| 51 | + call its canvas' ``draw_idle()`` method. This call can be customized by |
| 52 | + providing a ``draw_if_interactive`` module-level function, but this is now |
| 53 | + discouraged (if needed, consider overriding ``draw_idle()`` instead, keeping |
| 54 | + track of whether this is the first call that method). |
| 55 | + |
| 56 | +- `.pyplot.show()` calls ``FigureCanvas.pyplot_show()`` (a classmethod), |
| 57 | + forwarding any arguments, to start the main event loop. |
| 58 | + |
| 59 | + By default, ``pyplot_show()`` checks whether there are any ``managers`` |
| 60 | + registered with `.pyplot` (exiting early if not), calls ``manager.show()`` |
| 61 | + on all such managers, and then, if called with ``block=True`` (or with the |
| 62 | + default ``block=None`` and out of IPython's pylab mode and not in interactive |
| 63 | + mode), calls ``FigureCanvas.start_main_loop()`` (a classmethod) to start the |
| 64 | + main event loop. Interactive backends should therefore override the |
| 65 | + ``FigureCanvas.start_main_loop`` classmethod accordingly (or alternatively, |
| 66 | + they may also directly override ``FigureCanvas.pyplot_show`` directly). |
| 67 | + |
| 68 | + In the old function-based API, this customization point was provided via a |
| 69 | + ``show`` callable generated via the ``ShowBase`` class and its ``mainloop`` |
| 70 | + method. |
0 commit comments