Integrals Integrals - 1 month ago 19
Python Question

Making a quiver plot from .dat files

Hi I am trying to make a quiver (vector field) plot from data that is stored in .dat files. I have 4 .dat files which are 1D arrays, one for the x axis, y axis, f(x,y) along x and f(x,y) along y.

Note, I am able to construct a quiver plot without importing data from .dat files, I just followed this basic example here.

However, I am unable to apply this basic example to my example in which I need to import the data from .dat files. My code is below, I am not getting any error messages but I am getting a blank quiver plot. Any help/suggestions would be greatly appreciated, thanks!

import numpy as np
import matplotlib.pyplot as plt

n=12

data0 = np.genfromtxt('xaxis.dat')
data1 = np.genfromtxt('yaxis.dat')
data2 = np.genfromtxt('fx.dat')
data3 = np.genfromtxt('fy.dat')

x = data0[0]
y = data1[0]
fx = data2[0]
fy = data3[0]

plt.axes([0.025, 0.025, 0.95, 0.95])
plt.quiver(x,y,fx,fy, alpha=.5)
plt.quiver(x,y,fx,fy,edgecolor='k',facecolor='none', linewidth=.5)

plt.xlim(-1,n)
plt.xticks(())
plt.ylim(-1,n)
plt.yticks(())

plt.show()

Answer

In the example for the quiver plot you provided all X, Y, U and V are 2D arrays, with shape (n,n).

In your example you are importing an array of values for x, y, fx and fy, and then selecting only the first line with [0].

When using the code:

import numpy as np
import matplotlib.pyplot as plt

n=3 # number of points, changed it

data0 = np.genfromtxt('xaxis.dat')
data1 = np.genfromtxt('yaxis.dat')
data2 = np.genfromtxt('fx.dat')
data3 = np.genfromtxt('fy.dat')

x  = data0[0]
y  = data1[0]
fx = data2[0]
fy = data3[0]

plt.axes([0.025, 0.025, 0.95, 0.95]) # position of bottom left point of graph inside window and its size
plt.quiver(x,y,fx,fy, alpha=.5) # draw inside of arrows, half transparent
plt.quiver(x,y,fx,fy,edgecolor='k',facecolor='none', linewidth=.5) # draw contours of arrows

plt.xlim(-1,n) # left and right most values in the x axis
plt.xticks(()) # remove the numbers from the x axis
plt.ylim(-1,n) # ...
plt.yticks(()) # ...

plt.show()

I get: only one point With 0 1 2 0 1 2 0 1 2 in xaxis.dat and fx.dat, 0 0 0 1 1 1 2 2 2 in yaxis.dat and 1 1 1 2 2 2 3 3 3 in fy.dat. If I just remove the [0] from the arrays assignment, I get: all points with all points shown.

One change I would make is to use plt.xlim(min(x)-1,max(x)+1) and plt.ylim(min(y)-1,max(y)+1), to ensure you get to view the right area of the graph. For instance, if I make all four arrays equal to np.random.rand(10) (a 1D array with 10 random elements between 0 and 1), I get: random points

Notes on array shape

The plt.quiver will also accept the arrays in the format:

x  = [0, 1, 2] # 1D array (list, actually...)
y  = [0, 1, 2]
fx = [[0, 1, 2],
      [0, 1, 2],
      [0, 1, 2]] # 2D array
fy = [[0, 0, 0],
      [1, 1, 1],
      [2, 2, 2]]

enter image description here But will not mesh automatically if all arrays are 1D (in which case it will repeat x and y without the correct structure:

fx = np.array(fx).flatten()
fy = np.array(fy).flatten()

enter image description here

So either have:

x = [0, 1, 2, 3]
y = [4, 5, 6]
fx = [[0, 1, 2, 3],
      [0, 1, 2, 3],
      [0, 1, 2, 3]]
fy = [[4, 4, 4, 4],
      [5, 5, 5, 5],
      [6, 6, 6, 6]]

and let plt do the mesh for you, or have all arrays with the same shape and plt.quiver will get each arrow's position and components from them per index:

x = [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]
y = [4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6]
fx = [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]
fy = [4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6]

Previous answer (wrong)

[first two paragraphs]...

This means you probably noticed genfromtxt returns a 2D array (as it is able to import several columns from a single file, so the returned array will mimic the 2D structure of your file if nothing else is told), making data0[0] the first line on your document xaxis.dat.

EDIT: the sentence below is erroneous, plt.quiver can receive 1D arrays, just in the right shape.

However the quiver expects 2D arrays, from where it will retrieve the values for each point: for point i,j the position will be (X[i,j], Y[i,j]) and the arrow will be (U[i,j], V[i,j]).

If you have the repeated values for x and y in the file like this:

  • xaxis.dat:

    0, 1, 2, 0, 1, 2, 0, 1, 2

  • yaxix.dat:

    0, 0, 0, 1, 1, 1, 2, 2, 2

You can just reshape all four of your arrays to (# points in x, # points in y) and it should work out.

If you don't you will have to use something similar to np.mgrid (or np.meshgrid) to make a valid combination of X and Y arrays, and format fx and fy accordingly.