Introduction to Matplotlib

Now that we can start doing serious numerical analysis with Numpy arrays, we also reach the stage where we can no longer print out hundreds or thousands of values, so we need to be able to make plots to show the results.

The Matplotlib package can be used to make scientific-grade plots. You can import it with:

In [ ]:
import matplotlib.pyplot as plt

If you are using IPython and you want to make interactive plots, you can start up IPython with:

ipython --matplotlib

If you now type a plotting command, an interactive plot will pop up.

If you use the Jupyter Notebook, add a cell containing:

In [ ]:
%matplotlib inline

and the plots will appear inside the notebook.

Basic plotting

The main plotting function is called plot:

In [ ]:
plt.plot([1,2,3,6,4,2,3,4])

In the above example, we only gave a single list, so it will assume the x values are the indices of the list/array.

However, we can instead specify the x values:

In [ ]:
plt.plot([3.3, 4.4, 4.5, 6.5], [3., 5., 6., 7.])

Matplotlib can take Numpy arrays, so we can do for example:

In [ ]:
import numpy as np
x = np.linspace(0., 10., 50)
y = np.sin(x)
plt.plot(x, y)

The plot function is actually quite complex, and for example can take arguments specifying the type of point, the color of the line, and the width of the line:

In [ ]:
plt.plot(x, y, marker='o', color='green', linewidth=2)

The line can also be removed:

In [ ]:
plt.plot(x, y, marker='o', color='green', linewidth=0)

If you are interested, you can specify some of these attributes with a special syntax, which you can find more about in the Matplotlib documentation. Also, check out the Matplotlib webpage for examples of what is possible with this powerful package. For most plots this is probably all you will ever need.

In [ ]:
plt.plot(x, y, 'go')  # shortcut for green and circles

Exercise 1

We start by loading the data/munich_temperatures_average_with_bad_data.txt file which we encountered in the introduction to Numpy:

In [ ]:
# The following code reads the file and removes bad values
date, temperature = np.loadtxt('data/munich_temperatures_average_with_bad_data.txt', unpack=True)
keep = np.abs(temperature) < 99
date = date[keep]
temperature = temperature[keep]

Now that the data has been read in, plot the temperature against time:

In [ ]:
# your solution here

Next, try plotting the data against the fraction of the year (all years on top of each other). Note that you can use the % (modulo) operator to find the fractional part of the dates.

In [ ]:
# your solution here

Other types of plots

Scatter plots

While the plot function can be used to show scatter plots, it is mainly used for line plots, and the scatter function is more often used for scatter plots, because it allows more control of the markers.

In [ ]:
x = np.random.random(100)
y = np.random.random(100)
plt.scatter(x, y)

Histograms

Histograms are easy to plot using the hist function:

In [ ]:
plt.hist?
In [ ]:
v = np.random.uniform(0., 10., 100)
h = plt.hist(v, bins=[0,2,4,6,8,10], density=True)  # we do h= to capture the output of the function, but we don't use it (here)

Images

You can also show two-dimensional arrays with the imshow function. Note that this function requires a regular mesh as in pixels of a picture. If you have unregulaly meshed data, try the function pcolormesh (more info here).

In [ ]:
array = np.random.random((64, 64))
plt.imshow(array)

And the colormap can be changed (see here for default colormaps available in Matplotlib):

In [ ]:
plt.imshow(array, cmap='magma')

Contours

Often, countour plots come in handy when illustrating 3D data.

In [ ]:
x = y = np.arange(-2.0, 2.0, 0.005)
X, Y = np.meshgrid(x, y)
Z = np.exp(-X**2 - Y**2)

plt.axes().set_aspect('equal') # we want an equal aspect ratio such that you see we are plotting "circles"

CS = plt.contourf(X, Y, Z, cmap='viridis')
cbar = plt.colorbar(CS)

We can also add contour lines and labels (more on customozing plots with labels etc. later):

In [ ]:
plt.axes().set_aspect('equal')

CS = plt.contourf(X, Y, Z, cmap='viridis')
cbar = plt.colorbar(CS)
cbar.ax.set_ylabel('Label for colorbar')

CS = plt.contour(X, Y, Z, colors='white')
plt.clabel(CS, inline=1)

In the above, we used the np.meshgrid function which is very useful when the plotting functions (and also other functions in general) require the X and Y coordinates in a special format. To understand the np.meshgrid function better, consider the following example:

In [ ]:
# For example:
x = [1,2,3]
y = [1,2]
a, b = np.meshgrid(x, y)

print(np.shape(a), np.shape(b))
print(a)
print(b)

So for each of the chosen x and y points, a and b contain the values of x and y, respectively.

