Plotting with matplotlib

1. Getting Started

1.1 What is matplotlib?

Matplotlib is the most popular and mature library for plotting data using Python. It has all of the functionality you would expect, including the ability to control the formatting of plots and figures at a very fine level.

The official matplotlib documentation is at http://matplotlib.org/
The matplotlib gallery is at http://matplotlib.org/gallery.html

1.2 Importing matplotlib

Matplotlib is often used through 'pyplot', which provides a high-level interface for plotting.


In [ ]:
# In IPython or the IPython notebook, it's easiest to use the pylab magic, which
# imports matplotlib, numpy, and scipy.

# The matplotlib notebook flag means that plots will be shown interactively in the
# notebooks, rather than in pop-up windows.

%matplotlib notebook

import numpy as np
import matplotlib.pyplot as plt

2. Creating Figures

There are two major challenges with creating figures. First is understanding the syntax to actually make the basic plot appear. Second is formatting the basic plot to look exactly how you would like it to look. In general, the formatting will probably take you longer...

Within pyplot (currently imported as 'plt'), there are two basic ways to go about making plots - using the Matlab-like clone, and using the object-oriented approach. The latter provides better control over plot features, while only requiring slightly more typing. It's easy to quickly outgrow the Matlab clone, so we'll go right to the object-oriented syntax.

2.1 A first plot

In simple matplotlib plotting, there are two concepts to distinguish:

  • Figure - the entire figure, like what you might see in a journal, including all subplots, axes, lines, labels, etc. The whole enchilada.

  • Subplot/Axes - one of the sub-sections of the figure, labeled (a), (b), etc. in articles. Each subplot will contain one Axes object, which is the container where all of the useful stuff, such as actual lines, legends, labels, etc., are actually housed.

For example, here's how to make one figure with two subplots, the second of which contains two lines.


In [ ]:
# First we make some data to plot
x = np.linspace(-2*np.pi, 2*np.pi)
y1 = np.sin(x)
y2 = np.cos(x)

First, create an empty figure with 2 subplots using the subplots method

figure, axes = plt.subplots(rows, columns)

  • The arguments (1, 2) indicate 1 row and 2 cols
  • The function plt.subplots returns an object for the figure and for each axes
  • There are multiple ways to accomplish this same goal, but this is probably the simplest - notice that each subplot is associated with one of the axes objects.

In [ ]:
fig, axes = plt.subplots(1,2)

Now let's actually plot the data using the plot method on an axis

axis.plot(x, y)

You can plot multiple lines on an axis


In [ ]:
fig, axes = plt.subplots(1,2)

# We plot one line on the first axis
axes[0].plot(x, y1)
# and both lines on the second axis
axes[1].plot(x, y1)
axes[1].plot(x, y2);

Many of the basic formatting problems you have will be solved by the magic of tight_layout. Before you start tweaking how you figure looks, try it out.

plt.tight_layout()

In [ ]:
fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1)
axes[1].plot(x, y1)
axes[1].plot(x, y2)

plt.tight_layout();

To save your figure you can use the savefig command:

fig.savefig('fileanme', format='png')

Format options include png, pdf, ps, eps and svg


In [ ]:
fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1)
axes[1].plot(x, y1)
axes[1].plot(x, y2)

fig.savefig('first_plot.png', format='png');

TRY IT

Create a line graph plotting the function f(x) = x^3 for values of x 0-10.


In [ ]:

3. Formatting Figures

The formatting of figures often takes longer than actually setting them up and adding data. There are many different approaches to formatting figures in matplotlib (many goals can be accomplished in different ways, using different commands), and you will come across many of these as you learn more. The tips below give a few simple ways to get started.

3.1 Line formatting

The plot method has several available keyword arguments that you can use to change the line formatting.

  • color - Chages color of line. examples: 'red', 'blue', 'r', 'k', 0.5, '#ffaa00', (0,0.5,0.75)
  • linewidth - Weight of line. Takes float value in points (like font)
  • linestyle - Solid, dashed, or other. examples: -, --, -.

In [ ]:
x = np.linspace(-2*np.pi, 2*np.pi)
y1 = np.sin(x)
y2 = np.cos(x)

fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1, color='r', linewidth=5)
axes[1].plot(x, y1, color='#ffaa00', linewidth=0.5, linestyle='--')
axes[1].plot(x, y2, color='green', linestyle='-.');

3.2 Tick marks

You can set the values where the ticks are located using the xticks and yticks methods.

They take a list of values

plt.xticks([val1, val2, val3])
plt.yticks([yval1, yval2, yval3])

In [ ]:
x = np.linspace(-2*np.pi, 2*np.pi)
y1 = np.sin(x)
y2 = np.cos(x)

fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1, color='r', linewidth=5)
axes[1].plot(x, y1, color='#ffaa00', linewidth=0.5, linestyle='--')
axes[1].plot(x, y2, color='green', linestyle='-.')
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
plt.yticks([-1, 0, 1]);

Oh no! That changed it for the last plot but not for the first plot.

To set each plot individually, you need to set the current axis to the subplot you are interested in using the method sca. Then you can use xticks and yticks.

plt.sca(axis)
plt.xticks([val1, val2, val3])
plt.yticks([yval1, yval2, yval3])

In [ ]:
x = np.linspace(-2*np.pi, 2*np.pi)
y1 = np.sin(x)
y2 = np.cos(x)

fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1, color='r', linewidth=5)
axes[1].plot(x, y1, color='#ffaa00', linewidth=0.5, linestyle='--')
axes[1].plot(x, y2, color='green', linestyle='-.')

# Set the current axis to the first subplot
fig.sca(axes[0])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
plt.yticks([-1, 0, 1])

# Set the current axis to the second subplot
fig.sca(axes[1])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
plt.yticks([-1, 0, 1]);

3.3 Axis limits

Setting the limits of the axes is very similar to setting the ticks. The command to set the limits are xlim and ylim. Remember if you have more than one subplot, you will need to set the current axis before you set that axis' limits.

plt.sca(axis)
plt.xlim(xmin, xmax)
plt.ylim(ymin, ymax)

In [ ]:
x = np.linspace(-2*np.pi, 2*np.pi)
y1 = np.sin(x)
y2 = np.cos(x)

fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1, color='r', linewidth=5)
axes[1].plot(x, y1, color='#ffaa00', linewidth=0.5, linestyle='--')
axes[1].plot(x, y2, color='green', linestyle='-.')

# Set the current axis to the first subplot
fig.sca(axes[0])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
plt.yticks([-1, 0, 1])


# set x and y limits
plt.xlim(-np.pi, np.pi)
plt.ylim(-1, 1)

# Set the current axis to the second subplot
fig.sca(axes[1])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
plt.yticks([-1, 0, 1])


# set x and y limits
plt.xlim(-np.pi, np.pi)
plt.ylim(-1, 1);

3.4 Setting tick labels

To set the tick labels, you pass a second parameter to the xticks and yticks methods with a list of labels for that axis.

plt.sca(axis)
plt.xticks([tickvalues], [ticklabels])
plt.yticks([tickvalues], [ticklabels])

In [ ]:
x = np.linspace(-2*np.pi, 2*np.pi)
y1 = np.sin(x)
y2 = np.cos(x)

fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1, color='r', linewidth=5)
axes[1].plot(x, y1, color='#ffaa00', linewidth=0.5, linestyle='--')
axes[1].plot(x, y2, color='green', linestyle='-.')

# Set the current axis to the first subplot
fig.sca(axes[0])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi], ['-pi', '-pi/2', '0', 'pi/2', 'pi'])
# You probably don't want to set the labels when you just want the exact numbers.
plt.yticks([-1, 0, 1], ['-1', '0', '1'])


# set x and y limits
plt.xlim(-np.pi, np.pi)
plt.ylim(-1, 1)

# Set the current axis to the second subplot
fig.sca(axes[1])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi], ['-pi', '-pi/2', '0', 'pi/2', 'pi'])
plt.yticks([-1, 0, 1], ['-1', '0', '1'])


# set x and y limits
plt.xlim(-np.pi, np.pi)
plt.ylim(-1, 1);

3.5 Legend

When you create a line on a plot, you can pass it a keyword argument label and then create a legend that will use that label using the legend method. The legend method takes an optional parameter of loc for the location of the legend. You can see the values allowed here: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.legend This is another one of those commands that you need to set the current axis if you have more than one subplot.

plt.plot(x,y, label='my_label')
plt.legend(loc='best')

In [ ]:
x = np.linspace(-2*np.pi, 2*np.pi)
y1 = np.sin(x)
y2 = np.cos(x)

fig, axes = plt.subplots(1,2)
# Let's set labels here
axes[0].plot(x, y1, color='r', linewidth=5, label='sin(x)')
axes[1].plot(x, y1, color='#ffaa00', linewidth=0.5, linestyle='--', label='sin(x)')
axes[1].plot(x, y2, color='green', linestyle='-.', label='cos(x)')

# Set the current axis to the first subplot
fig.sca(axes[0])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi], ['-pi', '-pi/2', '0', 'pi/2', 'pi'])
# You probably don't want to set the labels when you just want the exact numbers.
plt.yticks([-1, 0, 1], ['-1', '0', '1'])
plt.legend(loc='best')

