In this post, we explain
- The basics of phase portraits of dynamical systems and state-space models.
- How to plot phase portraits in Python
A YouTube video accompanying this tutorial is given below.
The GitHub page with the codes presented in this tutorial is given here. Besides this tutorial, we created a tutorial on how to generate phase portraits of dynamical systems in MATLAB. The MATLAB tutorial is given here.
Basics of Phase Portraits of Dynamical Systems
For example, consider the following dynamical system:
(1)
This is a state-space model a dynamical system with two state-space variables
An arrow at a certain point is actually a tangent to the state-space trajectory at that point. Loosely speaking, during the small time interval, the direction of the arrow denotes the direction of the state-space trajectory evolution at a particular point.
Besides learning how to plot a phase portrait of a dynamical system, you will learn how to plot a particular state-space trajectory obtained by simulating (1) from a given initial state. A simulated state trajectory (red line) is shown in Figure 2 below. This state-space trajectory is generated for the initial conditions
Let us now explain the main idea for constructing phase portraits. Consider the general form of a state-space model of a dynamical system:
(2)
The vector
The components of the tangent vector
Python Code for Generating Phase Portraits
The first step is to import the necessary libraries and functions and to define a function that corresponds to the right-hand side of our state-space model. The code is given below.
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import numpy as np
# first create create a function that evaluates the right-hand-side of the
# state-space equations for a given state vector
# x is the current state vector
# t is current simulation time
def dynamicsStateSpace(x,t):
dxdt=[-x[0]-3*x[1],3*x[0]-x[1]]
return dxdt
The function “odeint” is used for simulating the state-space trajectory and for generating Fig. 2 at the beginning of the tutorial. For a given state vector
The next step is to define a grid of points at which we will compute the tangent vectors. After we define the grid, we compute the tangent vectors. This is performed by the following code
# next, define a grid of points at which we will show arrows
x0=np.linspace(-2,2,20)
x1=np.linspace(-2,3,20)
# create a grid
X0,X1=np.meshgrid(x0,x1)
# projections of the trajectory tangent vector
dX0=np.zeros(X0.shape)
dX1=np.zeros(X1.shape)
shape1,shape2=X1.shape
for indexShape1 in range(shape1):
for indexShape2 in range(shape2):
dxdtAtX=dynamicsStateSpace([X0[indexShape1,indexShape2],X1[indexShape1,indexShape2]],0)
dX0[indexShape1,indexShape2]=dxdtAtX[0]
dX1[indexShape1,indexShape2]=dxdtAtX[1]
The arrays
The final step is to plot the phase portrait. This is performed by the following code.
<pre class="wp-block-syntaxhighlighter-code">#adjust the figure size
plt.figure(figsize=(8, 8))
# plot the phase portrait
plt.quiver(X0,X1,dX0,dX1,color='b')
# adjust the axis limits
plt.xlim(-2,2)
plt.ylim(-2,2)
# insert the title
plt.title('Phase Portrait', fontsize=14)
# set the axis labels
plt.xlabel('<img src="https://aleksandarhaber.com/wp-content/ql-cache/quicklatex.com-1ee89d257836594b43959a4b9ba70cc6_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="x_{1}" title="Rendered by QuickLaTeX.com" height="11" width="16" style="vertical-align: -3px;"/>',fontsize=14)
plt.ylabel('<img src="https://aleksandarhaber.com/wp-content/ql-cache/quicklatex.com-1b8f7c11a53579abfdd4b94207dfc798_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="x_{2}" title="Rendered by QuickLaTeX.com" height="11" width="17" style="vertical-align: -3px;"/>',fontsize=14)
# adjust the font size of x and y axes
plt.tick_params(axis='both', which='major', labelsize=14)
# insert legend
# plt.legend(fontsize=14)
# save figure
plt.savefig('phasePortrait.png',dpi=600)
plt.show()</pre>
These code lines generate the plot shown in the figure below.
Next, we simulate a state-space trajectory for a selected initial condition, and we plot this state-space trajectory on the same phase portrait. This is performed by the following code.
<pre class="wp-block-syntaxhighlighter-code"># now simulate the dynamics for a certain starting trajectory and
# plot the dynamics on the same graph
initialState=np.array([-1,-1])
simulationTime=np.linspace(0,2,200)
# generate the state-space trajectory
solutionState=odeint(dynamicsStateSpace,initialState,simulationTime)
#adjust the figure size
plt.figure(figsize=(8, 8))
# plot the phase portrait
plt.quiver(X0,X1,dX0,dX1,color='b')
# adjust the axis limits
plt.xlim(-2,2)
plt.ylim(-2,2)
# add the state trajectory plot
plt.plot(solutionState[:,0], solutionState[:,1], color='r',linewidth=3)
# insert the title
plt.title('Phase Portrait', fontsize=14)
# set the axis labels
plt.xlabel('<img src="https://aleksandarhaber.com/wp-content/ql-cache/quicklatex.com-1ee89d257836594b43959a4b9ba70cc6_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="x_{1}" title="Rendered by QuickLaTeX.com" height="11" width="16" style="vertical-align: -3px;"/>',fontsize=14)
plt.ylabel('<img src="https://aleksandarhaber.com/wp-content/ql-cache/quicklatex.com-1b8f7c11a53579abfdd4b94207dfc798_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="x_{2}" title="Rendered by QuickLaTeX.com" height="11" width="17" style="vertical-align: -3px;"/>',fontsize=14)
# adjust the font size of x and y axes
plt.tick_params(axis='both', which='major', labelsize=14)
# insert legend
# plt.legend(fontsize=14)
# save figure
plt.savefig('phasePortraitStateTrajectory.png',dpi=600)
plt.show()
</pre>
The generated state-space trajectory is shown in the figure below.