Plotting tutorial (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 by default.
In case it's not available, just run
conda install matplotlib
Reference
Matplotlib Tutorial – A Complete Guide to Python Plot w/ Examples
Matplotlib Tutorial: Learn the basics of Python’s powerful Plotting library
Anatomy of a figure (from mpl official website)
Conventional short names for matplotlib
and numpy
:
import matplotlib.pyplot as plt
import numpy as np
# For inline plotting in jupyter notebooks
%matplotlib inline
Line plots
Line plots are usually for visualization of 2D data.
e.g. time series (y-t), phase plots (x-y)
plt.plot(xs, ys)
See also
# 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, '--')
Add more things 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')
Line customization
color: https://xkcd.com/color/rgb/
line/marker style: https://www.labri.fr/perso/nrougier/teaching/matplotlib/#figures-subplots-axes-and-ticks
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)
plt.figure()
lines = plt.plot(x, y[:, 0:2])
# Another way to set labels
plt.legend(lines, ['First', 'Second'], loc='upper right')
Tweaking Axis ticks
Logarithmic scale
plt.xscale('log')
Hiding ticks. @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
See also: axes()
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
# Bode plot example
# 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')
Multiple subplots
One could use MATLAB-style to define the subplots.
But the object-oriented way is even better. See 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)
# 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, 'o')
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()
See also 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')
See also: 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)
See also contour()
and imshow()
# 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()
#### 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')
anotations
anotations: https://matplotlib.org/tutorials/text/annotations.html#plotting-guide-annotation
data = np.random.rand(10)
plt.plot(data)
plt.annotate("Text",(2,0.5),(1,0.2),arrowprops= dict())
plt.annotate("peak",
(np.where(data==data.max())[0][0],data.max()), # where to point
xycoords='data',
xytext=(np.where(data==data.max())[0][0]+1,data.max()-0.1), # where to put text
arrowprops = dict(facecolor="grey",shrink=0.09)) # arrow property
plt.annotate("fixed arrow",
(0.8,0.8),xycoords='axes fraction',
xytext=(0.5,0.5),textcoords='axes fraction',
arrowprops = dict(arrowstyle="->")
)
# plt.show()