A quick introduction to plotting in Python
Matplotlib (MPL) is the default choice, with other options including Seaborn for high-level plotting, Plotly for JS plotting framework, Bokeh for interactive plotting.
Installation
Matplotlib is included in the Anaconda distribution.
Install it via conda
if you have not (e.g. a miniconda distribution)
conda install matplotlib
or by pip
if you're not using conda at all.
pip install matplotlib
Reference
Matplotlib Tutorial – A Complete Guide to Python Plot w/ Examples
Matplotlib Tutorial: Learn the basics of Python’s powerful Plotting library
Conventional short names for matplotlib
and numpy
import matplotlib.pyplot as plt
import numpy as np
# For inline plotting in jupyter notebooks
%matplotlib inline
Anatomy of a figure (from mpl official website)

Line plots
Line plots are usually for visualization of 2D data e.g. time series (y-t) and phase plots (x-y)
plt.plot(x, y)
# Data #
x = np.linspace(0, 10, num=100)
y1 = np.sin(x)
y2 = np.cos(x)
# Opens a new figure to be plotted
plt.figure()
# plot(x, y, <MATLAB stylestring>)
plt.plot(x, y1, '-')
plt.plot(x, y2, '--')
# Save figure to disk
fig.savefig('./plots/plt-fig1.png')
Adding more options to the plot.
# Let's add some more options
# Set figure (whole picture) size to 10 * 10
plt.figure(figsize = (10, 10))
# Add grid
plt.grid()
# Title
plt.title("Waves")
# Lables for X & Y axes
plt.xlabel("Time")
plt.ylabel("Amplitude")
# 'o-' does not mean orange line rather than circle dots
# '^' means triangle dots
# line labels are also set
plt.plot(x, y1, '^-', label="Line1", color='orange')
plt.plot(x, y2, 'b--', label="Line2")
# Show the labels
plt.legend(loc='upper left')
Multiple series
1 column = 1 series of data
# Data #
x = np.linspace(0, 10, 100)
# 4 columns of data = 4 series
# y = sin(x + 0.5k * pi); k = 0, 1, 2, 3
y = np.sin(x[:, np.newaxis] + np.pi * np.arange(0, 2, 0.5))
y.shape
plt.figure()
plt.plot(x, y)
legend()
to activate line labels
plt.figure()
lines = plt.plot(x, y[:, 0:2])
# Another way to set labels
plt.legend(lines, ['First', 'Second'], loc='upper right')
More on
Tweaking Axis ticks
Logarithmic scale
plt.xscale('log')
Hiding ticks From stack overflow
plt.tick_params(
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False, # ticks along the top edge are off
labelbottom=False) # labels along the bottom edge are off
More on: axes()
# Bode plot example
# Define a transfer function
def H(w):
wc = 4000*np.pi
return 1.0 / (1.0 + 1j * w / wc)
freq = np.logspace(1,5) # frequencies from 10**1 to 10**5 Hz
plt.figure()
plt.plot(freq, 20*np.log10(abs(H(2*np.pi*freq))))
plt.xscale('log')
plt.xlabel('Frequency (Hz)')
plt.ylabel('dB')
plt.tick_params(
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False, # ticks along the top edge are off
labelbottom=False) # labels along the bottom edge are off
Multiple subplots
# MATLAB style
# subplot(rows, columns, panel number)
plt.subplot(2, 1, 1)
plt.plot(x, y1)
# create the second panel and set current axis
plt.subplot(2, 1, 2)
plt.plot(x, y2)
The usage of subplots (object-oriented way) is sometimes simpler.
fig, ax = plt.subplots(nrows, ncols, figsize=(n, m))
# OO style (recommended)
fig, ax = plt.subplots(2)
# Plot for each axes (an unit in the figure)
ax[0].plot(x, y1)
ax[0].set_title("Upper panel")
ax[1].plot(x, y2)
ax[1].set_title("Lower panel")
# Common title
plt.suptitle("Common title")
Scatter plots
plt.plot(x, y)
Ref: Python Data Science Handbook
# Using plot() function
plt.figure()
x = np.linspace(0, 10)
y1 = np.sin(x)
plt.plot(x, y1, 'o', color='black')
# Same as plt.scatter(x, y1, marker='o', color='black')
Color map (cmap) and colorbar()
plt.scatter(x, y, c=colors)
plt.colorbar()
More on colormaps and colorbar
# Data #
rng = np.random.RandomState(0)
x = rng.randn(100)
y = rng.randn(100)
colors = rng.rand(100)
sizes = 1000 * rng.rand(100)
# Plot #
plt.figure()
# cmap for color mapping
plt.scatter(x, y, c=colors, s=sizes, alpha=0.3, cmap='viridis')
# show color scale bar
plt.colorbar()
Error bar
plt.errorbar(x, y, yerr=dy, fmt='.k')
More on errorbar
# Data #
x = np.linspace(0, 10, 50) # Input
dy = 0.8 # Uncertainty level
y = np.sin(x) + dy * np.random.randn(50) # Output with uncertainty
# Plot #
plt.figure()
# xerr or yerr parameter to set error bars
plt.errorbar(x, y, yerr=dy, fmt='.k')
Contour plots
plt.contour(X, Y, Z)
More on contour()
# data #
def f(x, y):
return np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
x = np.linspace(0, 5, 50)
y = np.linspace(0, 5, 40)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
# plot #
plt.figure()
plt.contour(X, Y, Z)
plt.figure()
# Change color map
plt.contour(X, Y, Z, 20, cmap='RdGy')
plt.figure()
# contourf() for filled countor plot
plt.contourf(X, Y, Z, 20, cmap='RdGy')
plt.colorbar()
plt.figure()
contours = plt.contour(X, Y, Z, 3, colors='black')
# Add labels of levels in the contour plot
plt.clabel(contours, inline=True, fontsize=8)
# Render image on the plot (faster but lower quality)
plt.imshow(Z, extent=[0, 5, 0, 5], origin='lower', cmap='RdGy', alpha=0.5)
plt.colorbar()
More on imshow()
#### set_clim() to set limits on the values in the color bar
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
# Data #
x = np.linspace(0, 10, 1000) # 1000 * 1
I = np.sin(x) * np.cos(x[:, np.newaxis]) # 1000 * 1000
speckles = (np.random.random(I.shape) < 0.01)
I[speckles] = np.random.normal(0, 3, np.count_nonzero(speckles))
# Figure #
fig, axs = plt.subplots(ncols=2, figsize=(10, 5))
# Left subplot
axs[0].set_title('Without limit')
im0 = axs[0].imshow(I, cmap='RdBu')
cb0 = plt.colorbar(im0, ax=axs[0], orientation='horizontal')
# Right subplot
axs[1].set_title('With limit')
im1 = axs[1].imshow(I, cmap='RdBu')
im1.set_clim(-1, 1)
cb1 = plt.colorbar(im1, ax=axs[1], extend='both', orientation='horizontal')
Plotting vector fields (quiver / streamplot plot)
Source: https://scipython.com/blog/visualizing-the-earths-magnetic-field/
More on: quiver(), streamplot()
Another example: https://stackoverflow.com/questions/25342072/computing-and-drawing-vector-fields
import sys
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
# Mean magnitude of the Earth's magnetic field at the equator in T
B0 = 3.12e-5
# Radius of Earth, Mm (10^6 m: mega-metres!)
RE = 6.370
# Deviation of magnetic pole from axis
alpha = np.radians(9.6)
def B(r, theta):
"""Return the magnetic field vector at (r, theta)."""
fac = B0 * (RE / r)**3
return -2 * fac * np.cos(theta + alpha), -fac * np.sin(theta + alpha)
# Grid of x, y points on a Cartesian grid
nx, ny = 64, 64
XMAX, YMAX = 40, 40
x = np.linspace(-XMAX, XMAX, nx)
y = np.linspace(-YMAX, YMAX, ny)
X, Y = np.meshgrid(x, y)
r, theta = np.hypot(X, Y), np.arctan2(Y, X)
# Magnetic field vector, B = (Ex, Ey), as separate components
Br, Btheta = B(r, theta)
# Transform to Cartesian coordinates: NB make North point up, not to the right.
c, s = np.cos(np.pi/2 + theta), np.sin(np.pi/2 + theta)
Bx = -Btheta * s + Br * c
By = Btheta * c + Br * s
fig, ax = plt.subplots()
# Plot the streamlines with an appropriate colormap and arrow style
color = 2 * np.log(np.hypot(Bx, By))
ax.streamplot(x, y, Bx, By, color=color, linewidth=1, cmap=plt.cm.inferno,
density=2, arrowstyle='->', arrowsize=1.5)
# Add a filled circle for the Earth; make sure it's on top of the streamlines.
ax.add_patch(Circle((0,0), RE, color='b', zorder=100))
ax.set_xlabel('$x$')
ax.set_ylabel('$y$')
ax.set_xlim(-XMAX, XMAX)
ax.set_ylim(-YMAX, YMAX)
ax.set_aspect('equal')
# Another vector field example
import numpy as np
import matplotlib.pyplot as plt
# Set limits and number of points in grid
y, x = np.mgrid[10:-10:100j, 10:-10:100j]
x_obstacle, y_obstacle = 0.0, 0.0
alpha_obstacle, a_obstacle, b_obstacle = 1.0, 1e3, 2e3
p = -alpha_obstacle * np.exp(-((x - x_obstacle)**2 / a_obstacle + (y - y_obstacle)**2 / b_obstacle))
# For the absolute values of "dx" and "dy" to mean anything, we'll need to
# specify the "cellsize" of our grid. For purely visual purposes, though,
# we could get away with just "dy, dx = np.gradient(p)".
dy, dx = np.gradient(p)
fig, ax = plt.subplots()
ax.quiver(x, y, dx, dy, p)
ax.set(aspect=1, title='Quiver Plot')
# Quiver plot with less density (draw every 3rd point)
skip = (slice(None, None, 3), slice(None, None, 3))
fig, ax = plt.subplots()
ax.quiver(x[skip], y[skip], dx[skip], dy[skip], p[skip])
ax.set(aspect=1, title='Quiver Plot (3rd points)')
# Streamplot with contour plot
fig, ax = plt.subplots()
ax.streamplot(x, y, dx, dy, color=p, density=0.5, cmap='gist_earth')
cont = ax.contour(x, y, p, cmap='gist_earth')
ax.clabel(cont)
ax.set(aspect=1, title='Streamplot with contours')
# Streamplot with stroke + contour plot
from matplotlib.patheffects import withStroke
fig, ax = plt.subplots()
ax.streamplot(x, y, dx, dy, linewidth=500*np.hypot(dx, dy),color=p, density=1.2, cmap='gist_earth')
cont = ax.contour(x, y, p, cmap='gist_earth', vmin=p.min(), vmax=p.max())
labels = ax.clabel(cont)
plt.setp(labels, path_effects=[withStroke(linewidth=8, foreground='w')])
ax.set(aspect=1, title='Streamplot with contours and strokes')