# set x and y limits
plt.xlim(-np.pi, np.pi)
plt.ylim(-1, 1)

# Set the current axis to the second subplot
fig.sca(axes[1])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi], ['-pi', '-pi/2', '0', 'pi/2', 'pi'])
plt.yticks([-1, 0, 1], ['-1', '0', '1'])
plt.legend(loc='upper right')

# set x and y limits
plt.xlim(-np.pi, np.pi)
plt.ylim(-1, 1);

TRY IT

Go back to your plot of f(x) = x^3 for values of x 0-10. Try out some of the formatting options you just learned to make your plot look "just right"


In [ ]:

4. Other types of plots

Matplotlib is more than just line plots, let's see what else it can do.

1.1 Other plots

In the examples above, we used the plot method to make line plots. There are also methods to make scatter plots, barplots, histograms, loglog plots, semilog plots, etc.

# Bar graph
ax.bar(x, y)

# Scatter plot
ax.scatter(x,y)

# Horizontal bar plot
ax.barh(x,y)

# Boxplot
ax.boxplot(x)

# Log-log plot
ax.loglog(x,y)

# Semilog plot
ax.semilogx(x,y)
ax.semilogy(x,y)

Plots too squished? Check out plt.tight_layout()


In [ ]:
# Make some data to plot
x = np.arange(0, 100)
y = np.random.rand(100)  # 100 random numbers

# Make a figure with 6 subplots and axes
# Notice that we are doing some arguement unpacking to get six subplots. You can use indexing instead if you prefer
fig, ((ax1, ax2), (ax3, ax4), (ax5, ax6)) = plt.subplots(3, 2)

# Add data to each axis. Optional arguments to each method will customize each plot.
ax1.bar(x,y)
ax2.scatter(x,y)
ax3.barh(x,y)
ax4.boxplot(x)
ax5.loglog(x,y)
ax6.semilogx(x,y)

Many of the same formatting options as the line plot are available for these additional plots. There are also some other options. The gallery (section 5) is the best place to find all the options.

Let's try changing the marker on the scatter plot: http://matplotlib.org/exmples/lines_bars_and_markers/marker_reference.html


In [ ]:
fig, ax = plt.subplots(1,1)
ax.scatter(x, y, marker='x')
ax.scatter(x, y + 2, marker='>', color='#00aaff')

4.2 Plotting images

Matplotlib also makes it easy to plot images. For this, you can use the plot method imshow (syntax borrowed from Matlab).

To load in an image we use the imread function. This takes a file path and reads the file into a numpy ndarray

To plot an image, you can use imshow function giving it an array.

A 1D array will be rendered as grayscale and a 3D or (4D with transparency) array will be a full color image.

To set the colormap of a grayscale image, you can use the optional cmap key word argument to imshow. Options available are listed here: http://matplotlib.org/examples/color/colormaps_reference.html


In [ ]:
# Read image from file and display it
img1 = plt.imread('astronaut.png')
# Uncomment following line to prove it still works without the alpha channel
# img1 = img1[:,:, 0:3]
fig, ax = plt.subplots(1,1)
ax.imshow(img1)

In [ ]:
# We can plot random noise in the viridis colormap.
img2 = np.random.rand(128, 128)

fig, ax = plt.subplots(1,1)
ax = ax.imshow(img2, cmap='viridis')

TRY IT

Plot the cubes from 1-10 in a vertical bar chart and in a scatter plot (2 separate subplots). Change the colors of the bars to green. Change the marker of the scatter plot to plus signs.


In [ ]:

It can be very intimidating to try to craft exactly the figure that you want, especially if you are used to being able to adjust things visually using a program like Excel.

If you get stuck and don't know where to start, or just want to learn more about what matplotlib can do, a great option is to have a look at the matplotlib gallery, which can be found at http://matplotlib.org/gallery.html. A good way to get started is to find a figure here that sort of looks like what you want, copy the code, and modify it for your own needs.

Have a look at the matplotlib gallery. If find a cool looking figure you can copy the code into a code line. You can of course do this manually but you can also use IPython "load magic" Type %loadpy and then the URL of the py file containing the code, and it will automatically copy it into a cell below. Run the cell with the code to see the figure. Now you can make small (or large) tweaks to get your perfect figure.

Note that some of the examples might require packages that are not installed on your machine (in particular those that make maps) - if this is the case, pick another example for the purposes of this exercise.

Hint to get the raw python url right click on the source code link towards the top and pick copy link.


In [ ]:
# %load http://matplotlib.org/mpl_examples/pylab_examples/contour_demo.py

TRY IT

Find an example from the gallery and run it here.


In [ ]: