How to use matplotlib quiver using an external file - python

I am trying to write a very simple code (should be):
I want to plot arrows from an external data file which gives me the vector dimensions in x and y, given in two columns sx and sy.
For example, I have two columns of 36 numbers each but they are the dimension of a vector having 6x6 grid. however when I do the following it gives me an error, I suppose I need an extra step to convert this data from two columns to a grid?!
But I have no idea what this step could be. Any insights?
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
data=np.loadtxt(r'text.dat')
x,y = np.meshgrid(np.arange(0, 6, 1), np.arange(0, 6, 1))
u = data[:,1]
v = data[:,2]
plt.quiver(x, y, u, v, angles='xy', scale_units='xy', scale=1)

You would benefit from a quick sanity check.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
data=np.loadtxt(r'text.dat')
x,y = np.meshgrid(np.arange(0, 6, 1), np.arange(0, 6, 1))
print x # 6x6 array, 2D!
print y # 6x6 array, 2D!
u = data[:,1] # 36 array, 1D!
v = data[:,2] # 36 array, 1D!
plt.quiver(x, y, u, v, angles='xy', scale_units='xy', scale=1)
Presumably your text.dat file holds records for points [(0,0), (1,0), (2,0), ... (0,1), (1,1), (2,1)... (4,5), (5,5)] in that order.
In such a case, you just need to flatten x and y to make them 1-dimensional. You can't mix 1D and 2D arrays in quiver.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
data=np.loadtxt(r'text.dat')
x,y = np.meshgrid(np.arange(0, 6, 1), np.arange(0, 6, 1))
x = x.flatten()
y = y.flatten()
print x # 36 array, 1D!
print y # 36 array, 1D!
u = data[:,1] # 36 array, 1D!
v = data[:,2] # 36 array, 1D!
plt.quiver(x, y, u, v, angles='xy', scale_units='xy', scale=1)
EDIT: If you continue having problems, run your commands in an interactive terminal or command prompt. Check each variable and its dimensions (array.shape) to make sure the variables are what you think they are. Are each of the dimensions actually 36?

Related

Evaluating and plotting a function z = f(x,y) with different array size of x and y

Although it's a notebook question, but I am unable to get it correct, my problem is:
I have a function y ranging from 0 to 5.3 with 130 divisions
I have a function z ranging from 0 to 0.3 with 48 divisions
I wanted to plot a function v such that:
v = cos(2* \pi *z)*sin(\pi *y)
I tried to do with Python using the following code:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math
y = np.arange(0, 5.3, 0.007692)
z = np.arange(0,0.3,0.021)
v = np.cos(2.0*math.pi*z)*np.sin(math.pi*y)
fig = plt.figure(figsize=(6, 6))
ax = fig.add_subplot(111, projection='3d')
ax.scatter( y, z, v,
linewidths=1, alpha=.7,
edgecolor='k',
s = 200,
c=v)
plt.show()
By looking at the problem or at the code itself it's clear that the array size of y and z are different and correspondingly the function "v" could not be evaluated correctly and thus I am getting the following error:
v = np.cos(2.0*math.pi*z)*np.sin(math.pi*y)
ValueError: operands could not be broadcast together with shapes (15,) (690,)
I am unable to get it fixed, also I tried to make different arrays for y and z and then using two different loops for y and z evaluated the value for function z, but again I could not do it correctly. Could any one please help.
Using useful comment by #tmdavison https://stackoverflow.com/users/588071/tmdavison I used the np.meshgrid I got the following contour, which is close to, what I was expecting, but is it possible to get the 3D plot of y,z,v ? The updated code is given as:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math
y = np.arange(0, 5.3, 0.007692)
z = np.arange(0,0.3,0.021)
xx, yy = np.meshgrid(y, z, sparse=True)
v = np.cos(2.0*math.pi*xx)*np.sin(math.pi*yy)
h = plt.contourf(y,z,v)
plt.colorbar()
plt.show()
fig = plt.figure(figsize=(6, 6))
ax = fig.add_subplot(111, projection='3d')
ax.scatter( y, z, v,
linewidths=1, alpha=.7,
edgecolor='k',
s = 200,
c=v)
plt.show()
But it is giving me error which says:
ValueError: shape mismatch: objects cannot be broadcast to a single shape

How to create a 3d surface plot with matplotlib when x and y are stated as 1d arrays?

