Seasoned computer scientists, engineers, and software developers all know that one of the subtler and trickier problems that arise in our industry is naming. It sounds a bit silly and it is repeatedly the subject of jokes, but the difficulty remains—how do you speak or write explicitly on a subject whose very nature requires exquisite precision and yet has great ambiguity that arises in different contexts?
We have the same problem with the term backend. Here, as in so many other instances, the context is everything. Our context is matplotlib, a set of tools, and a framework where everything is done in support of the visualizing of data and their relationships. The term backend has to be viewed from this perspective to support the generation of plots. The matplotlib backend has nothing to do with other noteworthy backends such as databases, servers, messaging systems, or dispatchers of various sorts. The backend of matplotlib is an abstraction layer over various components that are capable of rendering a Figure. Such plots appear in desktop applications that are embedded in widgets or web pages; other plots are images in publications (digital and print). They can be generated with code, through user interfaces, or by deploying a combination of both. These plots might be the creation of a single user tweaking a widget or a batch processing job on a high-performance computing grid. All are supported by and require a matplotlib backend.
As you might have been able to deduce from the examples given in the previous sections, the backends in matplotlib can be divided into two functional categories:
User interface backends include the following:
The hardcopy backends comprise of the following:
Hardcopy backends can be further divided based on the support of raster graphics, vector graphics, or both of these.
Furthermore, the user-interface and hardcopy backends are built upon some core abstractions. The base classes for these are as follows:
FigureCanvasBase
and FigureManagerBase
RendererBase
and GraphicsContextBase
Event
, ShowBase
, and Timer
Examining these base classes brings us to the nuts and bolts of the matplotlib backend architecture.
The FigureCanvasBase
class is a base class that is used by the user interface and hardcopy backends. It represents the canvas in which the Figure will render. Its responsibilities include the following:
When used by hardcopy backends, the FigureCanvasBase
classes can register the file types supported by hardcopy backends (for example, .tiff
and .jpg
). When used by the user interface backends, the FigureCanvasBase
classes provide the means by which the matplotlib canvas is inserted into the native toolkit window (even when it is GTK, Mac OS X Cocoa, Qt, or Tk).
Additionally, there is a FigureManagerBase
class that is used by matplotlib when running in pyplot
mode. This class wraps FigureCanvasBase
as well as various GUI toolkit methods for the easier rendering of figures and interfaces.
In matplotlib, the renderer handles the drawing operations. RendererBase
was originally inspired by the GIMP drawing toolkit's Drawable
class, and this is evident when one examines its drawing methods to render paths, images, Gouraud triangles, text, markers, path collections, and quad meshes.
Note that many of the render operations are handed off to an additional abstraction—GraphicsContextBase
. This abstraction provides a clean separation for code that handles color, line styles, hatching styles, blending properties, and antialiasing options, among others.
There are several aspects of the matplotlib backend that have to do with events, event loops, and timing. These responsibilities are divided across three base classes:
As mentioned in a previous section, FigureCanvasBase
defines event methods that are used when translating to and from native GUI toolkit events. These methods instantiate the Event
classes and are connected to the callbacks stored in CallbackRegistry
, which is itself stored as an attribute on FigureCanvasBase
.
Depending on the nature of the event, it may need to track the data in the artist layer, work with renderers, and so on. As such, some of the Event
classes carry references to more than just their event properties, allowing callback functions to easily access this data.
At the core of every GUI toolkit is an event loop. Every user interface backend that integrates with a toolkit needs to define a module-level Show
class, subclassing ShowBase
. Its mainloop
method is what pyplot
uses to start up the given toolkit's main loop. However, in order for this to work, matplotlib needs something to connect to the native toolkit's timer.
This is what implementations such as TimerQT
, TimerGTK3
, and TimerTornado
provide. These classes have a callbacks attribute that is a simple list of (function, args, and kwards) tuples that get called upon by timer events. The TimerQT
and TimerGTK3
classes integrate the GUI main loops, while the TimerTornado
class integrates the I/O
or event
loop of the Tornado asynchronous networking library.
A practical example of how these can work together will include things such as a key press, a mouse click, or the picking of events. Key presses can be used to develop custom keyboard commands that change a plot based on the interactive input from the user. The ability to pick events allows the developers to support the interactive panning and zooming of their plots. All of these events are intercepted by the matplotlib event system and then forwarded to the native toolkits after the backend does the appropriate translation.
The matplotlib backend components work together in order to provide a seamless experience regardless of:
We now have the information needed to visually summarize the backend layer. This information is portrayed in the following image:
Note that in reality, the backend layer and its components are more complex than this graphic portrays. There are multiple relationships, as is exemplified by RendererBase
and FigureCanvasBase
appearing twice. The intent is to show the main backend base classes. The FigureManagerBase
function has one of the other backend base classes as a supporting component (its canvas attribute).
This concludes our overview of matplotlib's backend layer. In the next section, we will move higher up the stack.