In [ ]:
# at coordinate (0|1), we have (note: the first index fixes y, the second x)
print(x[0], y[1], a[1][0], b[1][0])

Field lines

For a vector field, you can plot a depiction of the field lines with plt.streamplot

Here, we do this for the following field in the xy-plane $$\vec{K}(\vec{r})=\vec{K}(x,y,z) = (-y,x,0) = \vec{e}_z \times \vec{r}$$

We again use np.meshgrid to obtain the elements of $\vec{K}$ in the right format for the plt.streamplot function.

In [ ]:
x = np.arange(-10, 10, 0.1)
y = np.arange(-10, 10, 0.1)

xx, yy = np.meshgrid(x, y)

kx = -yy
ky = xx

plt.axes().set_aspect('equal')
plt.streamplot(x, y, kx, ky, color='k')

Customizing plots

You can also customize plots. For example, the following code adds axis labels, and sets the x and y ranges explicitly:

In [ ]:
x = np.random.random(100)
y = np.random.random(100)

plt.scatter(x, y)

plt.xlabel('x values')
plt.ylabel('y values')

plt.xlim(0., 1.)
plt.ylim(0., 1.)

Saving plots to files

To save a plot to a file, you can do:

In [ ]:
x = np.random.random(100)
y = np.random.random(100)

plt.scatter(x, y)

plt.xlabel('x values')
plt.ylabel('y values')

plt.xlim(0., 1.)
plt.ylim(0., 1.)

plt.savefig('my_plot.png', dpi=300)

This has created the PNG file 'my_plot.png' and you can then view the resulting file like you would view a normal image. On Linux, you can run the following on the command line:

$ eog my_plot.png

(or pick another image viewer than 'eog').

Note: there are many more options to save figures. I would always recommend to save plots as "vector" graphics, e.g. as PDF files unless the plot contains many datapoints such that the PDF file would be too large. In such cases (e.g. data from big simulations containing millions of datapoints), use PNG files but increase the resolution by providing the dpi=300 argument (dpi = dots per inch) to plt.savefig.

Interactive plotting

One of the features of Matplotlib is the ability to make interactive plots where you can, e.g., zoom in and out, set labels, save the plot to files etc. When using IPython, you can do:

%matplotlib qt

to change the backend to be interactive, after which plots are interactive (this won't work within a Jupyter/IPython notebook).

Learning more

The easiest way to find out more about a function and available options is to use the ? help in IPython:

    In [11]: plt.hist?

Definition: plt.hist(x, bins=10, range=None, normed=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, hold=None, **kwargs)
Docstring:
Plot a histogram.

Call signature::

  hist(x, bins=10, range=None, normed=False, weights=None,
         cumulative=False, bottom=None, histtype='bar', align='mid',
         orientation='vertical', rwidth=None, log=False,
         color=None, label=None, stacked=False,
         **kwargs)

Compute and draw the histogram of *x*. The return value is a
tuple (*n*, *bins*, *patches*) or ([*n0*, *n1*, ...], *bins*,
[*patches0*, *patches1*,...]) if the input contains multiple
data.

etc.

But sometimes you don't even know how to make a specific type of plot, in which case you can look at the Matplotlib Gallery for example plots and scripts, or search the internet.

Exercise 2

  1. Use Numpy to generate 10000 random values following a Gaussian/Normal distribution, and make a histogram. Try changing the number of bins to properly see the Gaussian. Try overplotting a Gaussian function using a colored line, and adjust the normalization such that the histogram and the line are aligned.

  2. Do the same for a Poisson distribution. Compare the Poisson distribution for expectation values $\lambda<15$ with the appropriate Gaussian.

In [ ]:
# your solution here

Exercise 3

Work out the magnetic field lines of two equal but infinite line currents along the z-axis that are separated by a distance $a$ from the y-axis.

Since the streamlines are scaled, one can drop constants.

The $\vec{B}$-Field of a single line current $I$ is $$\vec{B} (\vec{r})= \frac{\mu_0 I}{2 \pi} \frac{1}{|\vec{r}|} \vec{e}_{\varphi}$$

Only if time permits: Can you plot the magnetic fieldlines in the xy-plane for a circular coil with radius $a$ in the xz-plane?

The Biot-Savart law for a wire element $\mathrm{d}\vec{l}$ is

$$\mathrm{d}\vec{B} (\vec{r})= \frac{\mu_0 I}{4 \pi} \frac{\mathrm{d} \vec{l} \times \vec{r}}{|\vec{r}|^3}$$

where $\vec{r}$ is the vector from the current element to the place of measurement.

In [ ]:
# your solution here