#!/usr/bin/env python # coding: utf-8 # # Matplotlib # In[1]: get_ipython().run_line_magic('config', "InlineBackend.figure_format = 'svg'") import numpy as np import matplotlib.pyplot as plt # The first line above which begins with a `%` is called a [magic command](https://ipython.readthedocs.io/en/stable/interactive/magics.html), which here sets the figure format to svg, which is a vector graphics format but looks prettier than default format. # # There are two main approaches to use Matplotlib. The simplest one, which is somewhat similar to Matlab is described first. An object oriented approach is described in the end. # ## Single graph # $$ # f(x) = x \sin(x) \sin(50 x) # $$ # In[2]: f = lambda x: x * np.sin(x) * np.sin(50*x) n = 200 x = np.linspace(0.0,1.0,n) plt.plot(x, f(x)) plt.xlabel('x') plt.ylabel('f(x)') plt.title('Plot of f(x)') plt.grid(True) # ## Multiple graphs # In[3]: f = lambda x: x * np.sin(x) * np.sin(50*x) g = lambda x: x * np.cos(x) * np.cos(50*x) n = 200 x = np.linspace(0.0,1.0,n) plt.plot(x,f(x),x,g(x)) plt.xlabel('x') plt.ylabel('f(x)') plt.title('Plot of f(x) and g(x)') plt.legend(('f(x)','g(x)')) plt.grid(True) # The line colors are set to different values automatically, which is useful to distinguish the graphs. # # ## Control line style # # We can however control the [line style](https://matplotlib.org/stable/gallery/lines_bars_and_markers/linestyles.html) ourselves. # In[4]: f = lambda x: x * np.sin(x) * np.sin(50*x) g = lambda x: x * np.cos(x) * np.cos(50*x) n = 200 x = np.linspace(0.0,1.0,n) plt.plot(x,f(x),'r-',linewidth=2,label='f(x)') plt.plot(x,g(x),'b--',label='g(x)') plt.xlabel('x') plt.ylabel('y') plt.title('Plot of f(x) and g(x)') plt.legend() plt.grid(True) # We can also specify parameters like this # In[5]: plt.plot(x,f(x),c='red',ls='dashed',lw=2) plt.xlabel('x'); plt.ylabel('y'); # ## Show symbols # In[6]: f = lambda x: x * np.sin(x) * np.sin(50*x) g = lambda x: np.cos(x) * np.cos(50*x) n = 200 x = np.linspace(0.0,1.0,n) plt.plot(x,f(x),'k-o',markevery=10) plt.plot(x,g(x),'r--s',markevery=10) plt.xlabel('x') plt.ylabel('y') plt.title('Plot of f(x) and g(x)') plt.legend(('f(x)','g(x)'),loc='upper right') plt.grid(True) # ## Matrix of plots # In[7]: n = 200 x = np.linspace(0.0,1.0,n) y1 = np.sin(50*x) y2 = np.log(x+1) + np.tanh(x) y3 = x**2 + x * np.cos(10*x) y4 = np.cos(10*x) + np.sin(5*x) plt.figure(figsize=(10,8)) lw = 1.5 plt.subplot(221) plt.plot(x,y1,'k-',linewidth=lw) plt.xlabel('$x$'); plt.ylabel('$y_1$') plt.title('y1') plt.subplot(222) plt.plot(x,y2,'r--',linewidth=lw) plt.xlabel('$x$'); plt.ylabel('$y_2$') plt.title('y2') plt.subplot(223) plt.plot(x,y3,'g-.',linewidth=lw) plt.xlabel('$x$'); plt.ylabel('$y_3$') plt.title('y3') plt.subplot(224) plt.plot(x,y4,'b:',linewidth=lw) plt.xlabel('$x$'); plt.ylabel('$y_4$'); plt.title('y4'); # ## Plot in log scale: semilogy # # $$ # y = \exp(x), \qquad x \in [-100,0] # $$ # In[8]: n = 100 x = np.linspace(-100,0,n) y = np.exp(x) plt.plot(x,y) plt.xlabel('x'); plt.ylabel('y'); # The y axis has very small to very large values and the usual linear scale plot does not show this variation properly. We next plot the y axis in log scale. # In[9]: plt.semilogy(x,y) plt.xlabel('x'); plt.ylabel('y'); # The linear curve clearly shows the exponential character of the function. # ## Plot in log scale: loglog # # $$ # y = x^{-2}, \qquad x \in [10^{-3}, 10^{-2}] # $$ # In[10]: n = 10 x = np.linspace(1e-3,1e-2,n) y = 1.0/x**2 plt.plot(x,y,'o-') plt.xlabel('x'); plt.ylabel('y'); # The variations in both axes are too large, so we plot both axes in log scale. # In[11]: plt.loglog(x,y,'o-') plt.xlabel('x'); plt.ylabel('y'); # ## Scientific notation for tick values # In[12]: n = 100 x = np.linspace(0.1,1,n) y = 1e-4 * np.exp(x) plt.plot(x,y) plt.xlabel('x'); plt.ylabel('y'); # In[13]: plt.plot(x,y) plt.ticklabel_format(axis="y", style="sci", scilimits=(0,0)); # ## Control tick values # # Which tick values are labelled is automatically chosen by matplotlib, but we can control this ourselves. # In[14]: n = 100 x = np.linspace(0.0,1.0,n) y = np.sin(2.0*np.pi*x) plt.plot(x,y) plt.xticks([0.0, 0.25, 0.5, 0.75, 1.0]) plt.yticks([-1.0, -0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0]) plt.grid(True) # ## 2-D contour plots # $$ # \psi = \sin(2\pi x) \cos(2\pi y), \qquad (x,y) \in [0,1] \times [0,1] # $$ # In[15]: n = 100 x = np.linspace(0.0, 1.0, n) y = np.linspace(0.0, 1.0, n) X, Y = np.meshgrid(x,y) psi = np.sin(2*np.pi*X) * np.cos(2*np.pi*Y) plt.figure(figsize=(5,5)) plt.contour(X,Y,psi,levels=20) plt.xticks([0, 0.25, 0.5, 0.75, 1.0]) plt.yticks([0, 0.25, 0.5, 0.75, 1.0]) plt.xlabel('$x_1$') plt.ylabel('$x_2$') plt.grid(True) # ## 2-D filled plots # In[16]: n = 100 x = np.linspace(0.0, 1.0, n) y = np.linspace(0.0, 1.0, n) X, Y = np.meshgrid(x,y) psi = np.sin(2*np.pi*X) * np.cos(2*np.pi*Y) cf = plt.contourf(X,Y,psi,levels=20,cmap='jet') plt.colorbar(cf) plt.xticks([0, 0.25, 0.5, 0.75, 1.0]) plt.yticks([0, 0.25, 0.5, 0.75, 1.0]) plt.xlabel('$x_1$') plt.ylabel('$x_2$') plt.axis('equal') plt.grid(True) # ## 2-D surface plot # # We have use OO interface, which is explained below. # In[17]: n = 100 x = np.linspace(0.0, 1.0, n) y = np.linspace(0.0, 1.0, n) X, Y = np.meshgrid(x,y) psi = np.sin(2*np.pi*X) * np.cos(2*np.pi*Y) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') surf = ax.plot_surface(X, Y, psi, cmap='viridis', linewidth=0, antialiased=False, vmin=-1, vmax=1) fig.colorbar(surf, shrink=0.5, aspect=5) ax.set_zlim(-1.01, 1.01) ax.set_xlabel('X Label') ax.set_ylabel('Y Label'); # ## Object oriented approach* # # A single plot. # In[18]: f = lambda x: 0.5*x*np.sin(x)*np.sin(50*x) g = lambda x: 0.5*x*np.cos(x)*np.cos(50*x) n = 200 x = np.linspace(0.0,2.0,n) fig, ax = plt.subplots() ax.plot(x,f(x),'r-',linewidth=2,label='f(x)') ax.plot(x,g(x),'b--',label='g(x)') ax.set_xlabel('x') ax.set_ylabel('y') ax.set_title('Plot of f(x) and g(x)') ax.set_xlim(-0.1,2.1) ax.set_ylim(-1,1) ax.set_xticks([0,0.25,0.5,0.75,1.0,1.25,1.5,1.75,2.0]) ax.legend() ax.grid(True) ax.set_aspect('equal') ax.text(0, -0.4, '$\mu=115,\ \sigma=15$'); # A $1 \times 2$ matrix of plots. # In[19]: f = lambda x: x*np.sin(x)*np.sin(50*x) g = lambda x: x*np.cos(x)*np.cos(50*x) n = 200 x = np.linspace(0.0,1.0,n) fig, ax = plt.subplots(1,2,figsize=(8,5)) ax[0].plot(x,f(x),'r-',linewidth=2,label='f(x)') ax[0].set_xlabel('x') ax[0].set_ylabel('f(x)') ax[0].set_title('Plot of f(x)') ax[0].set_xlim(-0.1,1.1) ax[0].set_ylim(-1,1) ax[0].grid(True) ax[0].legend() ax[1].plot(x,g(x),'b--',label='g(x)') ax[1].set_xlabel('x') ax[1].set_ylabel('g(x)') ax[1].set_title('Plot of g(x)') ax[1].set_xlim(-0.1,1.1) ax[1].set_ylim(-1,1) ax[1].grid(True) ax[1].legend() fig.suptitle('Plot of f(x) and g(x)'); # We can make a $2 \times 2$ matrix of plots like this. # In[20]: f = lambda x: x*np.sin(x)*np.sin(50*x) g = lambda x: x*np.cos(x)*np.cos(50*x) n = 200 x = np.linspace(0.0,1.0,n) fig, ax = plt.subplots(2,2,figsize=(8,5)) ax[0,0].plot(x,f(x),'r-',linewidth=2,label='f') ax[0,0].set_xlabel('x') ax[0,0].set_ylabel('f(x)') ax[0,0].set_title('Plot of f(x)') ax[0,0].set_xlim(-0.1,1.1) ax[0,0].set_ylim(-1,1) ax[0,0].grid(True) ax[0,0].legend() ax[0,1].plot(x,g(x),'b--',label='g') ax[0,1].set_xlabel('x') ax[0,1].set_ylabel('g(x)') ax[0,1].set_title('Plot of g(x)') ax[0,1].set_xlim(-0.1,1.1) ax[0,1].set_ylim(-1,1) ax[0,1].grid(True) ax[0,1].legend() ax[1,0].plot(x,f(x)-g(x),'r-',linewidth=2,label='f-g') ax[1,0].set_xlabel('x') ax[1,0].set_ylabel('f(x)-g(x)') ax[1,0].set_title('Plot of f(x)-g(x)') ax[1,0].set_xlim(-0.1,1.1) ax[1,0].set_ylim(-1,1) ax[1,0].grid(True) ax[1,0].legend() ax[1,1].plot(x,f(x)+g(x),'b--',label='f+g') ax[1,1].set_xlabel('x') ax[1,1].set_ylabel('f(x)+g(x)') ax[1,1].set_title('Plot of f(x)+g(x)') ax[1,1].set_xlim(-0.1,1.1) ax[1,1].set_ylim(-1,1) ax[1,1].grid(True) ax[1,1].legend() fig.suptitle('2x2 matrix of plots');