Skip to content
Snippets Groups Projects

Plotting with python

The main plotting module in python is matplotlib. There is a lot that can be done with it - see the webpage

Contents


Inside a notebook

Inside a jupyter notebook you get access to this in a slightly different way, compared to other modules:

%matplotlib inline

This only needs to be done once in a notebook, like for standard imports.

There are also other alternatives, including interactive versions - see the practical on Jupyter notebooks for more information about this.

The library works very similarly to plotting in matlab. Let's start with some simple examples.

2D plots

import matplotlib.pyplot as plt
import numpy as np

plt.style.use('bmh')

x = np.linspace(-np.pi, np.pi, 256)
cosx, sinx = np.cos(x), np.sin(x)

plt.plot(x, cosx)
plt.plot(x, sinx, color='red', linewidth=4, linestyle='-.')
plt.plot(x, sinx**2)
plt.xlim(-np.pi, np.pi)
plt.title('Our first plots')

Note that the plt.style.use('bmh') command is not necessary, but it does make nicer looking plots in general. You can use ggplot instead of bmh if you want something resembling plots made by R. For a list of options run: print(plt.style.available)

You can also save the objects and interrogate/set their properties, as well as those for the general axes:

hdl = plt.plot(x, cosx)
print(hdl[0].get_color())
hdl[0].set_color('#707010')
hdl[0].set_linewidth(0.5)
plt.grid('off')

Use dir() or help() or the online docs to get more info on what you can do with these.

Histograms and bar charts

For a simple histogram you can do this:

r = np.random.rand(1000)
n,bins,_ = plt.hist((r-0.5)**2, bins=30)

where it also returns the number of elements in each bin, as n, and the bin centres, as bins.

The _ in the third part on the left hand side is a shorthand for just throwing away the corresponding part of the return structure.

There is also a call for doing bar plots:

samp1 = r[0:10]
samp2 = r[10:20]
bwidth = 0.3
xcoord = np.arange(10)
plt.bar(xcoord-bwidth, samp1, width=bwidth, color='red', label='Sample 1')
plt.bar(xcoord, samp2, width=bwidth, color='blue', label='Sample 2')
plt.legend(loc='upper left')

Scatter plots

It would be possible to use plot() to create a scatter plot, but there is also an alternative: scatter()

fig, ax = plt.subplots()
# setup some sizes for each point (arbitrarily example here)
ssize = 100*abs(samp1-samp2) + 10
ax.scatter(samp1, samp2, s=ssize, alpha=0.5)
# now add the y=x line
allsamps = np.hstack((samp1,samp2))
ax.plot([min(allsamps),max(allsamps)],[min(allsamps),max(allsamps)], color='red', linestyle='--')
plt.xlim(min(allsamps),max(allsamps))
plt.ylim(min(allsamps),max(allsamps))

Note that in this case we use the first line return to get a handle to the axis, ax, and the figure ,fig. The axis can be used instead of plt in most cases, although the xlim() and ylim() calls can only be done through plt.

In general, figures and subplots can be created in matplotlib in a similar fashion to matlab, but they do not have to be explicitly invoked as you can see from the earlier examples.

Subplots

These are very similar to matlab:

plt.subplot(2, 1, 1)
plt.plot(x,cosx, '.-')
plt.xlim(-np.pi, np.pi)
plt.ylabel('Full sampling')
plt.subplot(2, 1, 2)
plt.plot(x[::30], cosx[::30], '.-')
plt.xlim(-np.pi, np.pi)
plt.ylabel('Subsampled')

Displaying images

The main command for displaying images is imshow()

import nibabel as nib
import os.path as op
nim = nib.load(op.expandvars('${FSLDIR}/data/standard/MNI152_T1_1mm.nii.gz'), mmap=False)
imdat = nim.get_data().astype(float)
imslc = imdat[:,:,70]
plt.imshow(imslc, cmap=plt.cm.gray)
plt.colorbar()
plt.grid('off')

Note that matplotlib will use the voxel data orientation, and that configuring the plot orientation is your responsibility. To rotate a slice, simply transpose the data (.T). To invert the data along along an axis, you don't need to modify the data - simply swap the axis limits around:

plt.imshow(imslc.T, cmap=plt.cm.gray)
plt.xlim(reversed(plt.xlim()))
plt.ylim(reversed(plt.ylim()))
plt.colorbar()
plt.grid('off')

3D plots

# Taken from https://matplotlib.org/gallery/mplot3d/wire3d.html#sphx-glr-gallery-mplot3d-wire3d-py

from mpl_toolkits.mplot3d import axes3d

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# Grab some test data.
X, Y, Z = axes3d.get_test_data(0.05)

# Plot a basic wireframe.
ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)

Surface renderings are many other plots are possible - see 3D examples on the matplotlib webpage


Plotting from standalone scripts

When running from a standalone script, the same matplotlib import is required, but the line %matplotlib <backend> should not be used.

In a script it is also necessary to finish with plt.show() as otherwise nothing is actually displayed. For example, the above examples would setup a plot but the actual graphic would only appear after the plt.show() command was executed. Furthermore, control is not returned to the script immediately as the plot is interactive by default.


Exercise

Find a different type of plot (e.g., boxplot, violin plot, quiver plot, pie chart, etc.), look up the documentation and then write your own code that calls this to create a plot from some data that you create yourself (i.e., don't just blindly copy example code from the docs).

# Make up some data and do the funky plot