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 matplotlibReference
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 pltimport 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 plottedplt.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 * 10plt.figure(figsize = (10, 10))# Add gridplt.grid() # Titleplt.title("Waves")# Lables for X & Y axesplt.xlabel("Time")plt.ylabel("Amplitude")# 'o-' does not mean orange line rather than circle dots# '^' means triangle dots# line labels are also setplt.plot(x, y1, '^-', label="Line1", color='orange') plt.plot(x, y2, 'b--', label="Line2")# Show the labelsplt.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, 3y = np.sin(x[:, np.newaxis] + np.pi * np.arange(0, 2, 0.5))y.shapeplt.figure()plt.plot(x, y)plt.figure()lines = plt.plot(x, y[:, 0:2])# Another way to set labelsplt.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 offSee 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 functiondef 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 Hzplt.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 axisplt.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 titleplt.suptitle("Common title")Scatter plots
plt.plot(x, y, 'o')Ref: Python Data Science Handbook
# Using plot() functionplt.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 mappingplt.scatter(x, y, c=colors, s=sizes, alpha=0.3, cmap='viridis')# show color scale barplt.colorbar()Error bar
plt.errorbar(x, y, yerr=dy, fmt='.k')See also: errorbar
# Data #x = np.linspace(0, 10, 50) # Inputdy = 0.8 # Uncertainty levely = np.sin(x) + dy * np.random.randn(50) # Output with uncertainty# Plot #plt.figure()# xerr or yerr parameter to set error barsplt.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 mapplt.contour(X, Y, Z, 20, cmap='RdGy')plt.figure()# contourf() for filled countor plotplt.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 plotplt.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 barimport numpy as npimport matplotlib.pyplot as pltimport matplotlib as mpl# Data #x = np.linspace(0, 10, 1000) # 1000 * 1I = np.sin(x) * np.cos(x[:, np.newaxis]) # 1000 * 1000speckles = (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 subplotaxs[0].set_title('Without limit')im0 = axs[0].imshow(I, cmap='RdBu')cb0 = plt.colorbar(im0, ax=axs[0], orientation='horizontal')# Right subplotaxs[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 sysimport numpy as npimport matplotlib.pyplot as pltfrom matplotlib.patches import Circle# Mean magnitude of the Earth's magnetic field at the equator in TB0 = 3.12e-5# Radius of Earth, Mm (10^6 m: mega-metres!)RE = 6.370# Deviation of magnetic pole from axisalpha = 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 gridnx, ny = 64, 64XMAX, YMAX = 40, 40x = 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 componentsBr, 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 * cBy = Btheta * c + Br * sfig, ax = plt.subplots()# Plot the streamlines with an appropriate colormap and arrow stylecolor = 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 exampleimport numpy as npimport matplotlib.pyplot as plt# Set limits and number of points in gridy, x = np.mgrid[10:-10:100j, 10:-10:100j]x_obstacle, y_obstacle = 0.0, 0.0alpha_obstacle, a_obstacle, b_obstacle = 1.0, 1e3, 2e3p = -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 plotfig, 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 plotfrom matplotlib.patheffects import withStrokefig, 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 propertyplt.annotate("fixed arrow", (0.8,0.8),xycoords='axes fraction', xytext=(0.5,0.5),textcoords='axes fraction', arrowprops = dict(arrowstyle="->") )# plt.show()