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