In this post, we will build a couple different quiver plots using Python and matplotlib. A quiver plot is a type of 2D plot that shows vector lines as arrows. Quiver plots are useful in electrical engineering to visualize electrical potential and valuable in mechanical engineering to show stress gradients.

Install matplotlib and numpy

To create the quiver plots, we'll use Python, matplotlib, numpy and a Jupyter notebook.

I recommend undergraduate engineers use the Anaconda distribution of Python, which comes with matplotlib, numpy and Jupyter notebooks pre-installed installed. If matplotlib, numpy and Jupyter are not available, these packages can be installed with conda or pip. To install, open the Anaconda Prompt or a terminal and type:

> conda install matplotlib numpy jupyter

or

$ pip install matplotlib numpy jupyter

To start a Jupyter notebook, open the Anaconda Prompt and type:

> jupyter notebook

Jupyter notebooks can also be started on at a command prompt with:

$ jupyter notebook

Import matplotlib and numpy

At the top of the Jupyter notebook, we need to import the required packages to build our quiver plots:

  • matplotlib
  • numpy

The %matplotlib inline magic command is added so that we can see our plots right in the Jupyter notebook.


In [1]:
import matplotlib.pyplot as plt
import numpy as np

#add %matplotlib inline if using a Jupyter notebook, remove if using a .py script
%matplotlib inline

Quiver plot with one arrow

Let's buid a simple quiver plot that contains one arrow to see how matplotlib's ax.quiver() method works. The ax.quiver() method takes four positional arguments:

ax.quiver(x_pos, y_pos, x_direct, y_direct)

Where x_pos and y_pos are the arrow starting positions and x_direct, y_direct are the arrow directions.

Let's build our first plot to contain one quiver arrow at the starting point x_pos = 0, y_pos = 0. We'll define this one quiver arrow's direction as pointing up and to the right x_direct = 1, y_direct = 1.


In [2]:
fig, ax = plt.subplots()

x_pos = 0
y_pos = 0
x_direct = 1
y_direct = 1

ax.quiver(x_pos,y_pos,x_direct,y_direct)

plt.show()


We see a plot with one arrow pointing up and to the right.

Quiver plot with two arrows

Now let's add a second arrow to our quiver plot by passing in two starting points and two arrow directions.

We'll keep our first arrow- starting position at the origin 0,0 and pointing up and to the right, direction 1,1. We'll define the second arrow with a starting position of -0.5,0.5 which points straight down (in the 0,-1 direction).

An additional keyword argument to add the ax.quiver() method is scale=5. This keyword argument scales the arrow lengths, so the arrows are longer and easier to see on the quiver plot.

To see the start and end of both arrows, we'll set the axis limits between -1.5 and 1.5 using the ax.axis() method. ax.axis() accepts a list of axis limits in the form [xmin, xmax, ymin, ymax].


In [3]:
fig, ax = plt.subplots()

x_pos = [0, -0.5]
y_pos = [0, 0.5]
x_direct = [1, 0]
y_direct = [1, -1]

ax.quiver(x_pos,y_pos,x_direct,y_direct, scale=5)
ax.axis([-1.5,1.5,-1.5,1.5])

plt.show()


We see two arrows on the quiver plot. One arrow points to the upper right and the other arrow points straight down.

Quiver plot using np.meshgrid()

Two arrows are great, but to create a whole 2D surface worth of arrows, we'll utilize numpy's meshgrid() function.

We need to build a set of arrays that denote the x and y starting positions of each quiver arrow on the plot. We will call our quiver arrow starting position arrays X and Y.

We can use the x,y arrow starting positions to define the x and y components of each quiver arrow direction. We' ll call the quiver arrow direction arrays u and v. On this quiver plot, we'll define the quiver arrow direction based on the quiver arrow starting point using:

$$ x_{direction} = cos(x_{starting \ point}) $$$$ y_{direction} = sin(y_{starting \ point}) $$

In [4]:
x = np.arange(0,2.2,0.2)
y = np.arange(0,2.2,0.2)

X, Y = np.meshgrid(x, y)
u = np.cos(X)*Y
v = np.sin(y)*Y

Now we can build the quiver plot using matplotlib's ax.quiver() method. Remember, the ax.quiver() method call takes four positional arguments:

ax.quiver(x_pos, y_pos, x_direct, y_direct)

This time x_pos and y_pos are 2D arrays which contain the starting positions of the arrows and x_direct, y_direct are 2D arrays which contain the arrow directions.

The commands ax.xaxis.set_ticks([]) and ax.yaxis.set_ticks([]) removes the tick marks from the axis and ax.set_aspect('equal') sets the aspect ratio of the plot to 1:1.


In [5]:
fig, ax = plt.subplots(figsize=(7,7))
ax.quiver(X,Y,u,v)

ax.xaxis.set_ticks([])
ax.yaxis.set_ticks([])
ax.axis([-0.2, 2.3, -0.2, 2.3])
ax.set_aspect('equal')

plt.show()


Now let's build another quiver plot with the $\hat{i}$ and $\hat{j}$ components (the horizontal and vertical components) of vector, $\vec{F}$ are dependant upon the arrow starting point $x,y$ according to the function:

$$ \vec{F} = \frac{x}{5} \ \hat{i} - \frac{y}{5} \ \hat{j} $$

Again we'll use numpy's np.meshgrid() function to build the arrow starting position arrays, then apply our function $\vec{F}$ to the $x$ and $y$ arrow starting point arrays.


In [6]:
x = np.arange(-5,6,1)
y = np.arange(-5,6,1)

X, Y = np.meshgrid(x, y)

u, v = X/5, -Y/5

fig, ax = plt.subplots(figsize=(7,7))
ax.quiver(X,Y,u,v)

ax.xaxis.set_ticks([])
ax.yaxis.set_ticks([])
ax.axis([-6, 6, -6, 6])
ax.set_aspect('equal')

plt.show()


Quiver plot containing a gradient

Next, let's build a quiver plot using the gradient function. The gradient function has the form:

$$ z = xe^{-x^2-y^2} $$

We'll use numpy's np.gradient() function to apply the gradient function based on every arrow's x,y starting position.


In [7]:
x = np.arange(-2,2.2,0.2)
y = np.arange(-2,2.2,0.2)

X, Y = np.meshgrid(x, y)
z = X*np.exp(-X**2 -Y**2)
dx, dy = np.gradient(z)

fig, ax = plt.subplots(figsize=(7,7))
ax.quiver(X,Y,dx,dy)

ax.xaxis.set_ticks([])
ax.yaxis.set_ticks([])
ax.set_aspect('equal')

plt.show()


Quiver plot with four vortices

Now let's build a quiver plot that contains four vortices. The function $\vec{F}$ which describes the 2D vortex field is:

$$ \vec{F} = sin(x)cos(y) \ \hat{i} -cos(x)sin(y) \ \hat{j} $$

We'll build these direction arrays using numpy and the np.meshgrid() function.


In [8]:
x = np.arange(0,2*np.pi+2*np.pi/20,2*np.pi/20)
y = np.arange(0,2*np.pi+2*np.pi/20,2*np.pi/20)

X,Y = np.meshgrid(x,y)

u = np.sin(X)*np.cos(Y)
v = -np.cos(X)*np.sin(Y)

fig, ax = plt.subplots(figsize=(7,7))

ax.quiver(X,Y,u,v)

ax.xaxis.set_ticks([])
ax.yaxis.set_ticks([])
ax.axis([0,2*np.pi,0,2*np.pi])
ax.set_aspect('equal')

plt.show()


Cool. Nice and swirly.

Quiver plots with color

Next, let's add some color to the quiver plots. The ax.quiver() method has an optional fifth positional argument that specifies the quiver arrow color. The quiver arrow color argument needs to have the same dimensions as the position and direction arrays.


In [9]:
x = np.arange(0,2.2,0.2)
y = np.arange(0,2.2,0.2)

X, Y = np.meshgrid(x, y)
u = np.cos(X)*Y
v = np.sin(y)*Y

n = -2
color_array = np.sqrt(((v-n)/2)**2 + ((u-n)/2)**2)

fig, ax = plt.subplots(figsize=(7,7))
ax.quiver(X,Y,u,v, color_array, alpha=0.8)

ax.xaxis.set_ticks([])
ax.yaxis.set_ticks([])
ax.axis([-0.2, 2.3, -0.2, 2.3])
ax.set_aspect('equal')

plt.show()


Let's add some color to the gradient quiver plot:


In [10]:
x = np.arange(-2,2.2,0.2)
y = np.arange(-2,2.2,0.2)


X, Y = np.meshgrid(x, y)
z = X*np.exp(-X**2 -Y**2)
dx, dy = np.gradient(z)

n = -2
color_array = np.sqrt(((dx-n)/2)**2 + ((dy-n)/2)**2)

fig, ax = plt.subplots(figsize=(7,7))
ax.quiver(X,Y,dx,dy,color_array)

ax.xaxis.set_ticks([])
ax.yaxis.set_ticks([])
ax.set_aspect('equal')

plt.show()


Finally, we'll add some color to the vortex plot:


In [11]:
x = np.arange(0,2*np.pi+2*np.pi/20,2*np.pi/20)
y = np.arange(0,2*np.pi+2*np.pi/20,2*np.pi/20)

X,Y = np.meshgrid(x,y)

u = np.sin(X)*np.cos(Y)
v = -np.cos(X)*np.sin(Y)

n = -1
color_array = np.sqrt(((dx-n)/2)**2 + ((dy-n)/2)**2)

fig, ax = plt.subplots(figsize=(7,7))

ax.quiver(X,Y,u,v,color_array, scale=17)

ax.xaxis.set_ticks([])
ax.yaxis.set_ticks([])
ax.axis([0,2*np.pi,0,2*np.pi])
ax.set_aspect('equal')

plt.show()


Summary

In this post, we built a couple different quiver plots with matplotlib and Python. Quiver plots are part of matplotlib's pylot library. The ax.quiver() method accepts four positional arguments: x-positions, y-positions, x-directions, y-directions. Numpy's meshgrid() function is useful for creating these position arrays. Finally, we added some color to our quiver plots by including a fifth positional argument to the ax.quiver() method.