matplotlib#

Matplotlib is the core plotting package in scientific python. There are others to explore as well (which we’ll chat about on slack).

There are different interfaces for interacting with matplotlib, an interactive, function-driven (state machine) command-set and an object-oriented version. We’ll focus on the OO interface.

import numpy as np
import matplotlib.pyplot as plt

Matplotlib concepts#

Matplotlib was designed with the following goals (from mpl docs):

  • Plots should look great – publication quality (e.g. antialiased)

  • Postscript output for inclusion with TeX documents

  • Embeddable in a graphical user interface for application development

  • Code should be easy to understand it and extend

  • Making plots should be easy

Matplotlib is mostly for 2-d data, but there are some basic 3-d (surface) interfaces.

Volumetric data requires a different approach

Importing#

There are several different interfaces for matplotlib (see https://matplotlib.org/3.1.1/faq/index.html)

Basic ideas:

  • matplotlib is the entire package

  • matplotlib.pyplot is a module within matplotlib that provides easy access to the core plotting routines

  • pylab combines pyplot and numpy into a single namespace to give a MatLab like interface. You should avoid this—it might be removed in the future.

There are a number of modules that extend its behavior, e.g. basemap for plotting on a sphere, mplot3d for 3-d surfaces

Anatomy of a figure#

Figures are the highest level object and can include multiple axes

(figure from: https://matplotlib.org/stable/gallery/showcase/anatomy.html )

Backends#

Interactive backends: pygtk, wxpython, tkinter, …

Hardcopy backends: PNG, PDF, PS, SVG, …

Basic plotting#

plot() is the most basic command. Here we also see that we can use LaTeX notation for the axes

x = np.linspace(0,2.0*np.pi, num=100)
y = np.cos(x)

plt.plot(x,y)
plt.xlabel(r"$x$")
plt.ylabel(r"$\cos(x)$", fontsize="x-large")
plt.xlim(0, 2.0*np.pi)
(0.0, 6.283185307179586)
../_images/c1016d65fa4e6959a83acc5408dccead6b56bd3fb4ea0b5dc8194ac9eee22fff.png

Note that when we use the plot() command like this, matplotlib automatically creates a figure and an axis for us and it draws the plot on this for us. This is the state machine interface.

OO Interface#

fig = plt.figure()
ax = fig.add_subplot(111)

ax.plot(x, y)
ax.set_xlabel(r"$x$")
ax.set_ylabel(r"$\cos(x)$")
ax.set_xlim(0, 2*np.pi)
(0.0, 6.283185307179586)
../_images/15d8c2447255451fa7a2030e15b527c82b6f73ca2256941996d335cfa1e096bd.png

Quick Exercise:

We can plot 2 lines on a plot simply by calling plot twice. Make a plot with both sin(x) and cos(x) drawn

we can use symbols instead of lines pretty easily too—and label them

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, np.sin(x), "o", label="sine")
ax.plot(x, np.cos(x), "x", label="cosine")
ax.set_xlim(0.0, 2.0*np.pi)
ax.legend()
<matplotlib.legend.Legend at 0x7f5eec07cac0>
../_images/4fa93b34faf82e3120291b72afbb118495713f873d6bab9f2ef5a8f7ccfcfbc7.png

Here we specified the format using a “format string” (see https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.plot.html)

This has the form '[marker][line][color]'

most functions take a number of optional named arguments too

ax.clear()
ax.plot(x, np.sin(x), linestyle="--", linewidth=3.0)
ax.plot(x, np.cos(x), linestyle="-")
fig
../_images/ef3445ec164f814ca04cb5a285033005c92a4a0e296341f905329177468eb0cb.png

there is a command setp() that can also set the properties. We can get the list of settable properties as

Multiple axes#

There are a wide range of methods for putting multiple axes on a grid. We’ll look at the simplest method.

The add_subplot() method we’ve been using can take 3 numbers: the number of rows, number of columns, and current index

fig = plt.figure()

ax1 = fig.add_subplot(211)

x = np.linspace(0,5,100)
ax1.plot(x, x**3 - 4*x)
ax1.set_xlabel("x")
ax1.set_ylabel(r"$x^3 - 4x$", fontsize="large")

ax2 = fig.add_subplot(212)

ax2.plot(x, np.exp(-x**2))
ax2.set_xlabel("x")
ax2.set_ylabel("Gaussian")

# log scale
ax2.set_yscale("log")

# set the figure size
fig.set_size_inches(6, 8)

# tight_layout() makes sure things don't overlap
fig.tight_layout()
../_images/9d6c66719c613ed9ea70348fd70e7aef4a68a985797067523b0fca55f90780ab.png

Visualizing 2-d array data#

2-d datasets consist of (x, y) pairs and a value associated with that point. Here we create a 2-d Gaussian, using the meshgrid() function to define a rectangular set of points.

def g(x, y):
    return np.exp(-((x-0.5)**2)/0.1**2 - ((y-0.5)**2)/0.2**2)

N = 100

x = np.linspace(0.0,1.0,N)
y = x.copy()

xv, yv = np.meshgrid(x, y)

A “heatmap” style plot assigns colors to the data values. A lot of work has gone into the latest matplotlib to define a colormap that works good for colorblindness and black-white printing.

fig = plt.figure()
ax = fig.add_subplot(111)
im = ax.imshow(g(xv, yv), origin="lower")
fig.colorbar(im, ax=ax)
<matplotlib.colorbar.Colorbar at 0x7f5eec00cc40>
../_images/b5ebbd7fb62e5a47e1c45bd137ba1910ea82e1bc2e7d63b0c8ec2b9185ebb96d.png

Sometimes we want to show just contour lines—like on a topographic map. The contour() function does this for us.

fig = plt.figure()
ax = fig.add_subplot(111)
contours = ax.contour(g(xv, yv))
ax.axis("equal")   # this adjusts the size of image to make x and y lengths equal
(0.0, 99.0, 0.0, 99.0)
../_images/a348929b5ef728a7b22f94ffb97d6fedf34de134fe84b6a8f5a778064a70b90a.png

Quick Exercise:

Contour plots can label the contours, using the ax.clabel() function. Try adding labels to this contour plot.