SciPy

Pandas

# Matplotlib¶

## Overview¶

We’ve already generated quite a few figures in these lectures using Matplotlib

Matplotlib is interesting in that it provides two fairly different interfaces

The first is designed to mimic MATLAB graphics functionality, and is aimed mainly at beginners

The second is object oriented, more Pythonic and more powerful, but requires some more effort to learn

In this lecture we’ll cover both, with a focus on the second method

## The MATLAB-style API¶

Matplotlib is very easy to get started with, thanks to its simple MATLAB-style API (Application Progamming Interface)

Here’s an example

from pylab import *
x = linspace(0, 10, 200)
y = sin(x)
plot(x, y, 'b-', linewidth=2)
show()


The figure it generates looks as follows

If you’ve run these commands inside the IPython notebook with the --pylab inline flag

• the figure will appear embedded in your browser
• the from pylab import * line is unnecessary

If you’ve run these commands in IPython without the --pylab inline flag, it will appear as a separate window, like so

The buttons at the bottom of the window allow you to manipulate the figure and then save it if you wish

Note that the pylab module combines core parts of matplotlib, numpy and scipy

Hence from pylab import * pulls NumPy functions like linspace and sin into the global namespace

Most people start working with Matplotlib using this MATLAB style

## The Object-Oriented Approach¶

The MATLAB style API is simple and convenient, but it’s also a bit limited and somewhat un-Pythonic

For example, in the code above, we use from pylab import *

Here we are pulling lots and lots of names into the global namespace, which is not really a good idea

In particular, with import * we’re pulling in a lot of names and we don’t even know what we’re pulling in

To a trained Python programmer this is a horrible idea

It’s better to be explicit rather than implicit (type import this in the IPython (or Python) shell and look at the second line)

This leads us to the alternative, object oriented API

Here’s the code corresponding to the preceding figure using this second approach

import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
x = np.linspace(0, 10, 200)
y = np.sin(x)
ax.plot(x, y, 'b-', linewidth=2)
plt.show()


While there’s a bit more typing, the more explicit declarations will give us far more fine-grained control

This will become more clear as we go along

Incidentally, regarding the above lines of code,

• the form of the import statement import matplotlib.pyplot as plt is standard

• Here the call fig, ax = plt.subplots() returns a pair, where

• fig is a Figure instance—like a blank canvas
• ax is an AxesSubplot instance—think of a frame for plotting in
• The plot() function is actually a method of ax

### Customization¶

Here we’ve changed the line to red and added a legend

import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
x = np.linspace(0, 10, 200)
y = np.sin(x)
ax.plot(x, y, 'r-', linewidth=2, label='sine function', alpha=0.6)
ax.legend()
plt.show()


We’ve also used alpha to make the line slightly transparent—which makes it look smoother

Unfortunately the legend is obscuring the line

This can be fixed by replacing ax.legend() with ax.legend(loc='upper center')

If everthing is properly configured, then adding LaTeX is trivial

import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
x = np.linspace(0, 10, 200)
y = np.sin(x)
ax.plot(x, y, 'r-', linewidth=2, label=r'$y=\sin(x)$', alpha=0.6)
ax.legend(loc='upper center')
plt.show()


The r in front of the label string tells Python that this is a raw string

The figure now looks as follows

Controlling the ticks, adding titles and so on is also straightforward

import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
x = np.linspace(0, 10, 200)
y = np.sin(x)
ax.plot(x, y, 'r-', linewidth=2, label=r'$y=\sin(x)$', alpha=0.6)
ax.legend(loc='upper center')
ax.set_yticks([-1, 0, 1])
ax.set_title('Test plot')
plt.show()


Here’s the figure

It’s straightforward to generate mutiple plots on the same axes

Here’s an example that randomly generates three normal densities and adds a label with their mean

import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import norm
from random import uniform

fig, ax = plt.subplots()
x = np.linspace(-4, 4, 150)
for i in range(3):
m, s = uniform(-1, 1), uniform(1, 2)
y = norm.pdf(x, loc=m, scale=s)
current_label = r'$\mu = {0:.2f}$'.format(m)
ax.plot(x, y, linewidth=2, alpha=0.6, label=current_label)
ax.legend()
plt.show()


At other times we want multiple subplots in one figure

Here’s an example that generates 6 histograms

import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import norm
from random import uniform
num_rows, num_cols = 3, 2
fig, axes = plt.subplots(num_rows, num_cols, figsize=(8, 12))
for i in range(num_rows):
for j in range(num_cols):
m, s = uniform(-1, 1), uniform(1, 2)
x = norm.rvs(loc=m, scale=s, size=100)
axes[i, j].hist(x, alpha=0.6, bins=20)
t = r'$\mu = {0:.1f}, \quad \sigma = {1:.1f}$'.format(m, s)
axes[i, j].set_title(t)
axes[i, j].set_xticks([-4, 0, 4])
axes[i, j].set_yticks([])
plt.show()


The output looks as follows

In fact the preceding figure was generated by the code above preceded by the following three lines

from matplotlib import rc
rc('font',**{'family':'serif','serif':['Palatino']})
rc('text', usetex=True)


Depending on your LaTeX installation, this may or may not work for you — try experimenting and see how you go

### A Customizing Function¶

Perhaps you will find a set of customizations that you regularly use

Suppose we usually prefer our axes to go through the origin, and to have a grid

Here’s a nice example from this blog of how the object-oriented API can be used to build a custom subplots function that implements these changes

Read carefully through the code and see if you can follow what’s going on

import matplotlib.pyplot as plt
import numpy as np

def subplots():
"Custom subplots with axes throught the origin"
fig, ax = plt.subplots()

# Set the axes through the origin
for spine in ['left', 'bottom']:
ax.spines[spine].set_position('zero')
for spine in ['right', 'top']:
ax.spines[spine].set_color('none')

ax.grid()
return fig, ax

fig, ax = subplots()  # Call the local version, not plt.subplots()
x = np.linspace(-2, 10, 200)
y = np.sin(x)
ax.plot(x, y, 'r-', linewidth=2, label='sine function', alpha=0.6)
ax.legend(loc='lower right')
plt.show()


Here’s the figure it produces (note axes through the origin and the grid)

The custom subplots function

1. calls the standard plt.subplots function internally to generate the fig, ax pair,
2. makes the desired customizations to ax, and
3. passes the fig, ax pair back to the calling code