The basis for all of these topics is the object-oriented interface.

# Object-oriented versus MATLAB styles

We have seen a lot of examples, and in all of them we used the *matplotlib.pyplot* module to create and manipulate the plots, but this is not the only way to make use of the Matplotlib plotting power.

There are three ways to use Matplotlib:

*pyplot*: The module used so far in this article*pylab*: A module to merge Matplotlib and NumPy together in an environment closer to MATLAB- Object-oriented way: The Pythonic way to interface with Matplotlib

Let's first elaborate a bit about the *pyplot* module: *pyplot* provides a MATLAB-style, procedural, state-machine interface to the underlying object-oriented library in Matplotlib.

A **state machine** is a system with a global status, where each operation performed on the system changes its status.

*matplotlib.pyplot* is stateful because the underlying engine keeps track of the current figure and plotting area information, and plotting functions change that information. To make it clearer, we did not use any object references during our plotting we just issued a pyplot command, and the changes appeared in the figure.

At a higher level, *matplotlib.pyplot* is a collection of commands and functions that make Matplotlib behave like MATLAB (for plotting).

This is really useful when doing interactive sessions, because we can issue a command and see the result immediately, but it has several drawbacks when we need something more such as low-level customization or application embedding.

If we remember, Matplotlib started as an alternative to MATLAB, where we have at hand both numerical and plotting functions. A similar interface exists for Matplotlib, and its name is *pylab*.

*pylab* (do you see the similarity in the names?) is a companion module, installed next to *matplotlib* that merges *matplotlib.pyplot* (for plotting) and *numpy* (for mathematical functions) modules in a single namespace to provide an environment as near to MATLAB as possible, so that the transition would be easy.

We and the authors of Matplotlib discourage the use of *pylab*, other than for proof-of-concept snippets. While being rather simple to use, it teaches developers the wrong way to use Matplotlib.

The third way to use Matplotlib is through the **object-oriented** interface (**OO**, from now on). This is the most powerful way to write Matplotlib code because it allows for complete control of the result however it is also the most complex. This is the Pythonic way to use Matplotlib, and it's highly encouraged when programming with Matplotlib rather than working interactively. We will use it a lot from now on as it's needed to go down deep into Matplotlib.

Please allow us to highlight again the preferred style that the author of this article, and the authors of Matplotlib want to enforce: a bit of *pyplot* will be used, in particular for convenience functions, and the remaining plotting code is either done with the OO style or with *pyplot*, with *numpy* explicitly imported and used for numerical functions.

In this preferred style, the initial imports are:

import matplotlib.pyplot as plt

import numpy as np

In this way, we know exactly which module the function we use comes from (due to the module prefix), and it's exactly what we've always done in the code so far.

Now, let's present the same piece of code expressed in the three possible forms which we just described.

First, we present it in the style, *pyplot* only:

In [1]: import matplotlib.pyplot as plt

In [2]: import numpy as np

In [3]: x = np.arange(0, 10, 0.1)

In [4]: y = np.random.randn(len(x))

In [5]: plt.plot(x, y)

Out[5]: [<matplotlib.lines.Line2D object at 0x1fad810>]

In [6]: plt.title('random numbers')

In [7]: plt.show()

The preceding code snippet results in:

Now, let's see how we can do the same thing using the *pylab* interface:

$ ipython -pylab

...

In [1]: x = arange(0, 10, 0.1)

In [2]: y = randn(len(x))

In [3]: plot(x, y)

Out[3]: [<matplotlib.lines.Line2D object at 0x4284dd0>]

In [4]: title('random numbers')

In [5]: show()

Note that:

ipython -pylab

is not the same as running ipython and then:

from pylab import *

This is because *ipython's-pylab* switch, in addition to importing everything from pylab, also enables a specific ipython threading mode so that both the interactive interpreter and the plot window can be active at the same time.

Finally, lets make the same chart by using OO style, but with some *pyplot* convenience functions:

In [1]: import matplotlib.pyplot as plt

