Understanding the difference between pyplot and OO API

This recipe will try to explain some of the programming interfaces in matplotlib and make a comparison of pyplot and object-oriented API (Application Programming Interface). Depending on the task at hand, this will allow us to decide why and when to use either of these interfaces.

Getting ready

When the matplotlib library was introduced, it was similar to many open source projects—there was no proper (free) solution to the problem a person had, so he wrote one. The problem encountered with MATLAB® was with respect to performance for the task in hand (http://www.aosabook.org/en/matplotlib.html), and the original author already had knowledge of both MATLAB® and Python, so he started writing matplotlib as a solution for his need for the current project.

This is the main reason matplotlib has a MATLAB®-like interface that allows one to quickly plot data without worrying about background details, such as which platform matplotlib is running on, what are the underlying rendering libraries (is it with GTK, Qt, Tk, or wxWidgets either on Linux or Windows), or are we running on Mac OS with the help of Cocoa toolkits. This is all hidden inside matplotlib under a nice procedural interface in the matplotlib.pyplot module, a stateful interface handling logic for creating figures and axes to connect them with the configured backend. It also keeps data structures for the current figure and axes, which are called upon with the plot commands.

This is the interface (matplotlib.pyplot) we have been using through most of this book as it is simple, straightforward, and good enough for most of the tasks we were trying to accomplish. The matplotlib library was designed with this philosophy in mind. We must be able to draw plots with as few commands as possible, even just one command (for example, plt.plot([1,2,3,4,5]); plt.show() works). For these tasks, we don't want to be forced into thinking about objects, instances, methods, properties, rendering backends, figures, canvases, lines, and other graphical primitives.

If you are reading this book from the start, you probably note that some classes started appearing in various examples, such as, FontProperties or AxesGrid, where we needed more than what is provided by the matplotlib.pyplot module.

This is the object-oriented programming interface that implements all the hidden hard stuff, such as rendering graphical elements, rendering those to the platform's graphical toolkit, and handling user inputs (mouse and keystrokes). There is nothing to stop us from using OO API, and that is what we are going to do.

So if we take a look at matplotlib as software, it consists of three parts:

  • matplotlib.pyplot interface: This is a set of functions for the user to create plots like in MATLAB®
  • matplotlib API (also called matplotlib frontend): This is a set of classes for the creation and management of figures, text, lines, plots, and so on
  • backends: These are drawing drivers. They transform front abstract representation into a file or a display device

This backend layer contains concrete implementations of abstract interface classes. There are classes, such as FigureCanvas (a surface to draw onto paper), Renderer (a paintbrush that does the drawing on the canvas), and Event (a class that handles the user's keystrokes and mouse events).

The code is also separated. The base abstract classes are in matplotlib.backend_bases and every concrete implementation is in a separate module. For example, the GTK 3 backend is in matplotlib.backends.backend_gkt3agg.

In this stack, there is an Artist classes' hierarchy where most of the hard stuff is done. Artist knows about Renderer and how to use it to draw images on FigureCanvas. Most of the stuff, we are interested in (text, lines, ticks, tick labels, images, and so on) are Artist or subclasses of the Artist class (located in the matplotlib.artist module).

The matplotlib.artist.Artist class contains all the shared properties of its children: coordinates transformation, clip box, label, user event handlers, and visibility.

Getting ready

In this figure, Artist is the base for most of the other classes. There are two basic categories of classes that are inherited from Artist. The first category is of primitive artists that are visible objects such as Line2D, Rectangle, Circle, and Text. The second category is of composite artists that are collections of other Artists, such as Axis, Tick, Axes, and Figure. For example, Figure has the background of the primitive artist Rectangle, but also contains at least one composite artist, Axes.

Most of the plotting is happening on the Axes class (matplotlib.axes.Axes). The figure background elements such as ticks, axis lines, and the grid and color of the background patch is contained in Axes. Another important feature of Axes is that all the helper methods create other primitive artists and add them to the Axes instance; for example, plot, hist, and imshow.

Axes.hist, for example, creates many matplotlib.patch.Rectangle instances and stores them in the Axes.patches collection.

Axes.plot creates one or more matplotlib.lines.Line2D and stores them in the Axes.lines collection.

How to do it...

As an illustration, we will:

  1. Instantiate the matplotlib Path object for custom drawing.
  2. Construct the vertices of our object.
  3. Construct the path's command codes to connect those vertices.
  4. Create a patch.
  5. Add it to the Axes instance of figure.

The following code implements our intentions:

import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches

# add figure and axes
fig = plt.figure()
ax = fig.add_subplot(111)

coords = [
    (1., 0.),  # start position
    (0., 1.),
    (0., 2.),  # left side
    (1., 3.),
    (2., 3.),
    (3., 2.),  # top right corner
    (3.,1.),  # right side
    (2., 0.),
    (0., 0.),  # ignored
    ]

line_cmds = [Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
         ]

# construct path
path = Path(coords, line_cmds)
# construct path patch 
patch = patches.PathPatch(path, lw=1,
facecolor='#A1D99B', edgecolor='#31A354')
# add it to *ax* axes
ax.add_patch(patch)

ax.text(1.1, 1.4, 'Python', fontsize=24)
ax.set_xlim(-1, 4)
ax.set_ylim(-1, 4)
plt.show()

The preceding code will generate the following:

How to do it...

How it works...

For this octagon, we used the base patch matplotlib.path.Path, which supports the basic set of primitives for drawing lines and curves (moveto and lineto). These can be used to draw simple and also more advanced polygons using Bezier curves.

First, we specified a set of coordinates in the data coordinates that we match with a set of path commands to act upon those coordinates (or vertices, if you like). With that, we instantiate matplotlib.path.Path. We then construct the patch instance matplotlib.patched.PathPatch with that path, which is a general polycurve path patch.

This patch can now be added to the figure's axes (the fig.axes collection), and we can render the figure to show the polygon.

What we didn't want to do in this example is use matplotlib.figure.Figure directly in place of the matplotlib.pyplot.figure() call. The reason for this is that the pyplot.figure() call does a lot in the background, such as reading the rc parameters from the matplotlibrc file (to load default figsize, dpi, and figure color settings), setting up the figure manager class (Gcf), and so on. We could do all that, but until we really know what we are doing, this is the recommended way to create the figure.

As a general rule of thumb, unless we cannot achieve something via the pyplot interface, we should not reach for direct classes such as Figure, Axes, and Axis, because there is a lot of state managing going on in the background; unless we are developing matplotlib, we should avoid bothering about it.

There's more...

If you want interactivity and exploration, it would be the best to use matplotlib via the Python interactive shell. For this purpose, probably the most well known is IPython. This gives you all the matplotlib features in a powerful and introspective shell with rich set features such as history, inline plotting, and the possibility to share your work if you use the IPython Notebook.

The IPython Notebook is an interface to the IPython shell that can be accessed through the browser. Matplotlib has a strong integration with this interface, indeed the plots can be directly embedded in the browser interface.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.69.199