I would like to create a 3d surface plot from the arrays x,y,z where len(x) and len(z) = 250 and len(y)= 7
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
from matplotlib import cm
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X,Y,Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
yields me this error:
ValueError: shape mismatch: objects cannot be broadcast to a single shape
I tried meshgrid:
T,U=np.meshgrid(x,b)
surf = ax.plot_surface(T,U,y, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
But this yielded:
ValueError("Argument Z must be 2-dimensional.")
Any point in the right direction would be greatly appreciated. Thanks!
You need to expand your data to have x and y for each data point.
This is done by combining x and y to form an array with the same shape as z.
You can do this using np.meshgrid:
import numpy as np
x = np.array([1, 2, 3])
y = np.array([5, 6, 7, 8])
z = np.random.rand(4, 3)
# make sure to take a look hat the keyword
# indexing : {‘xy’, ‘ij’} and check some (x,y,z) pairs
# to make sure that the values are correct
xv, yv = np.meshgrid(x, y)
print(xv)
print(yv)
print(xv.shape)
print(yv.shape)
print(z.shape)

Creating a matplotlib 3D surface plot from lists

i want to create a surface plot of the lists shown in the code. It's a simplification of data i'll import from an excel file once i figured out how to plot it.
x and y should represent the plane from which the z-values emerge. I created a random matrix to pair up with the 3x10 values from x,y.
This is the error Message:
ValueError: shape mismatch: objects cannot be broadcast to a single shape
import matplotlib.pyplot as plt
import numpy as np
x = [0,1,2,3,4,5,6,7,8,9,10] #creating random data
y = [0,1,2,3]
a = np.random.rand (3, 10)
z = np.array(a, ndmin=2) #not really sure if this piece is necessary.
fig = plt.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
x, y = np.meshgrid(x, y)
ax.plot_surface(x, y, z)
plt.show()
ValueError: shape mismatch: objects cannot be broadcast to a single shape
I've already tried to leave z = np.array(a, ndmin=2) out. Didn't work either.
The problem is two-fold:
First, you have 4x11 points and not 3x10 points
Second, you need to import Axes3D for enabling the 3d plotting. You don't need to use additionally z = np.array(a, ndmin=2) I think
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
x = [0,1,2,3,4,5,6,7,8,9,10] #creating random data
y = [0,1,2,3]
a = np.random.rand(4, 11)
x, y = np.meshgrid(x, y)
fig = plt.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
ax.plot_surface(x, y, a)
plt.show()

How to get unit vectors using `quiver()` in matplotlib?

I'm trying to wrap my head around the quiver function to plot vector fields. Here's a test case:
import numpy as np
import matplotlib.pyplot as plt
X, Y = np.mgrid[1:1.5:0.5, 1:1.5:0.5]
print(X)
print(Y)
u = np.ones_like(X)
v = np.zeros_like(Y)
plt.quiver(X,Y, u, v)
plt.axis([0, 3, 0, 3], units='xy', scale=1.)
plt.show()
I am trying to get a vector of length 1, point from (1,0) to (2,0), but here is what I get:
I have tried adding the scale='xy' option, but the behaviour doesn't change. So how does this work?
First funny mistake is that you put the quiver arguments to the axis call. ;-)
Next, looking at the documentation, it says
If scale_units is ‘x’ then the vector will be 0.5 x-axis units. To plot vectors in the x-y plane, with u and v having the same units as x and y, use angles='xy', scale_units='xy', scale=1.
So let's do as the documentation tells us,
import numpy as np
import matplotlib.pyplot as plt
X, Y = np.mgrid[1:1.5:0.5, 1:1.5:0.5]
u = np.ones_like(X)
v = np.zeros_like(Y)
plt.quiver(X,Y, u, v, units='xy', angles='xy', scale_units='xy', scale=1.)
plt.axis([0, 3, 0, 3])
plt.show()
and indeed we get a one unit long arrow:

Streamflow plot not matching mgrid

I am plotting a streamplot of a 2D ODE system using the Python code:
import numpy as np
import matplotlib.pyplot as plt
Y, X = np.mgrid[-4:4:100j, -4:4:100j]
U = -0.5*X - Y
V = X - Y
plt.streamplot(X, Y, U, V, density=[1, 1])
plt.show()
However I am getting the following plot where it is extending the x and y axis by an additional unit, 5 instead of 4 even though the mgrid is -4 to 4 in both directions. I've tried different ranges but without success. Any ideas on how to confine the plot to -4:-4 and -4:4
You could use
ax.set(xlim=(-4,4), ylim=(-4,4))
to manually set the limits:
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
Y, X = np.mgrid[-4:4:100j, -4:4:100j]
U = -0.5*X - Y
V = X - Y
ax.streamplot(X, Y, U, V, density=[1, 1])
ax.set(xlim=(-4,4), ylim=(-4,4))
plt.show()

Categories

Resources