In [2]: import numpy as np

In [3]: x = np.arange(0, 10, 0.1)

In [4]: y = np.random.randn(len(x))

In [5]: fig = plt.figure()

In [6]: ax = fig.add_subplot(111)

In [7]: l, = plt.plot(x, y)

In [8]: t = ax.set_title('random numbers')

In [9]: plt.show()

The *pylab* code is the simplest, and ,*pyplot* is in the middle, while the OO is the most complex or verbose.

As the Python Zen teaches us, "Explicit is better than implicit" and "Simple is better than complex" and those statements are particularly true for this example: for simple interactive sessions, *pylab* or ,*pyplot* are the perfect choice because they hide a lot of complexity, but if we need something more advanced, then the OO API makes clearer where things are coming from, and what's going on. This expressiveness will be appreciated when we will embed Matplotlib inside GUI applications.

From now on, we will start presenting our code using the OO interface mixed with some *pyplot* functions.

## A brief introduction to Matplotlib objects

Before we can go on in a productive way, we need to briefly introduce which Matplotlib objects compose a figure.

Let's see from the higher levels to the lower ones how objects are nested:

Object |
Description |

FigureCanvas |
Container class for the Figure instance |

Figure |
Container for one or more Axes instances |

Axes |
The rectangular areas to hold the basic elements, such as lines, text, and so on |

## Our first (simple) example of OO Matplotlib

In the previous pieces of code, we had transformed this:

...

In [5]: plt.plot(x, y)

Out[5]: [<matplotlib.lines.Line2D object at 0x1fad810>]

...

into:

...

In [7]: l, = plt.plot(x, y)

...

The new code uses an explicit reference, allowing a lot more customizations. As we can see in the first piece of code, the plot() function returns a list of *Line2D* instances, one for each line (in this case, there is only one), so in the second code, *l* is a reference to the line object, so every operation allowed on *Line2D* can be done using *l*.

For example, we can set the line color with:

l.set_color('red')

Instead of using the keyword argument to *plot()*, so the line information can be changed after the *plot()* call.

# Subplots

In the previous section, we have seen a couple of important functions without introducing them. Let's have a look at them now:

*fig = plt.figure()*: This function returns a*Figure*, where we can add one or more*Axes*instances.*ax = fig.add_subplot(111)*: This function returns an*Axes*instance, where we can plot (as done so far), and this is also the reason why we call the variable referring to that instance ax (from*Axes*). This is a common way to add an*Axes to a*Figure, but*add_subplot()*does a bit more: it adds a**subplot**. So far we have only seen a*Figure*with one*Axes*instance, so only one area where we can draw, but Matplotlib allows more than one.

*add_subplot()* takes three parameters:

fig.add_subplot(numrows, numcols, fignum)

where:

*numrows*represents the number of rows of subplots to prepare*numcols*represents the number of columns of subplots to prepare*fignum*varies from*1*to*numrows*numcols*and specifies the current subplot (the one used now)

Basically, we describe a matrix of *numrows*numcols* subplots that we want into the *Figure*; please note that *fignum* is *1* at the upper-left corner of the *Figure* and it's equal to *numrows*numcols* at the bottom-right corner. The following table should provide a visual explanation of this:

numrows=2, numcols=2, fignum=1 |
numrows=2, numcols=2, fignum=2 |

numrows=2, numcols=2, fignum=3 |
numrows=2, numcols=2, fignum=4 |

Some usage examples are:

ax = fig.add_subplot(1, 1, 1)

Where we want a *Figure* with just a single plot area (like in all the previous examples).

ax2 = fig.add_subplot(2, 1, 2)

Here, we define the plot's matrix as made of two subplots in two different rows, and we want to work on the second one (*fignum=2*).

An interesting feature is that we can specify these numbers as a single parameter merging the numbers in just one string (as long as all of them are less than 10). For example:

ax2 = fig.add_subplot(212)

which is equivalent to:

ax2 = fig.add_subplot(2, 1, 2)

A simple example can clarify a bit:

In [1]: import matplotlib.pyplot as plt

In [2]: fig = plt.figure()

In [3]: ax1 = fig.add_subplot(211)

In [4]: ax1.plot([1, 2, 3], [1, 2, 3]);

In [5]: ax2 = fig.add_subplot(212)

In [6]: ax2.plot([1, 2, 3], [3, 2, 1]);

In [7]: plt.show()

We will use a simple naming convention for the variables that we are using. For example, we call all the *Axes* instance variables *ax*, and if there is more than one variable in the same code, then we add numbers at the end, for example, *ax1*, *ax2*, and so on.

This will allow us to make changes to the *Axes* instance after it's created, and in the case of multiple *Axes*, it will allow us to modify any of them after their creation. The same applies for multiple figures.

## Multiple figures

Matplotlib also provides the capability to draw not only multiple *Axes* inside the same *Figure*, but also multiple figures.

We can do this by calling *figure()* multiple times, keeping a reference to the *Figure* object and then using it to add as many subplots as needed in exactly the same way as having a single *Figure*.

We can now see a code with two calls to *figure()*:

In [1]: import matplotlib.pyplot as plt

In [2]: fig1 = plt.figure()

In [3]: ax1 = fig1.add_subplot(111)

In [4]: ax1.plot([1, 2, 3], [1, 2, 3]);

In [5]: fig2 = plt.figure()

In [6]: ax2 = fig2.add_subplot(111)

In [7]: ax2.plot([1, 2, 3], [3, 2, 1]);

In [8]: plt.show()

This code snippet generates two windows with one line each:

Note how the *Axes* instances are generated by calling the *add_subplot()* method on the two different *Figure* instances. As a side note, when using *pylab* or *pyplot*, we can call *figure()* with an integer parameter to access a previously created Figure: figure(1) returns a reference to the first Figure, *figure(2)* to the second one, and so on.

## Additional Y (or X) axes

There are situations where we want to plot two sets of data on the same image. In particular, this is the case when for the same X variable, we have two datasets (consider the situation where we take two measurements at the same time, and we want to plot them together to spot some relationships).

Matplotlib can do it:

In [1]: import matplotlib.pyplot as plt

In [2]: import numpy as np

In [3]: x = np.arange(0., np.e, 0.01)

In [4]: y1 = np.exp(-x)

In [5]: y2 = np.log(x)

In [6]: fig = plt.figure()

In [7]: ax1 = fig.add_subplot(111)

In [8]: ax1.plot(x, y1);

In [9]: ax1.set_ylabel('Y values for exp(-x)');

In [10]: ax2 = ax1.twinx() # this is the important function

In [11]: ax2.plot(x, y2, 'r');

In [12]: ax2.set_xlim([0, np.e]);

In [13]: ax2.set_ylabel('Y values for ln(x)');

In [14]: ax2.set_xlabel('Same X for both exp(-x) and ln(x)');

In [15]: plt.show()

What's really happening here is that two different *Axes* instances are placed such that one is on top of the other. The data for y1 will go in the first *Axes* instance, and the data for y2 will go in the second *Axes* instance.

The *twinx()* function does the trick: it creates a second set of axes, putting the new ax2 axes at the exact same position of *ax1*, ready to be used for plotting.

This is the reason why we had to set the red color for the second line: the plot information was reset so that line would have been blue, as if it was part of a completely new figure.

We can see that by using *ax1* and *ax2* for referring to *Axes* instances, we are able to modify the information (in this case, the axes labels) for both of them. Of course, since X is shared between the two, we have to call *set_xlabel()* for just one *Axes* instance.

Using two different Axes also allows us to have different scales for the two plots.

The *complementary* function, *twiny()*, allows us to share the Y-axis with two different X-axes.

## Logarithmic Axes

Another interesting feature of Matplotlib is the possibility to set the axes scale to a logarithmic one. We can independently set the X, the Y, or both axes to a logarithmic scale.

