#!/usr/bin/env python
# coding: utf-8
# #### **Author**: `marimuthu(mario)` [[@kmario23](https://github.com/kmario23)]
#
# ## **A crash course on Matplotlib**
# Matplotlib is a Python library for data visualization (2D/3D-graphics, animation etc.). It provides publication-quality figures in many formats. We will explore matplotlib in interactive mode covering most common cases in this tutorial.
# In[1]:
# mandatory imports
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # for 3D plotting
# `pyplot` provides a convenient interface to the matplotlib object-oriented plotting library. It is modeled closely after MATLAB. Therefore, the majority of plotting commands in pyplot have MATLAB analogs with similar arguments. Important commands are explained with interactive examples.
# In[2]:
# check version
matplotlib.__version__
# Let's now see a simple plotting and understand the ingredients that goes into customizing our plot as per our will and wish.
# ## **Simple curve plot**
# In[3]:
# get 10 linearly spaced points in the interval [0, 5)
x = np.linspace(0, 5, 10)
y = x ** 2
# create a figure/canvas of desired size
plt.figure(figsize=(8, 6))
# plot values; with a color `red`
plt.plot(x, y, 'r')
# give labels to the axes
plt.xlabel('x')
plt.ylabel('y')
# give a title to the plot
plt.title(r"Plot of $y=x^2$")
plt.show()
# ### **Cosine & Sine Plot**
#
# Starting with default settings, we would like to draw a `cosine` and `sine` functions on the same plot. Then, we will make it look prettier by customizing the default settings.
# In[4]:
# 256 linearly spaced values between -pi and +pi
# both endpoints would be included; check (X[0], X[-1])
X = np.linspace(-np.pi, np.pi, 256, endpoint=True)
# compute cosine and sin values
C, S = np.cos(X), np.sin(X)
# plot both curves
plt.plot(X, C)
plt.plot(X, S)
# show the plot
plt.show()
# #### The above plot doesn't seem too appealing. So, let's customizing the default settings a bit.
#
# *Matplotlib* allows the aspect ratio, DPI and figure size to be specified when the Figure object is created, using the `figsize` and `dpi` keyword arguments. `figsize` is a tuple of the `width` and `height` of the figure in inches, and `dpi` is the dots-per-inch (pixel per inch). To create an 800x600 pixel, 100 dots-per-inch figure, we can do:
# In[5]:
# Create a new figure of size 800x600, using 100 dots per inch
plt.figure(figsize=(8, 6), dpi=100)
# Create a new subplot from a grid of 1x1
plt.subplot(111)
# Now, plot `cosine` using `blue` color with a continuous line of width 1 (pixel)
plt.plot(X, C, color="blue", linewidth=1.0, linestyle="-")
# And plot `sine` using `green` color with a continuous line of width 1 (pixel)
plt.plot(X, S, color="green", linewidth=1.0, linestyle="-")
# Set x limits to [-4, +4]
plt.xlim(-4.0, 4.0)
# Set y limits to [-1, +1]
plt.ylim(-1.0, 1.0)
# optionally, save the figure as a pdf using 72 dots per inch
plt.savefig("./sine_cosine.pdf", format='pdf', dpi=72)
# show grid
plt.grid(True)
# Show the plot on the screen
plt.show()
# --------
#
# ## **setting axes limits**
#
# Instead of hard-coding the `xlim` and `ylim` values, we can take these values from the array itself and then set the limits accordingly.
# We can also change the `linewidth` and `color` kwargs as per our wish.
# In[6]:
# set figure size and dpi (dots per inch)
plt.figure(figsize=(10, 6), dpi=80)
# Create a new subplot from a grid of 1x1
plt.subplot(111)
# customize color and line width
plt.plot(X, C, color="blue", linewidth=2.5, linestyle="-")
plt.plot(X, S, color="red", linewidth=2.5, linestyle="-")
# set lower & upper bound by taking min & max value respectively
plt.xlim(X.min()*1.1, X.max()*1.1)
plt.ylim(C.min()*1.1, C.max()*1.1)
# optionally, save the figure as a pdf using 72 dots per inch
plt.savefig("./sine_cosine.pdf", format='pdf', dpi=80)
# show it on screen
plt.show()
# ## **setting axes ticks**
# In[7]:
# set figure size and dpi (dots per inch)
plt.figure(figsize=(10, 6), dpi=80)
# Create a new subplot from a grid of 1x1
plt.subplot(111)
# customize color and line width
plt.plot(X, C, color="blue", linewidth=2.5, linestyle="-")
plt.plot(X, S, color="red", linewidth=2.5, linestyle="-")
# set lower & upper bound by taking min & max value respectively
plt.xlim(X.min()*1.1, X.max()*1.1)
plt.ylim(C.min()*1.1, C.max()*1.1)
# provide five tick values for x and 3 for y
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
plt.yticks([-1, 0, +1])
# optionally, save the figure as a pdf using 72 dots per inch
plt.savefig("./sine_cosine.pdf", format='pdf', dpi=80)
# show it on screen
plt.show()
# ## **setting axes tick labels**
#
# We fixed the aexs ticks but their label is not very explicit. We could guess that 3.142 is π but it would be better to make it explicit. When we set tick values, we can also provide a corresponding label in the second argument list. Note that we'll use latex to allow for nice rendering of the label.
# In[8]:
# set figure size and dpi (dots per inch)
plt.figure(figsize=(10, 6), dpi=80)
# Create a new subplot from a grid of 1x1
plt.subplot(111)
# customize color and line width
plt.plot(X, C, color="blue", linewidth=2.5, linestyle="-")
plt.plot(X, S, color="red", linewidth=2.5, linestyle="-")
# set lower & upper bound by taking min & max value respectively
plt.xlim(X.min()*1.1, X.max()*1.1)
plt.ylim(C.min()*1.1, C.max()*1.1)
# provide five tick values for x and 3 for y
# and pass the corresponding label as a second argument.
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi],
[r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$'])
plt.yticks([-1, 0, +1],
[r'$-1$', r'$0$', r'$+1$'])
# optionally, save the figure as a pdf using 72 dots per inch
plt.savefig("./sine_cosine.pdf", format='pdf', dpi=80)
# show it on screen
plt.show()
# ## **Adding legends**
# In[9]:
# set figure size and dpi (dots per inch)
plt.figure(figsize=(10, 6), dpi=80)
# Create a new subplot from a grid of 1x1
plt.subplot(111)
# customize color and line width
# `label` is essential for `plt.legend` to work
plt.plot(X, C, color="blue", linewidth=2.5, linestyle="-", label="cosine")
plt.plot(X, S, color="red", linewidth=2.5, linestyle="-", label="sine")
# set lower & upper bound by taking min & max value respectively
plt.xlim(X.min()*1.1, X.max()*1.1)
plt.ylim(C.min()*1.1, C.max()*1.1)
# provide five tick values for x and 3 for y
# and pass the corresponding label as a second argument.
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi],
[r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$'])
plt.yticks([-1, 0, +1],
[r'$-1$', r'$0$', r'$+1$'])
# show legend on the upper left side of the axes
plt.legend(loc='upper left', frameon=False)
# optionally, save the figure as a pdf using 72 dots per inch
plt.savefig("./sine_cosine.pdf", format='pdf', dpi=80)
# show it on screen
plt.show()
# ----------
#
# ### **Figure and Subplots**
#
# **Figure**
#
# A figure is the windows in the GUI that has "Figure #" as title. Figures are numbered starting from 1 as opposed to the normal Python way starting from 0. There are several parameters that determine how the figure looks like.
#
# | Argument | Default |Description |
# |----------|:-------------:|------:|
# | num | 1 | number of figure |
# | figsize |figure.figsize | figure size in in inches (width, height)|
# | dpi |figure.dpi | resolution in dots per inch|
# |facecolor |figure.facecolor|color of the drawing background|
# |edgecolor |figure.edgecolor|color of edge around the drawing background|
# |frameon |True | draw figure frame or not |
# **Subplot**
#
# With subplot you can arrange plots in a regular grid. You need to specify the number of rows and columns and the number of the plot.
# Grid subplot ,
# Horizontal subplot , and
# Vertical subplot
#
#
#
#
# The following plot shows how to use the *figure title*, *axis labels*, and *legends* in a subplot:
# In[18]:
x = np.linspace(0, 5, 10)
y = x ** 2
fig, axes = plt.subplots(1, 2, figsize=(8,4), dpi=100)
# plot subplot 1
axes[0].plot(x, x**2, color="green", label="y = x**2")
axes[0].plot(x, x**3, color="red", label="y = x**3")
axes[0].legend(loc=2); # upper left corner
axes[0].set_xlabel('x')
axes[0].set_ylabel('y')
axes[0].set_title('Plot of y=x^2 and y=x^3')
# plot subplot 2
axes[1].plot(x, x**2, color="violet", label="y = x**2")
axes[1].plot(x, x**3, color="blue", label="y = x**3")
axes[1].legend(loc=2); # upper left corner
axes[1].set_xlabel('x')
axes[1].set_ylabel('y')
axes[1].set_title('Plot of y=x^2 and y=x^3')
# `fig.tight_layout()` automatically adjusts the positions of the axes on the figure canvas so that there is no overlapping content
# comment this out to see the difference
fig.tight_layout()
plt.show()
# ## **Formatting text: LaTeX, fontsize, font family**
#
# Matplotlib has great support for $LaTeX$. All we need to do is to use dollar signs encapsulate LaTeX in any text (legend, title, label, etc.). For example, `"$y=x^3$"`.
#
# But here we might run into a slightly subtle problem with $LaTeX$ code and Python text strings. In $LaTeX$, we frequently use the backslash in commands, for example `\alpha` to produce the symbol α. But the backslash already has a meaning in Python strings (the escape code character). To avoid Python messing up our latex code, we need to use "raw" text strings. Raw text strings are prepended with an `'r'`, like `r"\alpha"` or `r'\alpha'` instead of `"\alpha"` or `'\alpha'`:
# In[19]:
fig, ax = plt.subplots(figsize=(8,4), dpi=100)
ax.plot(x, x**2, label=r"$y = \alpha^2$")
ax.plot(x, x**3, label=r"$y = \alpha^3$")
ax.legend(loc=2) # upper left corner
ax.set_xlabel(r'$\alpha$', fontsize=18)
ax.set_ylabel(r'$y$', fontsize=18)
ax.set_title(r'Plot of y=$\alpha^{2}$ and y=$\alpha^{3}$')
plt.show()
# ## **Line and marker styles**
#
# To change the line width, we can use the `linewidth` or `lw` keyword argument. The line style can be selected using the `linestyle` or `ls` keyword arguments:
# In[20]:
fig, ax = plt.subplots(figsize=(12,6))
# possible marker symbols: marker = '+', 'o', '*', 's', ',', '.', '1', '2', '3', '4', ...
ax.plot(x, x+ 9, color="green", lw=2, ls='--', marker='+')
ax.plot(x, x+10, color="green", lw=2, ls='--', marker='o')
ax.plot(x, x+11, color="green", lw=2, ls='--', marker='s')
ax.plot(x, x+12, color="green", lw=2, ls='--', marker='1')
plt.show()
# ## **Logarithmic scale**
# It is also possible to set a logarithmic scale for one or both axes. This functionality is in fact only one application of a more general transformation system in Matplotlib. Each of the axes' scales are set seperately using `set_xscale` and `set_yscale` methods which accept one parameter (with the value `"log"` in this case):
#
# In[21]:
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
# plot normal scale
axes[0].plot(x, np.exp(x), color="red")
axes[0].plot(x, x**2, color="green")
axes[0].set_title("Normal scale")
axes[0].grid() # show grid
# plot `log` scale
axes[1].plot(x, np.exp(x), color="blue")
axes[1].plot(x, x**2, color="violet")
axes[1].set_yscale("log")
axes[1].set_title("Logarithmic scale (y)")
axes[1].grid() # show grid
fig.tight_layout()
plt.show()
# ## **Histogram plot**
# In[22]:
n = np.random.randn(100000)
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
# plot default histogram
axes[0].hist(n, color="blue")
axes[0].set_title("Default histogram")
axes[0].set_xlim((np.min(n), np.max(n)))
# plot cumulative histogram
axes[1].hist(n, cumulative=True, bins=50, color="green")
axes[1].set_title("Cumulative detailed histogram")
axes[1].set_xlim((np.min(n), np.max(n)))
fig.tight_layout()
plt.show()
#
# ## **Common types of plots**
#
# - **Scatter plot**
# A simple scatter plot of random values drawn from the standard Gaussian distribution.
# In[24]:
# set figure size and dpi (dots per inch)
plt.figure(figsize=(10, 6), dpi=80)
# Create a new subplot from a grid of 1x1
plt.subplot(111)
n = 1024
X = np.random.normal(0,1,n)
Y = np.random.normal(0,1,n)
# color is given by the angle between X & Y
T = np.arctan2(Y,X)
plt.axes([0.025, 0.025, 0.95, 0.95])
# The alpha blending value, between 0 (transparent) and 1 (opaque).
# s - marker size
# c - color
plt.scatter(X,Y, s=75, c=T, alpha=.5)
plt.xlim(-2.0, 2.0), plt.xticks([])
plt.ylim(-2.0, 2.0), plt.yticks([])
plt.show()
# --------
#
# - **Contour plot**
# A contour plot represents a 3-dimensional surface by plotting constant z slices, called contours, on a 2-dimensional grid.
# In[25]:
# set figure size and dpi (dots per inch)
plt.figure(figsize=(10, 6), dpi=80)
# Create a new subplot from a grid of 1x1
plt.subplot(111)
def f(x,y):
return (1-x/2+x**5+y**3)*np.exp(-x**2-y**2)
n = 256
x = np.linspace(-3, 3, n)
y = np.linspace(-3, 3, n)
X,Y = np.meshgrid(x, y)
plt.axes([0.025, 0.025, 0.95, 0.95])
plt.contourf(X, Y, f(X,Y), 8, alpha=.75, cmap=plt.cm.hot)
C = plt.contour(X, Y, f(X,Y), 8, colors='black')
plt.clabel(C, inline=1, fontsize=10)
plt.xticks([]), plt.yticks([])
plt.show()
# --------
#
# - **3D plot**
# Represent a 3-dimensional surface. To use 3D graphics in matplotlib, we first need to create an axes instance of the class `Axes3D`. 3D axes can be added to a matplotlib figure canvas in exactly the same way as 2D axes, but a conventient way to create a 3D axis instance is to use the projection='3d' keyword argument to the add_axes or add_subplot functions.
#
# Note: You can't rotate the plot in jupyter notebook. Plot it as a standalone module to zoom around and visualize it by rotating.
# In[26]:
# create figure and set figure size and dpi (dots per inch)
fig = plt.figure(figsize=(10, 6), dpi=80)
ax = Axes3D(fig)
# inputs
X = np.arange(-4, 4, 0.25)
Y = np.arange(-4, 4, 0.25)
X, Y = np.meshgrid(X, Y)
# 3D surface
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=plt.cm.hot)
ax.contourf(X, Y, Z, zdir='z', offset=-2, cmap=plt.cm.hot)
# set z axis limit
ax.set_zlim(-3, 3)
plt.show()
# --------
#
# - **3D Surface Plot**
# In[27]:
alpha = 0.7
phi_ext = 2 * np.pi * 0.5
def flux_qubit_potential(phi_m, phi_p):
return 2 + alpha - 2 * np.cos(phi_p)*np.cos(phi_m) - alpha * np.cos(phi_ext - 2*phi_p)
phi_m = np.linspace(0, 2*np.pi, 100)
phi_p = np.linspace(0, 2*np.pi, 100)
X,Y = np.meshgrid(phi_p, phi_m)
Z = flux_qubit_potential(X, Y).T
# In[28]:
fig = plt.figure(figsize=(25, 10))
# `ax` is a 3D-aware axis instance, because of the projection='3d' keyword argument to add_subplot
ax = fig.add_subplot(1, 2, 1, projection='3d')
p = ax.plot_surface(X, Y, Z, rstride=4, cstride=4, linewidth=0)
# surface_plot with color grading and color bar
ax = fig.add_subplot(1, 2, 2, projection='3d')
p = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=plt.cm.coolwarm, linewidth=0, antialiased=False)
cb = fig.colorbar(p, shrink=0.5)
plt.show()
# --------
#
# - **3D Wireframe Plot**
# In[29]:
fig = plt.figure(figsize=(25, 10))
# `ax` is a 3D-aware axis instance, because of the projection='3d' keyword argument to add_subplot
ax = fig.add_subplot(1, 1, 1, projection='3d')
# create and plot a wireframe
p = ax.plot_wireframe(X, Y, Z, rstride=4, cstride=4)
plt.show()
# --------
#
# - **Coutour plots with axis level projections**
# In[30]:
fig = plt.figure(figsize=(18, 8))
# `ax` is a 3D-aware axis instance, because of the projection='3d' keyword argument to add_subplot
ax = fig.add_subplot(1, 1, 1, projection='3d')
ax.plot_surface(X, Y, Z, rstride=4, cstride=4, alpha=0.25)
cset = ax.contour(X, Y, Z, zdir='z', offset=-np.pi, cmap=plt.cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='x', offset=-np.pi, cmap=plt.cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='y', offset=3*np.pi, cmap=plt.cm.coolwarm)
ax.set_xlim3d(-np.pi, 2*np.pi);
ax.set_ylim3d(0, 3*np.pi);
ax.set_zlim3d(-np.pi, 2*np.pi);
plt.show()
# **Changing viewing angle**
# - We can change the perspective of a 3D plot using the `view_init` function, which takes two arguments: the elevation and the azimuth angles (unit degrees)
# In[31]:
fig = plt.figure(figsize=(8, 8))
# `ax` is a 3D-aware axis instance, because of the projection='3d' keyword argument to add_subplot
ax = fig.add_subplot(2, 1, 1, projection='3d')
ax.plot_wireframe(X, Y, Z, rstride=4, cstride=4, alpha=0.25)
ax.view_init(30, 45)
# `ax` is a 3D-aware axis instance, because of the projection='3d' keyword argument to add_subplot
ax = fig.add_subplot(2,1,2, projection='3d')
ax.plot_wireframe(X, Y, Z, rstride=4, cstride=4, alpha=0.25)
ax.view_init(70, 30)
fig.tight_layout()
# ## **Reference**
#
# - Adapted slightly from [Scipy-matplotlib-guide](http://www.scipy-lectures.org/intro/matplotlib/)