Let's see an example where both subplots and the logarithmic scale are put together:

In [1]: import matplotlib as mpl

In [2]: mpl.rcParams['font.size'] = 10.

In [3]: import matplotlib.pyplot as plt

In [4]: import numpy as np

In [5]: x = np.arange(0., 20, 0.01)

In [6]: fig = plt.figure()

In [7]: ax1 = fig.add_subplot(311)

In [8]: y1 = np.exp(x/6.)

In [9]: ax1.plot(x, y1);

In [10]: ax1.grid(True)

In [11]: ax1.set_yscale('log')

In [12]: ax1.set_ylabel('log Y');

In [13]: ax2 = fig.add_subplot(312)

In [14]: y2 = np.cos(np.pi*x)

In [15]: ax2.semilogx(x, y2);

In [16]: ax2.set_xlim([0, 20]);

In [17]: ax2.grid(True)

In [18]: ax2.set_ylabel('log X');

In [19]: ax3 = fig.add_subplot(313)

In [20]: y3 = np.exp(x/4.)

In [21]: ax3.loglog(x, y3, basex=3);

In [22]: ax3.grid(True)

In [23]: ax3.set_ylabel('log X and Y');

In [24]: plt.show()

The output of the preceding code is as follows:

Note how the characters in this image are smaller than those in the other plots. This is because we had to reduce the font size to avoid the labels and plots overlapping with each other.

*semilogx()* (and the twin function *semilogy()*) is a commodity function that merges *plot()* and *ax.set_xscale('log')* functions in a single call. The same holds for *loglog()*, which makes a plot with log scaling on both X and Y axes.

The default logarithmic base is 10, but we can change it with the *basex* and *basey* keyword arguments for their respective axes. The functions *set_xscale()* or *set_yscale()* are more general as they can also be applied to polar plots, while *semilogx()*, *semilogy()*, or *loglog()* work for lines and scatter plots.

## Share axes

With *twinx()*, we have seen that we can plot two *Axes* on the same plotting area sharing one axis. But what if we want to draw more than two plots sharing an axis? What if we want to plot on different *Axes* in the same figure, still sharing that axis? Some areas where we might be interested in such kind of graphs are:

**Financial data**—comparing the evolution of some economic indicators over the same time**Hardware testing**—plotting the electrical signals received at each pin of a parallel or serial port**Health status**— showing the development of some medical information in a given time frame (such as blood pressure, beating heart rate, weight, and so on)

*Note that while having the same unit measure on the shared axis, the other is free to have any unit; this is very important as it allows us to group up heterogeneous information.*

Matplotlib makes it very easy to share an axis (for example, the X one) on different *Axes* instances, for example, pan and zoom actions on one graph are automatically replayed to all the others.

In [1]: import matplotlib as mpl

In [2]: mpl.rcParams['font.size'] = 11.

In [3]: import matplotlib.pyplot as plt

In [4]: import numpy as np

In [5]: x = np.arange(11)

In [6]: fig = plt.figure()

In [7]: ax1 = fig.add_subplot(311)

In [8]: ax1.plot(x, x);

In [9]: ax2 = fig.add_subplot(312, sharex=ax1)

In [10]: ax2.plot(2*x, 2*x);

In [11]: ax3 = fig.add_subplot(313, sharex=ax1)

In [12]: ax3.plot(3*x, 3*x);

In [13]: plt.show()

Again, we have to use a smaller font for texts. When printed, it looks like a standard subplot image. However, if you run the code on *ipython*, then you'll observe that when zooming, panning, or performing other similar activities on a subplot, all the others will be modified too, according to the same transformation.

As we can expect, there are a couple of keyword arguments; *sharex* and *sharey*, and it's also possible to specify both of them together. In particular, this is useful when the subplots show data with the same units of measure.

>> Continue Reading Advanced Matplotlib: Part 2

[ **1** | 2 ]

**If you have read this article you may be interested to view :**